text: /**
   * @private
   */
  Ext.define('Ext.device.filesystem.Sencha', {
      extend: 'Ext.device.filesystem.Abstract',
  
      /**
       * Requests a {@link Ext.device.filesystem.FileSystem} instance.
       *
       * @param {Object} config
       * The object which contains the following config options:
       *
       * @param {Function} config.success This is required.
       * The callback to be called when the file system has been successfully created.
       *
       * @param {Ext.device.filesystem.FileSystem} config.success.fileSystem
       * The created file system.
       *
       * @param {Function} config.failure This is optional.
       * The callback to be called when an error occurred.
       *
       * @param {Object} config.failure.error
       * The occurred error.
       *
       * @param {Object} config.scope
       * The scope object
       */
      requestFileSystem: function(config) {
          if (!config.success) {
              Ext.Logger.error('Ext.device.filesystem#requestFileSystem: You must specify a `success` callback.');
              return null;
          }
  
          Ext.device.Communicator.send({
              command: 'FileSystem#requestFileSystem',
              callbacks: {
                  success: function(id) {
                      var fileSystem = Ext.create('Ext.device.filesystem.FileSystem', id);
  
                      config.success.call(config.scope || this, fileSystem);
                  },
                  failure: function(error) {
                      if (config.failure) {
                          config.failure.call(config.scope || this, error);
                      }
                  }
              },
              scope: config.scope || this
          });
      }
  }, function() {
      /**
       * The FileSystem class which is used to represent a file system.
       */
      Ext.define('Ext.device.filesystem.FileSystem', {
          id: 0,
          root: null,
  
          constructor: function(id) {
              this.id = id;
              this.root = Ext.create('Ext.device.filesystem.DirectoryEntry', '/', this);
          },
  
          /**
           * Returns a {@link Ext.device.filesystem.DirectoryEntry} instance for the root of the file system.
           *
           * @return {Ext.device.filesystem.DirectoryEntry}
           * The file system root directory.
           */
          getRoot: function() {
              return this.root;
          }
      }, function() {
          /**
           * The Entry class which is used to represent entries in a file system,
           * each of which may be a {@link Ext.device.filesystem.FileEntry} or a {@link Ext.device.filesystem.DirectoryEntry}.
           *
           * This is an abstract class.
           * @abstract
           */
          Ext.define('Ext.device.filesystem.Entry', {
              directory: false,
              path: 0,
              fileSystem: null,
  
              constructor: function(directory, path, fileSystem) {
                  this.directory = directory;
                  this.path = path;
                  this.fileSystem = fileSystem;
              },
  
              /**
               * Returns whether the entry is a file.
               *
               * @return {Boolean}
               * The entry is a file.
               */
              isFile: function() {
                  return !this.directory;
              },
  
              /**
               * Returns whether the entry is a directory.
               *
               * @return {Boolean}
               * The entry is a directory.
               */
              isDirectory: function() {
                  return this.directory;
              },
  
              /**
               * Returns the name of the entry, excluding the path leading to it.
               *
               * @return {String}
               * The entry name.
               */
              getName: function() {
                  var components = this.path.split('/');
                  for (var i = components.length - 1; i >= 0; --i) {
                      if (components[i].length > 0) {
                          return components[i];
                      }
                  }
  
                  return '/';
              },
  
              /**
               * Returns the full absolute path from the root to the entry.
               *
               * @return {String}
               * The entry full path.
               */
              getFullPath: function() {
                  return this.path;
              },
  
              /**
               * Returns the file system on which the entry resides.
               *
               * @return {Ext.device.filesystem.FileSystem}
               * The entry file system.
               */
              getFileSystem: function() {
                  return this.fileSystem;
              },
  
              /**
               * Moves the entry to a different location on the file system.
               *
               * @param {Object} config
               * The object which contains the following config options:
               *
               * @param {Ext.device.filesystem.DirectoryEntry} config.parent This is required.
               * The directory to which to move the entry.
               *
               * @param {String} config.newName This is optional.
               * The new name of the entry to move. Defaults to the entry's current name if unspecified.
               *
               * @param {Function} config.success This is optional.
               * The callback to be called when the entry has been successfully moved.
               *
               * @param {Ext.device.filesystem.Entry} config.success.entry
               * The entry for the new location.
               *
               * @param {Function} config.failure This is optional.
               * The callback to be called when an error occurred.
               *
               * @param {Object} config.failure.error
               * The occurred error.
               *
               * @param {Object} config.scope
               * The scope object
               */
              moveTo: function(config) {
                  if (config.parent == null) {
                      Ext.Logger.error('Ext.device.filesystem.Entry#moveTo: You must specify a new `parent` of the entry.');
                      return null;
                  }
  
                  var me = this;
                  Ext.device.Communicator.send({
                      command: 'FileSystem#moveTo',
                      path: this.path,
                      fileSystemId: this.fileSystem.id,
                      parentPath: config.parent.path,
                      newName: config.newName,
                      copy: config.copy,
                      callbacks: {
                          success: function(path) {
                              if (config.success) {
                                  var entry = me.directory
                                      ? Ext.create('Ext.device.filesystem.DirectoryEntry', path, me.fileSystem)
                                      : Ext.create('Ext.device.filesystem.FileEntry', path, me.fileSystem);
  
                                  config.success.call(config.scope || this, entry);
                              }
                          },
                          failure: function(error) {
                              if (config.failure) {
                                  config.failure.call(config.scope || this, error);
                              }
                          }
                      },
                      scope: config.scope || this
                  });
              },
  
              /**
               * Works the same way as {@link Ext.device.filesystem.Entry#moveTo}, but copies the entry.
               */
              copyTo: function(config) {
                  this.moveTo(Ext.apply(config, {
                      copy: true
                  }));
              },
  
              /**
               * Removes the entry from the file system.
               *
               * @param {Object} config
               * The object which contains the following config options:
               *
               * @param {Function} config.success This is optional.
               * The callback to be called when the entry has been successfully removed.
               *
               * @param {Function} config.failure This is optional.
               * The callback to be called when an error occurred.
               *
               * @param {Object} config.failure.error
               * The occurred error.
               *
               * @param {Object} config.scope
               * The scope object
               */
              remove: function(config) {
                  Ext.device.Communicator.send({
                      command: 'FileSystem#remove',
                      path: this.path,
                      fileSystemId: this.fileSystem.id,
                      recursively: config.recursively,
                      callbacks: {
                          success: function() {
                              if (config.success) {
                                  config.success.call(config.scope || this);
                              }
                          },
                          failure: function(error) {
                              if (config.failure) {
                                  config.failure.call(config.scope || this, error);
                              }
                          }
                      },
                      scope: config.scope || this
                  });
              },
  
              /**
               * Looks up the parent directory containing the entry.
               *
               * @param {Object} config
               * The object which contains the following config options:
               *
               * @param {Function} config.success This is required.
               * The callback to be called when the parent directory has been successfully selected.
               *
               * @param {Ext.device.filesystem.DirectoryEntry} config.success.entry
               * The parent directory of the entry.
               *
               * @param {Function} config.failure This is optional.
               * The callback to be called when an error occurred.
               *
               * @param {Object} config.failure.error
               * The occurred error.
               *
               * @param {Object} config.scope
               * The scope object
               */
              getParent: function(config) {
                  if (!config.success) {
                      Ext.Logger.error('Ext.device.filesystem.Entry#getParent: You must specify a `success` callback.');
                      return null;
                  }
  
                  var me = this;
                  Ext.device.Communicator.send({
                      command: 'FileSystem#getParent',
                      path: this.path,
                      fileSystemId: this.fileSystem.id,
                      callbacks: {
                          success: function(path) {
                              var entry = me.directory
                                  ? Ext.create('Ext.device.filesystem.DirectoryEntry', path, me.fileSystem)
                                  : Ext.create('Ext.device.filesystem.FileEntry', path, me.fileSystem);
  
                              config.success.call(config.scope || this, entry);
                          },
                          failure: function(error) {
                              if (config.failure) {
                                  config.failure.call(config.scope || this, error);
                              }
                          }
                      },
                      scope: config.scope || this
                  });
              }
          });
  
          /**
           * The DirectoryEntry class which is used to represent a directory on a file system.
           */
          Ext.define('Ext.device.filesystem.DirectoryEntry', {
              extend: 'Ext.device.filesystem.Entry',
  
              constructor: function(path, fileSystem) {
                  this.callParent([true, path, fileSystem]);
              },
  
              /**
               * Lists all the entries in the directory.
               *
               * @param {Object} config
               * The object which contains the following config options:
               *
               * @param {Function} config.success This is required.
               * The callback to be called when the entries has been successfully read.
               *
               * @param {Ext.device.filesystem.Entry[]} config.success.entries
               * The array of entries of the directory.
               *
               * @param {Function} config.failure This is optional.
               * The callback to be called when an error occurred.
               *
               * @param {Object} config.failure.error
               * The occurred error.
               *
               * @param {Object} config.scope
               * The scope object
               */
              readEntries: function(config) {
                  if (!config.success) {
                      Ext.Logger.error('Ext.device.filesystem.DirectoryEntry#readEntries: You must specify a `success` callback.');
                      return null;
                  }
  
                  var me = this;
                  Ext.device.Communicator.send({
                      command: 'FileSystem#readEntries',
                      path: this.path,
                      fileSystemId: this.fileSystem.id,
                      callbacks: {
                          success: function(entryInfos) {
                              var entries = entryInfos.map(function(entryInfo) {
                                  return entryInfo.directory
                                      ? Ext.create('Ext.device.filesystem.DirectoryEntry', entryInfo.path, me.fileSystem)
                                      : Ext.create('Ext.device.filesystem.FileEntry', entryInfo.path, me.fileSystem);
                              });
  
                              config.success.call(config.scope || this, entries);
                          },
                          failure: function(error) {
                              if (config.failure) {
                                  config.failure.call(config.scope || this, error);
                              }
                          }
                      },
                      scope: config.scope || this
                  });
              },
  
              /**
               * Creates or looks up a file.
               *
               * @param {Object} config
               * The object which contains the following config options:
               *
               * @param {String} config.path This is required.
               * The absolute path or relative path from the entry to the file to create or select.
               *
               * @param {Object} config.options This is optional.
               * The object which contains the following options:
               *
               * @param {Boolean} config.options.create This is optional.
               * Indicates whether to create a file, if path does not exist.
               *
               * @param {Boolean} config.options.exclusive This is optional. Used with 'create', by itself has no effect.
               * Indicates that method should fail, if path already exists.
               *
               * @param {Function} config.success This is optional.
               * The callback to be called when the file has been successfully created or selected.
               *
               * @param {Ext.device.filesystem.Entry} config.success.entry
               * The created or selected file.
               *
               * @param {Function} config.failure This is optional.
               * The callback to be called when an error occurred.
               *
               * @param {Object} config.failure.error
               * The occurred error.
               *
               * @param {Object} config.scope
               * The scope object
               */
              getFile: function(config) {
                  if (config.path == null) {
                      Ext.Logger.error('Ext.device.filesystem.DirectoryEntry#getFile: You must specify a `path` of the file.');
                      return null;
                  }
  
                  if (config.options == null) {
                      config.options = {};
                  }
  
                  var me = this;
                  Ext.device.Communicator.send({
                      command: 'FileSystem#getEntry',
                      path: this.path,
                      fileSystemId: this.fileSystem.id,
                      newPath: config.path,
                      directory: config.directory,
                      create: config.options.create,
                      exclusive: config.options.exclusive,
                      callbacks: {
                          success: function(path) {
                              if (config.success) {
                                  var entry = config.directory
                                      ? Ext.create('Ext.device.filesystem.DirectoryEntry', path, me.fileSystem)
                                      : Ext.create('Ext.device.filesystem.FileEntry', path, me.fileSystem);
  
                                  config.success.call(config.scope || this, entry);
                              }
                          },
                          failure: function(error) {
                              if (config.failure) {
                                  config.failure.call(config.scope || this, error);
                              }
                          }
                      },
                      scope: config.scope || this
                  });
              },
  
              /**
               * Works the same way as {@link Ext.device.filesystem.DirectoryEntry#getFile},
               * but creates or looks up a directory.
               */
              getDirectory: function(config) {
                  this.getFile(Ext.apply(config, {
                      directory: true
                  }));
              },
  
              /**
               * Works the same way as {@link Ext.device.filesystem.Entry#remove},
               * but removes the directory and all of its contents, if any.
               */
              removeRecursively: function(config) {
                  this.remove(Ext.apply(config, {
                      recursively: true
                  }));
              }
          });
  
          /**
           * The FileEntry class which is used to represent a file on a file system.
           */
          Ext.define('Ext.device.filesystem.FileEntry', {
              extend: 'Ext.device.filesystem.Entry',
  
              offset: 0,
  
              constructor: function(path, fileSystem) {
                  this.callParent([false, path, fileSystem]);
  
                  this.offset = 0;
              },
  
              /**
               * Returns the byte offset into the file at which the next read/write will occur.
               *
               * @return {Number}
               * The file offset.
               */
              getOffset: function() {
                  return this.offset;
              },
  
              /**
               * Sets the byte offset into the file at which the next read/write will occur.
               *
               * @param {Object} config
               * The object which contains the following config options:
               *
               * @param {Number} config.offset This is required.
               * The file offset to set. If negative, the offset back from the end of the file.
               *
               * @param {Function} config.success This is optional.
               * The callback to be called when the file offset has been successfully set.
               *
               * @param {Function} config.failure This is optional.
               * The callback to be called when an error occurred.
               *
               * @param {Object} config.failure.error
               * The occurred error.
               *
               * @param {Object} config.scope
               * The scope object
               */
              seek: function(config) {
                  if (config.offset == null) {
                      Ext.Logger.error('Ext.device.filesystem.FileEntry#seek: You must specify an `offset` in the file.');
                      return null;
                  }
  
                  var me = this;
                  Ext.device.Communicator.send({
                      command: 'FileSystem#seek',
                      path: this.path,
                      fileSystemId: this.fileSystem.id,
                      offset: config.offset,
                      callbacks: {
                          success: function(offset) {
                              me.offset = offset;
  
                              if (config.success) {
                                  config.success.call(config.scope || this);
                              }
                          },
                          failure: function(error) {
                              if (config.failure) {
                                  config.failure.call(config.scope || this, error);
                              }
                          }
                      },
                      scope: config.scope || this
                  });
              },
  
              /**
               * Reads the data from the file starting at the file offset.
               *
               * @param {Object} config
               * The object which contains the following config options:
               *
               * @param {Number} config.length This is optional.
               * The length of bytes to read from the file. Defaults to the file's current size if unspecified.
               *
               * @param {Function} config.success This is optional.
               * The callback to be called when the data has been successfully read.
               *
               * @param {Object} config.success.data
               * The read data.
               *
               * @param {Function} config.failure This is optional.
               * The callback to be called when an error occurred.
               *
               * @param {Object} config.failure.error
               * The occurred error.
               *
               * @param {Object} config.scope
               * The scope object
               */
              read: function(config) {
                  var me = this;
                  Ext.device.Communicator.send({
                      command: 'FileSystem#read',
                      path: this.path,
                      fileSystemId: this.fileSystem.id,
                      offset: this.offset,
                      length: config.length,
                      callbacks: {
                          success: function(result) {
                              me.offset = result.offset;
  
                              if (config.success) {
                                  config.success.call(config.scope || this, result.data);
                              }
                          },
                          failure: function(error) {
                              if (config.failure) {
                                  config.failure.call(config.scope || this, error);
                              }
                          }
                      },
                      scope: config.scope || this
                  });
              },
  
              /**
               * Writes the data to the file starting at the file offset.
               *
               * @param {Object} config
               * The object which contains the following config options:
               *
               * @param {Object} config.data This is required.
               * The data to write to the file.
               *
               * @param {Function} config.success This is optional.
               * The callback to be called when the data has been successfully written.
               *
               * @param {Function} config.failure This is optional.
               * The callback to be called when an error occurred.
               *
               * @param {Object} config.failure.error
               * The occurred error.
               *
               * @param {Object} config.scope
               * The scope object
               */
              write: function(config) {
                  if (config.data == null) {
                      Ext.Logger.error('Ext.device.filesystem.FileEntry#write: You must specify a `data` for the file.');
                      return null;
                  }
  
                  var me = this;
                  Ext.device.Communicator.send({
                      command: 'FileSystem#write',
                      path: this.path,
                      fileSystemId: this.fileSystem.id,
                      offset: this.offset,
                      data: config.data,
                      callbacks: {
                          success: function(offset) {
                              me.offset = offset;
  
                              if (config.success) {
                                  config.success.call(config.scope || this);
                              }
                          },
                          failure: function(error) {
                              if (config.failure) {
                                  config.failure.call(config.scope || this, error);
                              }
                          }
                      },
                      scope: config.scope || this
                  });
              },
  
              /**
               * Truncates or extends the file to the specified size in bytes.
               * If the file is extended, the added bytes are null bytes.
               *
               * @param {Object} config
               * The object which contains the following config options:
               *
               * @param {Number} config.size This is required.
               * The new file size.
               *
               * @param {Function} config.success This is optional.
               * The callback to be called when the file size has been successfully changed.
               *
               * @param {Function} config.failure This is optional.
               * The callback to be called when an error occurred.
               *
               * @param {Object} config.failure.error
               * The occurred error.
               *
               * @param {Object} config.scope
               * The scope object
               */
              truncate: function(config) {
                  if (config.size == null) {
                      Ext.Logger.error('Ext.device.filesystem.FileEntry#truncate: You must specify a `size` of the file.');
                      return null;
                  }
  
                  var me = this;
                  Ext.device.Communicator.send({
                      command: 'FileSystem#truncate',
                      path: this.path,
                      fileSystemId: this.fileSystem.id,
                      offset: this.offset,
                      size: config.size,
                      callbacks: {
                          success: function(offset) {
                              me.offset = offset;
  
                              if (config.success) {
                                  config.success.call(config.scope || this);
                              }
                          },
                          failure: function(error) {
                              if (config.failure) {
                                  config.failure.call(config.scope || this, error);
                              }
                          }
                      },
                      scope: config.scope || this
                  });
              }
          });
      });
  });
  