// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Use the <code>chrome.fileSystemProvider</code> API to create file systems,
// that can be accessible from the file manager on Chrome OS.
[implemented_in="chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_api.h"]
namespace fileSystemProvider {
  // Error codes used by providing extensions in response to requests as well
  // as in case of errors when calling methods of the API. For success,
  // <code>"OK"</code> must be used.
  enum ProviderError {
    OK,
    FAILED,
    IN_USE,
    EXISTS,
    NOT_FOUND,
    ACCESS_DENIED,
    TOO_MANY_OPENED,
    NO_MEMORY,
    NO_SPACE,
    NOT_A_DIRECTORY,
    INVALID_OPERATION,
    SECURITY,
    ABORT,
    NOT_A_FILE,
    NOT_EMPTY,
    INVALID_URL,
    IO
  };

  // Mode of opening a file. Used by $(ref:onOpenFileRequested).
  enum OpenFileMode {
    READ,
    WRITE
  };

  // Type of a change detected on the observed directory.
  enum ChangeType {
    CHANGED,
    DELETED
  };

  // List of common actions. <code>"SHARE"</code> is for sharing files with
  // others. <code>"SAVE_FOR_OFFLINE"</code> for pinning (saving for offline
  // access). <code>"OFFLINE_NOT_NECESSARY"</code> for notifying that the file
  // doesn't need to be stored for offline access anymore.
  // Used by $(ref:onGetActionsRequested) and $(ref:onExecuteActionRequested).
  enum CommonActionId {
    SAVE_FOR_OFFLINE,
    OFFLINE_NOT_NECESSARY,
    SHARE
  };

  // Represents metadata of a file or a directory.
  dictionary EntryMetadata {
    // True if it is a directory. Must be provided if requested in
    // <code>options</code>.
    boolean? isDirectory;

    // Name of this entry (not full path name). Must not contain '/'. For root
    // it must be empty. Must be provided if requested in <code>options</code>.
    DOMString? name;

    // File size in bytes. Must be provided if requested in
    // <code>options</code>.
    double? size;

    // The last modified time of this entry. Must be provided if requested in
    // <code>options</code>.
    [instanceOf=Date] object? modificationTime;

    // Mime type for the entry. Always optional, but should be provided if
    // requested in <code>options</code>.
    DOMString? mimeType;

    // Thumbnail image as a data URI in either PNG, JPEG or WEBP format, at most
    // 32 KB in size. Optional, but can be provided only when explicitly
    // requested by the $(ref:onGetMetadataRequested) event.
    DOMString? thumbnail;
  };

  // Represents a watcher.
  dictionary Watcher {
    // The path of the entry being observed.
    DOMString entryPath;

    // Whether watching should include all child entries recursively. It can be
    // true for directories only.
    boolean recursive;

    // Tag used by the last notification for the watcher.
    DOMString? lastTag;
  };

  // Represents an opened file.
  dictionary OpenedFile {
    // A request ID to be be used by consecutive read/write and close requests.
    long openRequestId;

    // The path of the opened file.
    DOMString filePath;

    // Whether the file was opened for reading or writing.
    OpenFileMode mode;
  };

  // Represents a mounted file system.
  dictionary FileSystemInfo {
    // The identifier of the file system.
    DOMString fileSystemId;

    // A human-readable name for the file system. 
    DOMString displayName;

    // Whether the file system supports operations which may change contents
    // of the file system (such as creating, deleting or writing to files).
    boolean writable;

    // The maximum number of files that can be opened at once. If 0, then not
    // limited.
    long openedFilesLimit;

    // List of currently opened files.
    OpenedFile[] openedFiles;

    // Whether the file system supports the <code>tag</code> field for observing
    // directories.
    boolean? supportsNotifyTag;

    // List of watchers.
    Watcher[] watchers;
  };

  // Options for the $(ref:mount) method.
  dictionary MountOptions {
    // The string indentifier of the file system. Must be unique per each
    // extension.
    DOMString fileSystemId;

    // A human-readable name for the file system. 
    DOMString displayName;

    // Whether the file system supports operations which may change contents
    // of the file system (such as creating, deleting or writing to files).
    boolean? writable;

    // The maximum number of files that can be opened at once. If not specified,
    // or 0, then not limited.
    long? openedFilesLimit;

    // Whether the file system supports the <code>tag</code> field for observed
    // directories.
    boolean? supportsNotifyTag;
  };

  // Options for the $(ref:unmount) method.
  dictionary UnmountOptions {
    // The identifier of the file system to be unmounted.
    DOMString fileSystemId;
  };

  // Options for the $(ref:onUnmountRequested) event.
  dictionary UnmountRequestedOptions {
    // The identifier of the file system to be unmounted.
    DOMString fileSystemId;

    // The unique identifier of this request.
    long requestId;
  };

  // Options for the $(ref:onGetMetadataRequested) event.
  dictionary GetMetadataRequestedOptions {
    // The identifier of the file system related to this operation.
    DOMString fileSystemId;

    // The unique identifier of this request.
    long requestId;

    // The path of the entry to fetch metadata about.
    DOMString entryPath;

    // Set to <code>true</code> if <code>is_directory</code> value is requested.
    boolean isDirectory;

    // Set to <code>true</code> if <code>name</code> value is requested.
    boolean name;

    // Set to <code>true</code> if <code>size</code> value is requested.
    boolean size;

    // Set to <code>true</code> if <code>modificationTime</code> value is
    // requested.
    boolean modificationTime;

    // Set to <code>true</code> if <code>mimeType</code> value is requested.
    boolean mimeType;

    // Set to <code>true</code> if the thumbnail is requested.
    boolean thumbnail;
  };

  // Options for the $(ref:onGetActionsRequested) event.
  dictionary GetActionsRequestedOptions {
    // The identifier of the file system related to this operation.
    DOMString fileSystemId;

    // The unique identifier of this request.
    long requestId;

    // List of paths of entries for the list of actions.
    DOMString[] entryPaths;
  };

  // Options for the $(ref:onReadDirectoryRequested) event.
  dictionary ReadDirectoryRequestedOptions {
    // The identifier of the file system related to this operation.
    DOMString fileSystemId;

    // The unique identifier of this request.
    long requestId;

    // The path of the directory which contents are requested. 
    DOMString directoryPath;

    // Set to <code>true</code> if <code>is_directory</code> value is requested.
    boolean isDirectory;

    // Set to <code>true</code> if <code>name</code> value is requested.
    boolean name;

    // Set to <code>true</code> if <code>size</code> value is requested.
    boolean size;

    // Set to <code>true</code> if <code>modificationTime</code> value is
    // requested.
    boolean modificationTime;

    // Set to <code>true</code> if <code>mimeType</code> value is requested.
    boolean mimeType;

    // Set to <code>true</code> if the thumbnail is requested.
    boolean thumbnail;
  };

  // Options for the $(ref:onOpenFileRequested) event.
  dictionary OpenFileRequestedOptions {
    // The identifier of the file system related to this operation.
    DOMString fileSystemId;

    // A request ID which will be used by consecutive read/write and close
    // requests.
    long requestId;

    // The path of the file to be opened.
    DOMString filePath;

    // Whether the file will be used for reading or writing.
    OpenFileMode mode;
  };

  // Options for the $(ref:onCloseFileRequested) event.
  dictionary CloseFileRequestedOptions {
    // The identifier of the file system related to this operation.
    DOMString fileSystemId;

    // The unique identifier of this request.
    long requestId;

    // A request ID used to open the file.
    long openRequestId;
  };

  // Options for the $(ref:onReadFileRequested) event.
  dictionary ReadFileRequestedOptions {
    // The identifier of the file system related to this operation.
    DOMString fileSystemId;

    // The unique identifier of this request.
    long requestId;

    // A request ID used to open the file.
    long openRequestId;

    // Position in the file (in bytes) to start reading from.
    double offset;

    // Number of bytes to be returned.
    double length;
  };

  // Options for the $(ref:onCreateDirectoryRequested) event.
  dictionary CreateDirectoryRequestedOptions {
    // The identifier of the file system related to this operation.
    DOMString fileSystemId;

    // The unique identifier of this request.
    long requestId;

    // The path of the directory to be created.
    DOMString directoryPath;

    // Whether the operation is recursive (for directories only).
    boolean recursive;
  };

  // Options for the $(ref:onDeleteEntryRequested) event.
  dictionary DeleteEntryRequestedOptions {
    // The identifier of the file system related to this operation.
    DOMString fileSystemId;

    // The unique identifier of this request.
    long requestId;

    // The path of the entry to be deleted.
    DOMString entryPath;

    // Whether the operation is recursive (for directories only).
    boolean recursive;
  };

  // Options for the $(ref:onCreateFileRequested) event.
  dictionary CreateFileRequestedOptions {
    // The identifier of the file system related to this operation.
    DOMString fileSystemId;

    // The unique identifier of this request.
    long requestId;

    // The path of the file to be created.
    DOMString filePath;
  };

  // Options for the $(ref:onCopyEntryRequested) event.
  dictionary CopyEntryRequestedOptions {
    // The identifier of the file system related to this operation.
    DOMString fileSystemId;

    // The unique identifier of this request.
    long requestId;

    // The source path of the entry to be copied.
    DOMString sourcePath;

    // The destination path for the copy operation.
    DOMString targetPath;
  };

  // Options for the $(ref:onMoveEntryRequested) event.
  dictionary MoveEntryRequestedOptions {
    // The identifier of the file system related to this operation.
    DOMString fileSystemId;

    // The unique identifier of this request.
    long requestId;

    // The source path of the entry to be moved into a new place.
    DOMString sourcePath;

    // The destination path for the copy operation.
    DOMString targetPath;
  };

  // Options for the $(ref:onTruncateRequested) event.
  dictionary TruncateRequestedOptions {
    // The identifier of the file system related to this operation.
    DOMString fileSystemId;

    // The unique identifier of this request.
    long requestId;

    // The path of the file to be truncated.
    DOMString filePath;

    // Number of bytes to be retained after the operation completes.
    double length;
  };

  // Options for the $(ref:onWriteFileRequested) event.
  dictionary WriteFileRequestedOptions {
    // The identifier of the file system related to this operation.
    DOMString fileSystemId;

    // The unique identifier of this request.
    long requestId;

    // A request ID used to open the file.
    long openRequestId;

    // Position in the file (in bytes) to start writing the bytes from.
    double offset;

    // Buffer of bytes to be written to the file.
    ArrayBuffer data;
  };

  // Options for the $(ref:onAbortRequested) event.
  dictionary AbortRequestedOptions {
    // The identifier of the file system related to this operation.
    DOMString fileSystemId;

    // The unique identifier of this request.
    long requestId;

    // An ID of the request to be aborted.
    long operationRequestId;
  };

  // Options for the $(ref:onAddWatcherRequested) event.
  dictionary AddWatcherRequestedOptions {
    // The identifier of the file system related to this operation.
    DOMString fileSystemId;

    // The unique identifier of this request.
    long requestId;

    // The path of the entry to be observed.
    DOMString entryPath;

    // Whether observing should include all child entries recursively. It can be
    // true for directories only.
    boolean recursive;
  };

  // Options for the $(ref:onRemoveWatcherRequested) event.
  dictionary RemoveWatcherRequestedOptions {
    // The identifier of the file system related to this operation.
    DOMString fileSystemId;

    // The unique identifier of this request.
    long requestId;

    // The path of the watched entry.
    DOMString entryPath;

    // Mode of the watcher.
    boolean recursive;
  };

  // Information about an action for an entry.
  dictionary Action {
    // The identifier of the action. Any string or $(ref:CommonActionId) for
    // common actions.
    DOMString id;

    // The title of the action. It may be ignored for common actions.
    DOMString? title;
  };

  // Options for the $(ref:onExecuteActionRequested) event.
  dictionary ExecuteActionRequestedOptions {
    // The identifier of the file system related to this operation.
    DOMString fileSystemId;

    // The unique identifier of this request.
    long requestId;

    // The set of paths of the entries to be used for the action.
    DOMString[] entryPaths;

    // The identifier of the action to be executed.
    DOMString actionId;
  };

  // Information about a change happened to an entry within the observed
  // directory (including the entry itself).
  dictionary Change {
    // The path of the changed entry.
    DOMString entryPath;

    // The type of the change which happened to the entry.
    ChangeType changeType;
  };

  // Options for the $(ref:notify) method.
  dictionary NotifyOptions {
    // The identifier of the file system related to this change.
    DOMString fileSystemId;

    // The path of the observed entry.
    DOMString observedPath;

    // Mode of the observed entry.
    boolean recursive;

    // The type of the change which happened to the observed entry. If it is
    // DELETED, then the observed entry will be automatically removed from the
    // list of observed entries.
    ChangeType changeType;

    // List of changes to entries within the observed directory (including the
    // entry itself)
    Change[]? changes;

    // Tag for the notification. Required if the file system was mounted with
    // the <code>supportsNotifyTag</code> option. Note, that this flag is
    // necessary to provide notifications about changes which changed even
    // when the system was shutdown.
    DOMString? tag;
  };

  // Options for the $(ref:onConfigureRequested) event.
  dictionary ConfigureRequestedOptions {
    // The identifier of the file system to be configured.
    DOMString fileSystemId;

    // The unique identifier of this request.
    long requestId;
  };

  // Callback to receive the result of $(ref:getAll) function.
  callback GetAllCallback = void(FileSystemInfo[] fileSystems);

  // Callback to receive the result of $(ref:get) function.
  callback GetCallback = void(FileSystemInfo fileSystem);

  // Callback to be called by the providing extension in case of a success.
  [nocompile] callback ProviderSuccessCallback = void();

  // Callback to be called by the providing extension in case of an error.
  // Any error code is allowed except <code>OK</code>.
  [nocompile] callback ProviderErrorCallback = void(ProviderError error);

  // Success callback for the $(ref:onGetMetadataRequested) event.
  [nocompile] callback MetadataCallback = void(EntryMetadata metadata);

  // Success callback for the $(ref:onGetActionsRequested) event.
  [nocompile] callback ActionsCallback = void(Action[] actions);

  // Success callback for the $(ref:onReadDirectoryRequested) event. If more
  // entries will be returned, then <code>hasMore</code> must be true, and it
  // has to be called again with additional entries. If no more entries are
  // available, then <code>hasMore</code> must be set to false.
  [nocompile] callback EntriesCallback = void(
      EntryMetadata[] entries, boolean hasMore);

  // Success callback for the $(ref:onReadFileRequested) event. If more
  // data will be returned, then <code>hasMore</code> must be true, and it
  // has to be called again with additional entries. If no more data is
  // available, then <code>hasMore</code> must be set to false.
  [nocompile] callback FileDataCallback = void(
      ArrayBuffer data, boolean hasMore);

  // A generic result callback to indicate success or failure.
  callback ResultCallback = void();

  interface Functions {
    // Mounts a file system with the given <code>fileSystemId</code> and
    // <code>displayName</code>. <code>displayName</code> will be shown in the
    // left panel of the Files app. <code>displayName</code> can contain any
    // characters including '/', but cannot be an empty string.
    // <code>displayName</code> must be descriptive but doesn't have to be
    // unique. The <code>fileSystemId</code> must not be an empty string.
    //
    // Depending on the type of the file system being mounted, the
    // <code>source</code> option must be set appropriately.
    //
    // In case of an error, $(ref:runtime.lastError) will be set with a
    // corresponding error code.
    static void mount(MountOptions options,
                      optional ResultCallback callback);

    // Unmounts a file system with the given <code>fileSystemId</code>. It
    // must be called after $(ref:onUnmountRequested) is invoked. Also,
    // the providing extension can decide to perform unmounting if not requested
    // (eg. in case of lost connection, or a file error).
    //
    // In case of an error, $(ref:runtime.lastError) will be set with a
    // corresponding error code.
    static void unmount(UnmountOptions options,
                        optional ResultCallback callback);

    // Returns all file systems mounted by the extension.
    static void getAll(GetAllCallback callback);

    // Returns information about a file system with the passed
    // <code>fileSystemId</code>.
    static void get(DOMString fileSystemId, GetCallback callback);

    // Notifies about changes in the watched directory at
    // <code>observedPath</code> in <code>recursive</code> mode. If the file
    // system is mounted with <code>supportsNofityTag</code>, then
    // <code>tag</code> must be provided, and all changes since the last
    // notification always reported, even if the system was shutdown. The last
    // tag can be obtained with $(ref:getAll).
    //
    // To use, the <code>file_system_provider.notify</code> manifest option
    // must be set to true.
    //
    // Value of <code>tag</code> can be any string which is unique per call,
    // so it's possible to identify the last registered notification. Eg. if
    // the providing extension starts after a reboot, and the last registered
    // notification's tag is equal to "123", then it should call $(ref:notify)
    // for all changes which happened since the change tagged as "123". It
    // cannot be an empty string.
    //
    // Not all providers are able to provide a tag, but if the file system has
    // a changelog, then the tag can be eg. a change number, or a revision
    // number.
    //
    // Note that if a parent directory is removed, then all descendant entries
    // are also removed, and if they are watched, then the API must be notified
    // about the fact. Also, if a directory is renamed, then all descendant
    // entries are in fact removed, as there is no entry under their original
    // paths anymore.
    //
    // In case of an error, $(ref:runtime.lastError) will be set
    // will a corresponding error code.
    static void notify(NotifyOptions options,
                       optional ResultCallback callback);
  };

  interface Events {
    // Raised when unmounting for the file system with the
    // <code>fileSystemId</code> identifier is requested. In the response, the
    // $(ref:unmount) API method must be called together with
    // <code>successCallback</code>. If unmounting is not possible (eg. due to
    // a pending operation), then <code>errorCallback</code> must be called.
    [maxListeners=1] static void onUnmountRequested(
        UnmountRequestedOptions options,
        ProviderSuccessCallback successCallback,
        ProviderErrorCallback errorCallback);

    // Raised when metadata of a file or a directory at <code>entryPath</code>
    // is requested. The metadata must be returned with the
    // <code>successCallback</code> call. In case of an error,
    // <code>errorCallback</code> must be called.
    [maxListeners=1] static void onGetMetadataRequested(
        GetMetadataRequestedOptions options,
        MetadataCallback successCallback,
        ProviderErrorCallback errorCallback);

    // Raised when a list of actions for a set of files or directories at
    // <code>entryPaths</code> is requested. All of the returned actions must
    // be applicable to each entry. If there are no such actions, an empty array
    // should be returned. The actions must be returned with the
    // <code>successCallback</code> call. In case of an error,
    // <code>errorCallback</code> must be called.
    [maxListeners=1] static void onGetActionsRequested(
        GetActionsRequestedOptions options,
        ActionsCallback successCallback,
        ProviderErrorCallback errorCallback);

    // Raised when contents of a directory at <code>directoryPath</code> are
    // requested. The results must be returned in chunks by calling the
    // <code>successCallback</code> several times. In case of an error,
    // <code>errorCallback</code> must be called.
    [maxListeners=1] static void onReadDirectoryRequested(
        ReadDirectoryRequestedOptions options,
        EntriesCallback successCallback,
        ProviderErrorCallback errorCallback);

    // Raised when opening a file at <code>filePath</code> is requested. If the
    // file does not exist, then the operation must fail. Maximum number of
    // files opened at once can be specified with <code>MountOptions</code>.
    [maxListeners=1] static void onOpenFileRequested(
        OpenFileRequestedOptions options,
        ProviderSuccessCallback successCallback,
        ProviderErrorCallback errorCallback);

    // Raised when opening a file previously opened with
    // <code>openRequestId</code> is requested to be closed.
    [maxListeners=1] static void onCloseFileRequested(
        CloseFileRequestedOptions options,
        ProviderSuccessCallback successCallback,
        ProviderErrorCallback errorCallback);

    // Raised when reading contents of a file opened previously with
    // <code>openRequestId</code> is requested. The results must be returned in
    // chunks by calling <code>successCallback</code> several times. In case of
    // an error, <code>errorCallback</code> must be called.
    [maxListeners=1] static void onReadFileRequested(
        ReadFileRequestedOptions options,
        FileDataCallback successCallback,
        ProviderErrorCallback errorCallback);

    // Raised when creating a directory is requested. The operation must fail
    // with the EXISTS error if the target directory already exists.
    // If <code>recursive</code> is true, then all of the missing directories
    // on the directory path must be created.
    [maxListeners=1] static void onCreateDirectoryRequested(
        CreateDirectoryRequestedOptions options,
        ProviderSuccessCallback successCallback,
        ProviderErrorCallback errorCallback);

    // Raised when deleting an entry is requested. If <code>recursive</code> is
    // true, and the entry is a directory, then all of the entries inside
    // must be recursively deleted as well.
    [maxListeners=1] static void onDeleteEntryRequested(
        DeleteEntryRequestedOptions options,
        ProviderSuccessCallback successCallback,
        ProviderErrorCallback errorCallback);

    // Raised when creating a file is requested. If the file already exists,
    // then <code>errorCallback</code> must be called with the
    // <code>"EXISTS"</code> error code.
    [maxListeners=1] static void onCreateFileRequested(
        CreateFileRequestedOptions options,
        ProviderSuccessCallback successCallback,
        ProviderErrorCallback errorCallback);

    // Raised when copying an entry (recursively if a directory) is requested.
    // If an error occurs, then <code>errorCallback</code> must be called.
    [maxListeners=1] static void onCopyEntryRequested(
        CopyEntryRequestedOptions options,
        ProviderSuccessCallback successCallback,
        ProviderErrorCallback errorCallback);

    // Raised when moving an entry (recursively if a directory) is requested.
    // If an error occurs, then <code>errorCallback</code> must be called.
    [maxListeners=1] static void onMoveEntryRequested(
        MoveEntryRequestedOptions options,
        ProviderSuccessCallback successCallback,
        ProviderErrorCallback errorCallback);

    // Raised when truncating a file to a desired length is requested.
    // If an error occurs, then <code>errorCallback</code> must be called.
    [maxListeners=1] static void onTruncateRequested(
        TruncateRequestedOptions options,
        ProviderSuccessCallback successCallback,
        ProviderErrorCallback errorCallback);

    // Raised when writing contents to a file opened previously with
    // <code>openRequestId</code> is requested.
    [maxListeners=1] static void onWriteFileRequested(
        WriteFileRequestedOptions options,
        ProviderSuccessCallback successCallback,
        ProviderErrorCallback errorCallback);

    // Raised when aborting an operation with <code>operationRequestId</code>
    // is requested. The operation executed with <code>operationRequestId</code>
    // must be immediately stopped and <code>successCallback</code> of this
    // abort request executed. If aborting fails, then
    // <code>errorCallback</code> must be called. Note, that callbacks of the
    // aborted operation must not be called, as they will be ignored. Despite
    // calling <code>errorCallback</code>, the request may be forcibly aborted.
    [maxListeners=1] static void onAbortRequested(
        AbortRequestedOptions options,
        ProviderSuccessCallback successCallback,
        ProviderErrorCallback errorCallback);

    // Raised when showing a configuration dialog for <code>fileSystemId</code>
    // is requested. If it's handled, the
    // <code>file_system_provider.configurable</code> manfiest option must be
    // set to true.
    [maxListeners=1] static void onConfigureRequested(
        ConfigureRequestedOptions options,
        ProviderSuccessCallback successCallback,
        ProviderErrorCallback errorCallback);

    // Raised when showing a dialog for mounting a new file system is requested.
    // If the extension/app is a file handler, then this event shouldn't be
    // handled. Instead <code>app.runtime.onLaunched</code> should be handled in
    // order to mount new file systems when a file is opened. For multiple
    // mounts, the <code>file_system_provider.multiple_mounts</code> manifest
    // option must be set to true.
    [maxListeners=1] static void onMountRequested(
        ProviderSuccessCallback successCallback,
        ProviderErrorCallback errorCallback);

    // Raised when setting a new directory watcher is requested. If an error
    // occurs, then <code>errorCallback</code> must be called.
    [maxListeners=1] static void onAddWatcherRequested(
      AddWatcherRequestedOptions options,
      ProviderSuccessCallback successCallback,
      ProviderErrorCallback errorCallback);

    // Raised when the watcher should be removed. If an error occurs, then
    // <code>errorCallback</code> must be called.
    [maxListeners=1] static void onRemoveWatcherRequested(
      RemoveWatcherRequestedOptions options,
      ProviderSuccessCallback successCallback,
      ProviderErrorCallback errorCallback);

    // Raised when executing an action for a set of files or directories is\
    // requested. After the action is completed, <code>successCallback</code>
    // must be called. On error, <code>errorCallback</code> must be called.
    [maxListeners=1] static void onExecuteActionRequested(
      ExecuteActionRequestedOptions options,
      ProviderSuccessCallback successCallback,
      ProviderErrorCallback errorCallback);
  };
};

