app = angular.module "ped", [
  "ped.session"
  
  "ped.editor"
  "ped.borderLayout"
  "ped.previewer"
]

app.controller 'MainCtrl', ["$scope", "session", ($scope, session) ->
  $scope.session = session
  
  session.reset files: [
    filename: "index.html"
    content: """
      <!doctype html>
      <html ng-app="plunker" >
      <head>
        <meta charset="utf-8">
        <title>AngularJS Plunker</title>
        <script>document.write('<base href="' + document.location + '" />');</script>
        <link rel="stylesheet" href="style.css">
        <script data-require="[email protected]" src="http://code.angularjs.org/1.1.4/angular.js"></script>
        <script src="app.js"></script>
      </head>
      <body ng-controller="MainCtrl">
        <p>Hello {{name}}!</p>
      </body>
      </html> 
    """
  ,
    filename: "app.js"
    content: """
      var app = angular.module('plunker', []);
       
      app.controller('MainCtrl', function($scope) {
        $scope.name = 'World';
      });
    """
  ,
    filename: "style.css"
    content: """
      p {
        color: red;
      }
    """
  ]
  
  $scope.addFile = ->
    if filename = prompt("Filename?")
      session.addBuffer(filename)
      
]
<!DOCTYPE html>
<html ng-app="ped">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <link data-require="bootstrap-css@*" data-semver="2.3.2" rel="stylesheet" href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap.min.css" />
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script data-require="[email protected]" src="http://code.angularjs.org/1.1.5/angular.js" data-semver="1.1.5"></script>
    <script data-require="[email protected]" data-semver="0.4.0" src="http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.4.0.min.js"></script>
    <script data-require="[email protected]" data-semver="0.0.1" src="http://angular-ui.github.io/ui-router/release/angular-ui-router.min.js"></script>
    <script data-require="[email protected]" data-semver="0.2.0" src="http://ace.ajax.org/build/src/ace.js"></script>
    <script src="filer.js"></script>
    <script src="editor.js"></script>
    <script src="borderLayout.js"></script>
    <script src="previewer.js"></script>
    <script src="session.js"></script>
    <script src="app.js"></script>
  </head>

  <body ng-controller="MainCtrl">
    <border-layout>
      <border class="sidebar" anchor="west" target="250px" min="200px" max="300px">
        <ul class="nav nav-list">
          <li ng-class="{active: buffer==session.active}" ng-repeat="buffer in session.buffers track by buffer.filename">
            <a ng-click="session.active=buffer" ng-bind="buffer.filename"></a>
          </li>
          <li>
            <a ng-click="addFile()">Add file...</a>
          </li>
        </ul>
        <handle></handle>
      </border>
      <border class="preview" anchor="east" target="30%">
        <previewer session="session"></previewer>
        <handle></handle>
      </border>
      <center>
        <editor session="session"></editor>
      </center>
    </border-layout>
  </body>

</html>
/* Put your css in here */

.editor {
  position: absolute;
  top: 0; left: 0; right: 0; bottom: 0;

  .editor-canvas {
    position: absolute;
    top: 0; left: 0; right: 0; bottom: 0;
  }
}

.border-layout {
  position: absolute;
  top: 0; left: 0; right: 0; bottom: 0;
  
  background-color: black;
  
  .pane {
    position: absolute;
    box-sizing: border-box;
    overflow: auto;
    background-color: white;
    
    .overlay {
      z-index: 999;
      display: none;
      position: absolute;
      top: 0; left: 0; right: 0; bottom: 0;
    }
    
    &.moving .overlay {
      background-color: transparent;
      display: block;
    }
  }

  .pane.north {
    top: 0; left: 0; right: 0;
  }
  .pane.south {
    left: 0; right: 0; bottom: 0;
  }
  
  .pane.west {
    top: 0; left: 0; bottom: 0;
  }
  .pane.east {
    top: 0; right: 0; bottom: 0;
  }
  
  .pane.center {
    top: 0; left: 0; right: 0; bottom: 0;
  }
}


.pane.sidebar {
  padding-right: 8px;
  
  .nav-list a {
    cursor: pointer;
  }
  
  .handle {
    position: absolute;
    top: 0; right: 0; bottom: 0;
    width: 8px;
    background-color: #666;
    cursor: ew-resize;
    
    &.moving {
      background-color: #AAA;
    }
    
    &.constrained {
      background-color: #966;
    }
  }
}

.pane.preview {
  padding-left: 8px;
  
  .handle {
    position: absolute;
    top: 0; left: 0; bottom: 0;
    width: 8px;
    background-color: #666;
    cursor: ew-resize;
    
    &.moving {
      background-color: #AAA;
    }
    
    &.constrained {
      background-color: #966;
    }
  }
}

.pane.navbar {
  margin: 0;
}

.moving h1 {
  color: red;
}
module = angular.module "ped.session", [
]

module.service "session", class Session
  class Buffer
    constructor: (@filename, @content = "") ->
      #console.log "Buffer::constructor", arguments...
    rename: (filename) ->
      @filename = filename
      @

  constructor: ->
    #console.log "Session::constructor", arguments...
    @active = new Buffer("index.html")
    @buffers = [@active]
    
  reset: (json = {}) ->
    @buffers.length = 0
    @buffers.push new Buffer(file.filename, file.content) for file in json.files
    @buffers.push new Buffer("index.html") unless @buffers.length
    
    unless @active = @getBufferByFilename("index.html")
      @active = @buffers[0]

  getBufferByFilename: (filename) ->
    return buffer for buffer in @buffers when buffer.filename is filename
  
  add: (filename, content = "") ->
    filename ||= prompt("Filename?")
    
    unless filename
      throw new Error("Invalid filename")
      
    if buffer = @getBufferByFilename(filename)
      throw new Error("Buffer already exists")
    
    @buffers.push new Buffer(filename, content)
    @

  remove: (filename) ->
    unless filename
      throw new Error("Invalid filename")
      
    unless buffer = @getBufferByFilename(filename)
      throw new Error("Buffer does not exist")
    
    @buffers.splice @buffers.indexOf(buffer), 1
    @
module = angular.module "ped.editor", [
]

module.directive "editorBuffer", [ "$rootScope", ($rootScope) ->
  EditSession = require("ace/edit_session").EditSession
  UndoManager = require("ace/undomanager").UndoManager
  Range = require("ace/range").Range
  
  
  restrict: "E"
  replace: true
  require: ["^editor", "ngModel", "editorBuffer"]
  scope:
    buffer: "="
  template: """
    <div class="editor-buffer"></div>
  """
  controller: class EditorBuffer
    @inject = ["$scope"]
    constructor: ($scope) ->
      #console.log "EditorBuffer::constructor", arguments...
      @buffer = $scope.buffer
      
      @aceSession = new EditSession(@buffer.content or "")
      @aceSession.setUndoManager(new UndoManager())
      @aceSession.setTabSize(2)
      @aceSession.setUseWorker(true)
      
      $scope.$watch "buffer.filename", =>
        @aceSession.setMode(@guessMode())
    
    syncWith: ($scope, model) ->
      session = @aceSession
      
      model.$render = -> session.setValue(model.$modelValue)
      
      updateViewValue = (value) -> model.$setViewValue(value)
      
      session.on "change", ->
        if model.$viewValue != (value = session.getValue())
          if $rootScope.$$phase then updateViewValue(value)
          else $scope.$apply -> updateViewValue(value)
      
      $scope.$on "$destroy", -> editor.removeListener "change", updateViewValue
    
    guessMode: ->
      "ace/mode/" +
        if /\.js$/.test(@buffer.filename) then "javascript"
        else if /\.html$/.test(@buffer.filename) then "html"
        else if /\.css$/.test(@buffer.filename) then "css"
        else "text"
      
  link: ($scope, $el, attrs, [editor, model, ctrl]) ->
    #console.log "editor-buffer::link", arguments...
    editor.attachBuffer(ctrl)
    ctrl.syncWith($scope, model)
    
]

module.directive "editorCanvas", [ () ->
  restrict: "E"
  replace: true
  require: "^editor"
  template: """
    <div class="editor-canvas"></div>
  """
  link: ($scope, $el, attrs, editor) ->
    #console.log "editor-canvas::link", arguments...
    editor.setCanvas($el[0])
      
]

module.directive "editor", ->
  AceEditor = require("ace/editor").Editor
  Renderer = require("ace/virtual_renderer").VirtualRenderer
  
  restrict: "E"
  replace: true
  require: "editor"
  scope:
    session: "="
  template: """
    <div class="editor">
      <editor-buffer buffer="buffer" ng-model="buffer.content" ng-repeat="buffer in session.buffers"></editor-buffer>
      <editor-canvas></editor-canvas>
    </div>
  """
  controller: class Editor
    constructor: () ->
      #console.log "Editor::constructor", arguments...
      @controllers = []
        
    setCanvas: (el) -> @ace = new AceEditor(new Renderer(el, "ace/theme/textmate"))
    attachBuffer: (controller) -> @controllers.push(controller)
  
  link: ($scope, $el, attrs, ctrl) ->
    #console.log "editor::link", arguments...
    
    #console.log "Editor", ctrl.ace
    
    $scope.$watch "session.active", (active) ->
      for controller in ctrl.controllers when controller.buffer == active
        ctrl.ace.setSession(controller.aceSession)
        #console.log "Activating", controller
    
    $scope.$on "reflow", ->
      ctrl.ace.resize()
        
module = angular.module "ped.borderLayout", [
]

calculateSize = (target, total) ->
  target ||= 0
  
  if angular.isNumber(target)
    if target >= 1 then return Math.round(target)
    if target >= 0 then return Math.round(target * total)
    
    return 0
    
  if matches = target.match /^(\d+)px$/ then return parseInt(matches[1], 10)
  if matches = target.match /^(\d+)%$/ then return Math.round(total * parseInt(matches[1], 10) / 100)
  
  throw new Error("Unsupported size: #{target}")


throttle = (delay, fn) ->
  throttled = false
  ->
    return if throttled
    
    throttled = true
    setTimeout ( -> throttled = false), delay
    
    fn.call(@, arguments...)

module.directive "border", ->
  restrict: "E"
  replace: true
  require: ["border", "^borderLayout"]
  transclude: true
  scope:
    anchor: "@"
    target: "@"
    min: "@"
    max: "@"
  template: """
    <div class="pane {{anchor}}" ng-class="{moving: moving, constrained: constrained}" ng-style="style" ng-transclude>
      <div class="overlay"></div>
    </div>
  """
  controller: class Border
    @inject = ["$scope", "$element"]
    constructor: ($scope, $element) ->
      #console.log "Border::constructor", arguments...
      
      $scope.style = {}
      
      @scope = $scope
      @el = $element[0]
    
    getElementSize: ->
      if @scope.anchor in ["north", "south"] then return @el.offsetHeight
      else if @scope.anchor in ["west", "east"] then return @el.offsetWidth
      else throw new Error("Unsupported anchor: [email protected]}")
      
    
    setSize: (size, style = {}) ->
      #console.log "Border::setSize", arguments...
      
      @scope.size = size
      
      if @scope.anchor in ["north", "south"] then style.height = "#{size}px"
      else if @scope.anchor in ["west", "east"] then style.width = "#{size}px"
      else throw new Error("Unsupported anchor: [email protected]}")
      
      angular.copy style, @scope.style
      size
      
    calculateSize: (avail, total, style = {}) ->
      #console.log "calculateSize", arguments...
      
      target = @scope.size || @scope.target || @getElementSize() || 0
      max = @scope.max || Number.MAX_VALUE
      min = @scope.min || 0
      
      size = calculateSize(target, total)
      size = Math.min(size, calculateSize(max, total))
      size = Math.max(size, calculateSize(min, total))
      size = Math.min(size, avail)
      
      @setSize(size, style)
      
  link: ($scope, $el, attrs, [ctrl, layout]) ->
    #console.log "border::link", arguments...
    
    layout.setBorder $scope.anchor, ctrl


module.directive "center", ->
  restrict: "E"
  replace: true
  require: ["center", "^borderLayout"]
  transclude: true
  template: """
    <div class="pane center" ng-style="style" ng-transclude>
    </div>
  """
  controller: class Center
    @inject = ["$scope"]
    constructor: ($scope) ->
      #console.log "Center::constructor", arguments...
      @scope = $scope
    
    setRect: (rect) ->
      #console.log "Center::setRect", arguments...
      @scope.style =
        left: "#{rect.left || 0}px"
        top: "#{rect.top || 0}px"
        right: "#{rect.right || 0}px"
        bottom: "#{rect.bottom || 0}px"
      
  link: ($scope, $el, attrs, [ctrl, layout]) ->
    #console.log "center::link"
    
    layout.setCenter ctrl

module.directive "handle", [ "$window", ($window) ->
  restrict: "E"
  replace: true
  require: ["^border", "^borderLayout"]
  transclude: true
  template: """
    <div class="handle" ng-class="{moving: moving, constrained: constrained}" ng-mousedown="trackMove($event)" ng-transclude>
    </div>
  """
  link: ($scope, $el, attrs, [border, layout]) ->
    $scope.trackMove = ($event) ->
      #console.log "trackMove", arguments...

      $event.preventDefault()
      
      if border.scope.anchor in ["north", "south"] then coord = "y"
      else if border.scope.anchor in ["west", "east"] then coord = "x"

      if border.scope.anchor in ["north", "west"] then scale = 1
      else if border.scope.anchor in ["south", "east"] then scale = -1

      initialCoord = $event[coord]
      initialSize = border.scope.size
      el = $el[0]

      mouseMove = throttle 10, (e) ->
        #console.log "Mousemove", arguments...
        e.preventDefault()

        el.setCapture?()

        $scope.$apply ->
          targetSize = initialSize + scale * (e[coord] - initialCoord)
          border.scope.size = targetSize
          layout.reflow()
          
          #console.log "Constrained", targetSize, border.scope.size
          
          $scope.constrained = border.scope.constrained = targetSize != border.scope.size
          $scope.moving = border.scope.moving = true
          
      mouseUp = (e) ->
        #console.log "Mouseup", arguments...
        e.preventDefault()
        
        $scope.$apply ->
          $scope.constrained = border.scope.constrained = false
          $scope.moving = border.scope.moving = false
        
        $window.removeEventListener "mousemove", mouseMove, true
        $window.removeEventListener "mouseup", mouseUp, true
        
        el.releaseCapture?()
        
      el.unselectable = "on";
      el.onselectstart = -> false
      el.style.userSelect = el.style.MozUserSelect = "none"
      
      $window.addEventListener "mousemove", mouseMove, true
      $window.addEventListener "mouseup", mouseUp, true
]

module.directive "borderLayout", [ "$window", ($window) ->
  stylesAdded = false
  stylesheet = """
  """
  
  restrict: "E"
  replace: true
  require: "borderLayout"
  transclude: true
  template: """
    <div class="border-layout" ng-transclude>
    </div>
  """
  
  controller: class BorderLayout
    @inject = ["$scope", "$element"]
    constructor: ($scope, $element) ->
      #console.log "BorderLayout::constructor", arguments...
      
      @handleSize = 8
      @el = $element[0]
      @scope = $scope
    
    setCenter: (center) ->
      throw new Error("Center already assigned") if @center
      
      @center = center
      @
    
    setBorder: (border, pane) ->
      throw new Error("Border already assigned: #{border}") if @[border]
      
      @[border] = pane
      @
      
    reflow: ->
      
      width = @el.offsetWidth
      height = @el.offsetHeight
      
      rect =
        left: 0
        top: 0
        bottom: 0
        right: 0
      
      
      if @north then rect.top += @north.calculateSize(height - rect.top - rect.bottom, height)
      if @south then rect.bottom += @south.calculateSize(height - rect.top - rect.bottom, height)
      
      if @west then rect.left += @west.calculateSize(width - rect.left - rect.right, width, { top: "#{rect.top}px", bottom: "#{rect.bottom}px" })
      if @east then rect.right += @east.calculateSize(width - rect.left - rect.right, width, { top: "#{rect.top}px", bottom: "#{rect.bottom}px" })
      
      @center.setRect(rect)
      
      @scope.$broadcast "reflow"
    
  link: ($scope, $el, attr, ctrl) ->
    #console.log "border-layout::link"

    ctrl.reflow()
    
    $window.addEventListener "resize", ->
      #console.log "Resize event", arguments...
      $scope.$apply(ctrl.reflow.bind(ctrl))
]
module = angular.module "ped.previewer", [
]


module.factory "types", ->
  types =
    html:
      regex: /\.html$/i
      mime: "text/html"
    javascript:
      regex: /\.js$/i
      mime: "text/javascript"
    css:
      regex: /\.css$/i
      mime: "text/css"
    text:
      regex: /\.txt$/
      mime: "text/plain"
  
  for name, type of types
    types.name = name
  
  types: types
  getByFilename: (filename) ->
    for name, mode of @types
      if mode.regex.test(filename) then return mode
    
    return @types.text


module.directive "previewer", [ "$q", "$rootScope", "types", ($q, $rootScope, types) ->
  restrict: "E"
  replace: true
  scope:
    session: "="
  template: """
    <iframe src="about:blank" width="100%" height="400px" frameborder="0"></iframe>
  """
  link: ($scope, $el, attrs) ->
    
    withFiler = do ->
      dfd = $q.defer()
      filer = new Filer
      filer.init {persistent: false, size: 1024 * 1024}, (fs) -> $rootScope.$apply ->
        if fs then dfd.resolve(filer)
        else dfd.reject("Failed to create filesystem")
      
      
      (cb) -> dfd.promise.then(cb)
      
    
    $scope.$watch "session.buffers", (buffers) -> 
      withFiler (filer) ->
        promises = []
        index = null
        
        for buffer in buffers then do (buffer) ->
          dfd = $q.defer()
          
          filer.write buffer.filename, {data: buffer.content, type: types.getByFilename(buffer.filename).mime, append: false}, (entry) -> $scope.$apply ->
            #console.log "File written", buffer.filename, arguments...
            if buffer.filename is "index.html" then index = entry
            dfd.resolve()
          
          promises.push(dfd.promise)
        
        $q.all(promises).then ->
          #console.log "Preview ready", index.toURL()
          
          $el.attr "src",
            if index then index.toURL()
            else "about:blank"
          
          $scope.$broadcast "refresh"
    , true
]
var self=this;self.URL=self.URL||self.webkitURL;self.requestFileSystem=self.requestFileSystem||self.webkitRequestFileSystem;self.resolveLocalFileSystemURL=self.resolveLocalFileSystemURL||self.webkitResolveLocalFileSystemURL;navigator.temporaryStorage=navigator.temporaryStorage||navigator.webkitTemporaryStorage;navigator.persistentStorage=navigator.persistentStorage||navigator.webkitPersistentStorage;self.BlobBuilder=self.BlobBuilder||self.MozBlobBuilder||self.WebKitBlobBuilder;
if(void 0===self.FileError){var FileError=function(){};FileError.prototype.prototype=Error.prototype}
var Util={toArray:function(a){return Array.prototype.slice.call(a||[],0)},strToDataURL:function(a,b,c){return(void 0!=c?c:1)?"data:"+b+";base64,"+self.btoa(a):"data:"+b+","+a},strToObjectURL:function(a,b){for(var c=new Uint8Array(a.length),d=0;d<c.length;++d)c[d]=a.charCodeAt(d);c=new Blob([c],b?{type:b}:{});return self.URL.createObjectURL(c)},fileToObjectURL:function(a){return self.URL.createObjectURL(a)},fileToArrayBuffer:function(a,b,c){var d=new FileReader;d.onload=function(a){b(a.target.result)};
d.onerror=function(a){c&&c(a)};d.readAsArrayBuffer(a)},dataURLToBlob:function(a){if(-1==a.indexOf(";base64,")){var b=a.split(","),a=b[0].split(":")[1],b=b[1];return new Blob([b],{type:a})}for(var b=a.split(";base64,"),a=b[0].split(":")[1],b=window.atob(b[1]),c=b.length,d=new Uint8Array(c),i=0;i<c;++i)d[i]=b.charCodeAt(i);return new Blob([d],{type:a})},arrayBufferToBlob:function(a,b){var c=new Uint8Array(a);return new Blob([c],b?{type:b}:{})},arrayBufferToBinaryString:function(a,b,c){var d=new FileReader;
d.onload=function(a){b(a.target.result)};d.onerror=function(a){c&&c(a)};a=new Uint8Array(a);d.readAsBinaryString(new Blob([a]))},arrayToBinaryString:function(a){if("object"!=typeof a)return null;for(var b=a.length,c=Array(b);b--;)c[b]=String.fromCharCode(a[b]);return c.join("")},getFileExtension:function(a){var b=a.lastIndexOf(".");return-1!=b?a.substring(b):""}},MyFileError=function(a){this.prototype=FileError.prototype;this.code=a.code;this.name=a.name};FileError.BROWSER_NOT_SUPPORTED=1E3;
FileError.prototype.__defineGetter__("name",function(){for(var a=Object.keys(FileError),b=0,c;c=a[b];++b)if(FileError[c]==this.code)return c;return"Unknown Error"});
var Filer=new function(){function a(e){if(b=e||null)c=b.root,d=!0}var b=null,c=null,d=!1,i=function(e){return 0==e.indexOf("filesystem:")},k=function(e){i(e)||(e="/"==e[0]?b.root.toURL()+e.substring(1):0==e.indexOf("./")||0==e.indexOf("../")?"../"==e&&c!=b.root?c.toURL()+"/"+e:c.toURL()+e:c.toURL()+"/"+e);return e},l=function(e,a){var b=arguments[1],c=arguments[2],g=function(e){if(e.code==FileError.NOT_FOUND_ERR){if(c)throw Error('"'+b+'" or "'+c+'" does not exist.');throw Error('"'+b+'" does not exist.');
}throw Error("Problem getting Entry for one or more paths.");},m=k(b);if(3==arguments.length){var d=k(c);self.resolveLocalFileSystemURL(m,function(a){self.resolveLocalFileSystemURL(d,function(b){e(a,b)},g)},g)}else self.resolveLocalFileSystemURL(m,e,g)},p=function(e,a,c,f,g,m){if(!b)throw Error("Filesystem has not been initialized.");if(typeof e!=typeof a)throw Error("These method arguments are not supported.");var d=c||null,n=void 0!=m?m:!1;(e.isFile||a.isDirectory)&&a.isDirectory?n?e.moveTo(a,d,
f,g):e.copyTo(a,d,f,g):l(function(e,a){if(a.isDirectory)n?e.moveTo(a,d,f,g):e.copyTo(a,d,f,g);else{var b=Error('Oops! "'+a.name+" is not a directory!");if(g)g(b);else throw b;}},e,a)};a.DEFAULT_FS_SIZE=1048576;a.version="0.4.1";a.prototype={get fs(){return b},get isOpen(){return d},get cwd(){return c}};a.prototype.pathToFilesystemURL=function(a){return k(a)};a.prototype.init=function(a,j,h){if(!self.requestFileSystem)throw new MyFileError({code:FileError.BROWSER_NOT_SUPPORTED,name:"BROWSER_NOT_SUPPORTED"});
var a=a?a:{},f=a.size||1048576;this.type=self.TEMPORARY;if("persistent"in a&&a.persistent)this.type=self.PERSISTENT;var g=function(a){this.size=f;b=a;c=b.root;d=!0;j&&j(a)};this.type==self.PERSISTENT&&navigator.persistentStorage?navigator.persistentStorage.requestQuota(f,function(a){self.requestFileSystem(this.type,a,g.bind(this),h)}.bind(this),h):self.requestFileSystem(this.type,f,g.bind(this),h)};a.prototype.ls=function(a,j,h){if(!b)throw Error("Filesystem has not been initialized.");var f=function(a){c=
a;var e=[],b=c.createReader(),f=function(){b.readEntries(function(a){a.length?(e=e.concat(Util.toArray(a)),f()):(e.sort(function(a,e){return a.name<e.name?-1:e.name<a.name?1:0}),j(e))},h)};f()};a.isDirectory?f(a):i(a)?l(f,k(a)):c.getDirectory(a,{},f,h)};a.prototype.mkdir=function(a,j,h,f){if(!b)throw Error("Filesystem has not been initialized.");var g=null!=j?j:!1,d=a.split("/"),o=function(b,c){if("."==c[0]||""==c[0])c=c.slice(1);b.getDirectory(c[0],{create:!0,exclusive:g},function(b){if(b.isDirectory)c.length&&
1!=d.length?o(b,c.slice(1)):h&&h(b);else if(b=Error(a+" is not a directory"),f)f(b);else throw b;},function(b){if(b.code==FileError.INVALID_MODIFICATION_ERR)if(b.message="'"+a+"' already exists",f)f(b);else throw b;})};o(c,d)};a.prototype.open=function(a,c,d){if(!b)throw Error("Filesystem has not been initialized.");a.isFile?a.file(c,d):l(function(a){a.file(c,d)},k(a))};a.prototype.create=function(a,d,h,f){if(!b)throw Error("Filesystem has not been initialized.");c.getFile(a,{create:!0,exclusive:null!=
d?d:!0},h,function(b){if(b.code==FileError.INVALID_MODIFICATION_ERR)b.message="'"+a+"' already exists";if(f)f(b);else throw b;})};a.prototype.mv=function(a,b,c,f,d){p.bind(this,a,b,c,f,d,!0)()};a.prototype.rm=function(a,c,d){if(!b)throw Error("Filesystem has not been initialized.");var f=function(a){a.isFile?a.remove(c,d):a.isDirectory&&a.removeRecursively(c,d)};a.isFile||a.isDirectory?f(a):l(f,a)};a.prototype.cd=function(a,d,h){if(!b)throw Error("Filesystem has not been initialized.");a.isDirectory?
(c=a,d&&d(c)):(a=k(a),l(function(a){if(a.isDirectory)c=a,d&&d(c);else if(a=Error("Path was not a directory."),h)h(a);else throw a;},a))};a.prototype.cp=function(a,b,c,d,g){p.bind(this,a,b,c,d,g)()};a.prototype.write=function(a,d,h,f){if(!b)throw Error("Filesystem has not been initialized.");var g=function(a){a.createWriter(function(b){b.onerror=f;if(d.append)b.onwriteend=function(){h&&h(a,this)},b.seek(b.length);else{var c=!1;b.onwriteend=function(){c?h&&h(a,this):(c=!0,this.truncate(this.position))}}if(d.data.__proto__==
ArrayBuffer.prototype)d.data=new Uint8Array(d.data);var e=new Blob([d.data],d.type?{type:d.type}:{});b.write(e)},f)};a.isFile?g(a):i(a)?l(g,a):c.getFile(a,{create:!0,exclusive:!1},g,f)};return a};