app.coffee
                    
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)
]
                    index.html
                    
<!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>
                    style.less
                    
/* 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;
}
                    session.coffee
                    
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
@
                    editor.coffee
                    
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()
                    borderLayout.coffee
                    
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: #{@scope.anchor}")
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: #{@scope.anchor}")
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))
]
                    previewer.coffee
                    
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
]
                    filer.js
                    
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};