Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

cordova-app-loader

Package Overview
Dependencies
Maintainers
1
Versions
23
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

cordova-app-loader - npm Package Compare versions

Comparing version 0.6.0 to 0.6.1

bundle.js

111

autoupdate.js

@@ -1,65 +0,64 @@

var CordovaAppLoader = require('./index');
var CordovaPromiseFS = require('cordova-promise-fs');
var Promise = require('promiscuous');
window.setImmediate = window.setTimeout;
(function(){
// Check for Cordova
var isCordova = typeof cordova !== 'undefined',
// CordovaPromiseFS
fs,
// CordovaFileLoader
loader,
// script-tag...
script,
// ...that contains the serverRoot
serverRoot;
// Helper variable: Chrome should use temporary storage.
var isCordova = typeof cordova !== 'undefined',
fs,
loader,
script,
serverUrl;
// Get serverRoot from script tag.
script = document.querySelector('script[server]');
if(script) serverRoot= script.getAttribute('server');
if(!serverRoot) {
throw new Error('Add a "server" attribute to the bootstrap.js script!');
}
// Get SERVER_URL from script tag.
script = document.querySelector('script[server]');
if(script){
serverUrl= script.getAttribute('server');
}
if(!serverUrl) {
throw new Error('Add a "server" attribute to the autoupdate.js script!');
}
// Initialize filesystem and loader
fs = new CordovaPromiseFS({
persistent: isCordova, // Chrome should use temporary storage.
Promise: Promise
});
// Initialize filesystem and loader
fs = new CordovaPromiseFS({
persistent: isCordova,
Promise: Promise
});
loader = new CordovaAppLoader({
fs: fs,
localRoot: 'app',
serverRoot: serverRoot,
mode: 'mirror',
cacheBuster: true
});
loader = new CordovaAppLoader({
fs: fs,
localRoot: 'app',
serverRoot: serverUrl,
mode: 'mirror',
cacheBuster: true
});
// Check > Download > Update
function check(){
loader.check()
.then(function(){
return loader.download();
})
.then(function(){
return loader.update();
},function(err){
console.error('Auto-update error:',err);
});
}
// Check > Download > Update
function check(){
loader.check()
.then(function(){
return loader.download();
})
.then(function(){
return loader.update();
},function(err){
console.error('Auto-update error:',err);
});
}
// Couple events:
// Couple events:
// 1. On launch
check();
// On launch
check();
// 2. Cordova: On resume
fs.deviceready.then(function(){
document.addEventListener('resume',check);
});
// Cordova: On resume
fs.deviceready.then(function(){
document.addEventListener('resume',check);
});
// Chrome: On page becomes visible again
function handleVisibilityChange() {
if (!document.webkitHidden) {
check();
// 3. Chrome: On page becomes visible again
function handleVisibilityChange() {
if (!document.webkitHidden) {
check();
}
}
}
document.addEventListener("webkitvisibilitychange", handleVisibilityChange, false);
document.addEventListener("webkitvisibilitychange", handleVisibilityChange, false);
})();
{
"name": "cordova-app-loadaer",
"main": "dist/CordovaAppLoader.js",
"version": "0.6.0",
"version": "0.6.1",
"homepage": "https://github.com/markmarijnissen/cordova-file-cache",

@@ -6,0 +6,0 @@ "authors": [

@@ -1,1190 +0,64 @@

/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {
(function(){
// Check for Cordova
var isCordova = typeof cordova !== 'undefined',
// CordovaPromiseFS
fs,
// CordovaFileLoader
loader,
// script-tag...
script,
// ...that contains the serverRoot
serverRoot;
var CordovaAppLoader = __webpack_require__(1);
var CordovaPromiseFS = __webpack_require__(2);
var Promise = __webpack_require__(3);
window.setImmediate = window.setTimeout;
// Get serverRoot from script tag.
script = document.querySelector('script[server]');
if(script) serverRoot= script.getAttribute('server');
if(!serverRoot) {
throw new Error('Add a "server" attribute to the bootstrap.js script!');
}
// Helper variable: Chrome should use temporary storage.
var isCordova = typeof cordova !== 'undefined',
fs,
loader,
script,
serverUrl;
// Initialize filesystem and loader
fs = new CordovaPromiseFS({
persistent: isCordova, // Chrome should use temporary storage.
Promise: Promise
});
// Get SERVER_URL from script tag.
script = document.querySelector('script[server]');
if(script){
serverUrl= script.getAttribute('server');
}
if(!serverUrl) {
throw new Error('Add a "server" attribute to the autoupdate.js script!');
}
loader = new CordovaAppLoader({
fs: fs,
localRoot: 'app',
serverRoot: serverRoot,
mode: 'mirror',
cacheBuster: true
});
// Initialize filesystem and loader
fs = new CordovaPromiseFS({
persistent: isCordova,
Promise: Promise
});
// Check > Download > Update
function check(){
loader.check()
.then(function(){
return loader.download();
})
.then(function(){
return loader.update();
},function(err){
console.error('Auto-update error:',err);
});
}
loader = new CordovaAppLoader({
fs: fs,
localRoot: 'app',
serverRoot: serverUrl,
mode: 'mirror',
cacheBuster: true
});
// Couple events:
// Check > Download > Update
function check(){
loader.check()
.then(function(){
return loader.download();
})
.then(function(){
return loader.update();
},function(err){
console.error('Auto-update error:',err);
});
}
// 1. On launch
check();
// Couple events:
// 2. Cordova: On resume
fs.deviceready.then(function(){
document.addEventListener('resume',check);
});
// On launch
check();
// Cordova: On resume
fs.deviceready.then(function(){
document.addEventListener('resume',check);
});
// Chrome: On page becomes visible again
function handleVisibilityChange() {
if (!document.webkitHidden) {
check();
}
}
document.addEventListener("webkitvisibilitychange", handleVisibilityChange, false);
/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {
var CordovaFileCache = __webpack_require__(4);
var Promise = null;
function createFilemap(files){
var result = {};
Object.keys(files).forEach(function(key){
result[files[key].filename] = files[key];
});
return result;
}
function AppLoader(options){
if(!options) throw new Error('CordovaAppLoader has no options!');
if(!options.fs) throw new Error('CordovaAppLoader has no "fs" option (cordova-promise-fs)');
if(!options.serverRoot) throw new Error('CordovaAppLoader has no "serverRoot" option.');
if(!window.pegasus || !window.Manifest) throw new Error('CordovaAppLoader bootstrap.js is missing.');
Promise = options.fs.Promise;
// initialize variables
this.manifest = window.Manifest;
this.newManifest = null;
// normalize serverRoot and set remote manifest url
options.serverRoot = options.serverRoot || '';
if(!!options.serverRoot && options.serverRoot[options.serverRoot.length-1] !== '/') options.serverRoot += '/';
this.newManifestUrl = options.serverRoot + (options.manifest || 'manifest.json');
// initialize a file cache
if(options.mode) options.mode = 'mirror';
this.cache = new CordovaFileCache(options);
// private stuff
this._toBeDeleted = [];
this._toBeDownloaded = [];
this._updateReady = false;
this._checkTimeout = options.checkTimeout || 10000;
}
AppLoader.prototype.check = function(newManifest){
var self = this, manifest = this.manifest;
return new Promise(function(resolve,reject){
if(typeof newManifest === "string") {
self.newManifestUrl = newManifest;
newManifest = undefined;
}
function checkManifest(newManifest){
// make sure cache is ready for the DIFF operations!
self.cache.ready.then(function(){
if(!newManifest.files){
reject('Downloaded Manifest has no "files" attribute.');
return;
}
var newFiles = createFilemap(newManifest.files);
var oldFiles = createFilemap(manifest.files);
// Create the diff
self._toBeDownloaded = Object.keys(newFiles)
.filter(function(file){
return !oldFiles[file]
|| oldFiles[file].version !== newFiles[file].version
|| !self.cache.isCached(file);
});
self.cache.list().then(function(files){
self._toBeDeleted = files
.map(function(file){
return file.substr(self.cache._localRoot.length);
})
.filter(function(file){
return !newFiles[file];
})
.concat(self._toBeDownloaded);
if(self._toBeDeleted.length > 0 || self._toBeDownloaded.length > 0){
// Save the new Manifest
self.newManifest = newManifest;
self.newManifest.root = self.cache.toInternalURL('/') + (self.newManifest.root || '');
resolve(true);
} else {
resolve(false);
}
},reject);
},reject);
}
if(typeof newManifest === "object") {
checkManifest(newManifest);
} else {
pegasus(self.newManifestUrl).then(checkManifest,reject);
setTimeout(function(){reject(new Error('timeout'));},self._checkTimeout);
}
});
};
AppLoader.prototype.canDownload = function(){
return !!this.newManifest && !this._updateReady;
};
AppLoader.prototype.canUpdate = function(){
return this._updateReady;
};
AppLoader.prototype.download = function(onprogress){
var self = this;
if(!self.canDownload()) {
return Promise.resolve(null);
}
// we will delete files, which will invalidate the current manifest...
localStorage.removeItem('manifest');
this.manifest.files = Manifest.files = {};
return self.cache.remove(self._toBeDeleted,true)
.then(function(){
self.cache.add(self._toBeDownloaded);
return self.cache.download(onprogress);
}).then(function(){
self._toBeDeleted = [];
self._toBeDownloaded = [];
self._updateReady = true;
return self.newManifest;
},function(files){
// on download error, remove files...
if(!!files && files.length){
self.cache.remove(files);
}
return files;
});
};
AppLoader.prototype.update = function(reload){
if(this._updateReady) {
// update manifest
localStorage.setItem('manifest',JSON.stringify(this.newManifest));
if(reload !== false) location.reload();
return true;
}
return false;
};
AppLoader.prototype.clear = function(){
localStorage.removeItem('manifest');
return this.cache.clear();
};
AppLoader.prototype.reset = function(){
return this.clear().then(function(){
location.reload();
},function(){
location.reload();
});
};
module.exports = AppLoader;
/***/ },
/* 2 */
/***/ function(module, exports, __webpack_require__) {
/**
* Static Private functions
*/
/* createDir, recursively */
function __createDir(rootDirEntry, folders, success,error) {
rootDirEntry.getDirectory(folders[0], {create: true}, function(dirEntry) {
// Recursively add the new subfolder (if we still have another to create).
if (folders.length > 1) {
__createDir(dirEntry, folders.slice(1),success,error);
} else {
success(dirEntry);
}
}, error);
}
function dirname(str) {
var parts = str.split('/');
if(parts.length > 1) {
parts.splice(parts.length-1,1);
return parts.join('/');
} else {
return '';
}
}
function filename(str) {
var parts = str.split('/');
return parts[parts.length-1];
}
var transferQueue = [], // queued fileTransfers
inprogress = 0; // currently active filetransfers
/**
* Factory function: Create a single instance (based on single FileSystem)
*/
module.exports = function(options){
/* Promise implementation */
var Promise = options.Promise || window.Promise;
if(!Promise) { throw new Error("No Promise library given in options.Promise"); }
/* default options */
this.options = options = options || {};
options.persistent = options.persistent !== undefined? options.persistent: true;
options.storageSize = options.storageSize || 20*1024*1024;
options.concurrency = options.concurrency || 3;
options.retry = options.retry || [];
/* Cordova deviceready promise */
var deviceready, isCordova = typeof cordova !== 'undefined';
if(isCordova){
deviceready = new Promise(function(resolve,reject){
document.addEventListener("deviceready", resolve, false);
setTimeout(function(){ reject(new Error('deviceready has not fired after 5 seconds.')); },5100);
});
} else {
/* FileTransfer implementation for Chrome */
deviceready = Promise.resolve();
if(typeof webkitRequestFileSystem !== 'undefined'){
window.requestFileSystem = webkitRequestFileSystem;
window.FileTransfer = function FileTransfer(){};
FileTransfer.prototype.download = function download(url,file,win,fail) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.onreadystatechange = function(onSuccess, onError, cb) {
if (xhr.readyState == 4) {
if(xhr.status === 200){
write(file,xhr.responseText).then(win,fail);
} else {
fail(xhr.status);
}
}
};
xhr.send();
return xhr;
};
} else {
window.requestFileSystem = function(x,y,z,fail){
fail(new Error('requestFileSystem not supported!'));
};
}
}
/* the filesystem! */
var fs = new Promise(function(resolve,reject){
deviceready.then(function(){
window.requestFileSystem(options.persistent? 1: 0, options.storageSize, resolve, reject);
setTimeout(function(){ reject(new Error('Could not retrieve FileSystem after 5 seconds.')); },5100);
},reject);
});
/* debug */
fs.then(function(fs){
window.__fs = fs;
},function(err){
console.error('Could not get Cordova FileSystem:',err);
});
function create(path){
return ensure(dirname(path)).then(function(){
return file(path,{create:true});
});
}
/* ensure directory exists */
function ensure(folders) {
return new Promise(function(resolve,reject){
return fs.then(function(fs){
if(!folders) {
resolve(fs.root);
} else {
folders = folders.split('/').filter(function(folder) {
return folder && folder.length > 0 && folder[0] !== '.';
});
__createDir(fs.root,folders,resolve,reject);
}
},reject);
});
}
/* does file exist? If so, resolve with fileEntry, if not, resolve with false. */
function exists(path){
return new Promise(function(resolve,reject){
file(path).then(
function(fileEntry){
resolve(fileEntry);
},
function(err){
if(err.code === 1) {
resolve(false);
} else {
reject(err);
}
}
);
});
}
/* convert path to URL to be used in JS/CSS/HTML */
function toURL(path) {
return file(path).then(function(fileEntry) {
return fileEntry.toURL();
});
}
/* convert path to URL to be used in JS/CSS/HTML */
var toInternalURL,toInternalURLSync;
if(isCordova) {
/* synchronous helper to get internal URL. */
toInternalURLSync = function(path){
if(path[0] !== '/') path = '/' + path;
return 'cdvfile://localhost/'+(options.persistent? 'persistent':'temporary') + path;
};
toInternalURL = function(path) {
return file(path).then(function(fileEntry) {
return fileEntry.toInternalURL();
});
};
} else {
/* synchronous helper to get internal URL. */
toInternalURLSync = function(path){
if(path[0] !== '/') path = '/' + path;
return 'filesystem:'+location.origin+(options.persistent? '/persistent':'/temporary') + path;
};
toInternalURL = function(path) {
return file(path).then(function(fileEntry) {
return fileEntry.toURL();
});
};
}
/* convert path to base64 date URI */
function toDataURL(path) {
return read(path,'readAsDataURL');
}
/* get file file */
function file(path,options){
options = options || {};
return new Promise(function(resolve,reject){
return fs.then(function(fs){
fs.root.getFile(path,options,resolve,reject);
},reject);
});
}
/* get directory entry */
function dir(path,options){
options = options || {};
return new Promise(function(resolve,reject){
return fs.then(function(fs){
if(!path || path === '/') {
resolve(fs.root);
} else {
fs.root.getDirectory(path,options,resolve,reject);
}
},reject);
});
}
/* return contents of a file */
function read(path,method) {
method = method || 'readAsText';
return file(path).then(function(fileEntry) {
return new Promise(function(resolve,reject){
fileEntry.file(function(file){
var reader = new FileReader();
reader.onloadend = function(){
resolve(this.result);
};
reader[method](file);
},reject);
});
});
}
function readJSON(path){
return read(path).then(JSON.parse);
}
/* write contents to a file */
function write(path,blob,mimeType) {
return ensure(dirname(path))
.then(function() { return file(path,{create:true}); })
.then(function(fileEntry) {
return new Promise(function(resolve,reject){
fileEntry.createWriter(function(writer){
writer.onwriteend = resolve;
writer.onerror = reject;
if(typeof blob === 'string') {
blob = new Blob([blob],{type: mimeType || 'text/plain'});
} else if(blob instanceof Blob !== true){
blob = new Blob([JSON.stringify(blob,null,4)],{type: mimeType || 'application/json'});
}
writer.write(blob);
},reject);
});
});
}
/* move a file */
function move(src,dest) {
return ensure(dirname(dest))
.then(function(dir) {
return file(src).then(function(fileEntry){
return new Promise(function(resolve,reject){
fileEntry.moveTo(dir,filename(dest),resolve,reject);
});
});
});
}
/* copy a file */
function copy(src,dest) {
return ensure(dirname(dest))
.then(function(dir) {
return file(src).then(function(fileEntry){
return new Promise(function(resolve,reject){
fileEntry.copyTo(dir,filename(dest),resolve,reject);
});
});
});
}
/* delete a file */
function remove(path,mustExist) {
var method = mustExist? file:exists;
return new Promise(function(resolve,reject){
method(path).then(function(fileEntry){
if(fileEntry !== false) {
fileEntry.remove(resolve,reject);
} else {
resolve();
}
},reject);
});
}
/* delete a directory */
function removeDir(path) {
return dir(path).then(function(dirEntry){
return new Promise(function(resolve,reject) {
dirEntry.removeRecursively(resolve,reject);
});
});
}
/* list contents of a directory */
function list(path,mode) {
mode = mode || '';
var recursive = mode.indexOf('r') > -1;
var getAsEntries = mode.indexOf('e') > -1;
var onlyFiles = mode.indexOf('f') > -1;
var onlyDirs = mode.indexOf('d') > -1;
if(onlyFiles && onlyDirs) {
onlyFiles = false;
onlyDirs = false;
}
return new Promise(function(resolve,reject){
return dir(path).then(function(dirEntry){
var dirReader = dirEntry.createReader();
dirReader.readEntries(function(entries) {
var promises = [Promise.resolve(entries)];
if(recursive) {
entries
.filter(function(entry){return entry.isDirectory; })
.forEach(function(entry){
promises.push(list(entry.fullPath,'re'));
});
}
Promise.all(promises).then(function(values){
var entries = [];
entries = entries.concat.apply(entries,values);
if(onlyFiles) entries = entries.filter(function(entry) { return entry.isFile; });
if(onlyDirs) entries = entries.filter(function(entry) { return entry.isDirectory; });
if(!getAsEntries) entries = entries.map(function(entry) { return entry.fullPath; });
resolve(entries);
},reject);
}, reject);
},reject);
});
}
// Whenever we want to start a transfer, we call popTransferQueue
function popTransferQueue(){
// while we are not at max concurrency
while(transferQueue.length > 0 && inprogress < options.concurrency){
// increment activity counter
inprogress++;
// fetch filetranfer, method-type (isDownload) and arguments
var args = transferQueue.pop();
var ft = args.shift();
var isDownload = args.shift();
var serverUrl = args.shift();
var localPath = args.shift();
var win = args.shift();
var fail = args.shift();
var trustAllHosts = args.shift();
var transferOptions = args.shift();
if(ft._aborted) {
inprogress--;
} else if(isDownload){
ft.download.call(ft,serverUrl,localPath,win,fail,trustAllHosts,transferOptions);
if(ft.onprogress) ft.onprogress(new ProgressEvent());
} else {
ft.upload.call(ft,localPath,serverUrl,win,fail,transferOptions,trustAllHosts);
}
}
// if we are at max concurrency, popTransferQueue() will be called whenever
// the transfer is ready and there is space avaialable.
}
// Promise callback to check if there are any more queued transfers
function nextTransfer(result){
inprogress--; // decrement counter to free up one space to start transfers again!
popTransferQueue(); // check if there are any queued transfers
return result;
}
function filetransfer(isDownload,serverUrl,localPath,transferOptions,onprogress){
if(typeof transferOptions === 'function') {
onprogress = transferOptions;
transferOptions = {};
}
serverUrl = encodeURI(serverUrl);
if(isCordova) localPath = toInternalURLSync(localPath);
transferOptions = transferOptions || {};
if(!transferOptions.retry || !transferOptions.retry.length) {
transferOptions.retry = options.retry;
}
transferOptions.retry = transferOptions.retry.concat();
var ft = new FileTransfer();
if(typeof onprogress === 'function') ft.onprogress = onprogress;
var promise = new Promise(function(resolve,reject){
var attempt = function(err){
if(transferOptions.retry.length === 0) {
reject(err);
} else {
transferQueue.unshift([ft,isDownload,serverUrl,localPath,resolve,attempt,transferOptions.trustAllHosts || false,transferOptions]);
var timeout = transferOptions.retry.shift();
if(timeout > 0) {
setTimeout(nextTransfer,timeout);
} else {
nextTransfer();
}
}
};
transferOptions.retry.unshift(0);
inprogress++;
attempt();
});
promise.then(nextTransfer,nextTransfer);
promise.progress = function(onprogress){
ft.onprogress = onprogress;
return promise;
};
promise.abort = function(){
ft._aborted = true;
ft.abort();
return promise;
};
return promise;
}
function download(url,dest,options,onprogress){
return filetransfer(true,url,dest,options,onprogress);
}
function upload(source,dest,options,onprogress){
return filetransfer(false,dest,source,options,onprogress);
}
return {
fs: fs,
file: file,
filename: filename,
dir: dir,
dirname: dirname,
create:create,
read: read,
readJSON: readJSON,
write: write,
move: move,
copy: copy,
remove: remove,
removeDir: removeDir,
list: list,
ensure: ensure,
exists: exists,
download: download,
upload: upload,
toURL:toURL,
isCordova:isCordova,
toInternalURLSync: toInternalURLSync,
toInternalURL:toInternalURL,
toDataURL:toDataURL,
deviceready: deviceready,
options: options,
Promise: Promise
};
};
/***/ },
/* 3 */
/***/ function(module, exports, __webpack_require__) {
/**@license MIT-promiscuous-©Ruben Verborgh*/
(function (func, obj) {
// Type checking utility function
function is(type, item) { return (typeof item)[0] == type; }
// Creates a promise, calling callback(resolve, reject), ignoring other parameters.
function Promise(callback, handler) {
// The `handler` variable points to the function that will
// 1) handle a .then(resolved, rejected) call
// 2) handle a resolve or reject call (if the first argument === `is`)
// Before 2), `handler` holds a queue of callbacks.
// After 2), `handler` is a finalized .then handler.
handler = function pendingHandler(resolved, rejected, value, queue, then, i) {
queue = pendingHandler.q;
// Case 1) handle a .then(resolved, rejected) call
if (resolved != is) {
return Promise(function (resolve, reject) {
queue.push({ p: this, r: resolve, j: reject, 1: resolved, 0: rejected });
});
}
// Case 2) handle a resolve or reject call
// (`resolved` === `is` acts as a sentinel)
// The actual function signature is
// .re[ject|solve](<is>, success, value)
// Check if the value is a promise and try to obtain its `then` method
if (value && (is(func, value) | is(obj, value))) {
try { then = value.then; }
catch (reason) { rejected = 0; value = reason; }
}
// If the value is a promise, take over its state
if (is(func, then)) {
function valueHandler(resolved) {
return function (value) { then && (then = 0, pendingHandler(is, resolved, value)); };
}
try { then.call(value, valueHandler(1), rejected = valueHandler(0)); }
catch (reason) { rejected(reason); }
}
// The value is not a promise; handle resolve/reject
else {
// Replace this handler with a finalized resolved/rejected handler
handler = function (Resolved, Rejected) {
// If the Resolved or Rejected parameter is not a function,
// return the original promise (now stored in the `callback` variable)
if (!is(func, (Resolved = rejected ? Resolved : Rejected)))
return callback;
// Otherwise, return a finalized promise, transforming the value with the function
return Promise(function (resolve, reject) { finalize(this, resolve, reject, value, Resolved); });
};
// Resolve/reject pending callbacks
i = 0;
while (i < queue.length) {
then = queue[i++];
// If no callback, just resolve/reject the promise
if (!is(func, resolved = then[rejected]))
(rejected ? then.r : then.j)(value);
// Otherwise, resolve/reject the promise with the result of the callback
else
finalize(then.p, then.r, then.j, value, resolved);
}
}
};
// The queue of pending callbacks; garbage-collected when handler is resolved/rejected
handler.q = [];
// Create and return the promise (reusing the callback variable)
callback.call(callback = { then: function (resolved, rejected) { return handler(resolved, rejected); },
catch: function (rejected) { return handler(0, rejected); } },
function (value) { handler(is, 1, value); },
function (reason) { handler(is, 0, reason); });
return callback;
}
// Finalizes the promise by resolving/rejecting it with the transformed value
function finalize(promise, resolve, reject, value, transform) {
setImmediate(function () {
try {
// Transform the value through and check whether it's a promise
value = transform(value);
transform = value && (is(obj, value) | is(func, value)) && value.then;
// Return the result if it's not a promise
if (!is(func, transform))
resolve(value);
// If it's a promise, make sure it's not circular
else if (value == promise)
reject(TypeError());
// Take over the promise's state
else
transform.call(value, resolve, reject);
}
catch (error) { reject(error); }
});
}
// Export the main module
module.exports = Promise;
// Creates a resolved promise
Promise.resolve = ResolvedPromise;
function ResolvedPromise(value) { return Promise(function (resolve) { resolve(value); }); }
// Creates a rejected promise
Promise.reject = function (reason) { return Promise(function (resolve, reject) { reject(reason); }); };
// Transforms an array of promises into a promise for an array
Promise.all = function (promises) {
return Promise(function (resolve, reject, count, values) {
// Array of collected values
values = [];
// Resolve immediately if there are no promises
count = promises.length || resolve(values);
// Transform all elements (`map` is shorter than `forEach`)
promises.map(function (promise, index) {
ResolvedPromise(promise).then(
// Store the value and resolve if it was the last
function (value) {
values[index] = value;
--count || resolve(values);
},
// Reject if one element fails
reject);
});
});
};
})('f', 'o');
/***/ },
/* 4 */
/***/ function(module, exports, __webpack_require__) {
var hash = __webpack_require__(5);
var Promise = null;
var isCordova = typeof cordova !== 'undefined';
if(!isCordova) {
window.ProgressEvent = function ProgressEvent(){}
}
/* Cordova File Cache x */
function FileCache(options){
// cordova-promise-fs
this._fs = options.fs;
if(!this._fs) {
throw new Error('Missing required option "fs". Add an instance of cordova-promise-fs.');
}
// Use Promises from fs.
Promise = this._fs.Promise;
// 'mirror' mirrors files structure from "serverRoot" to "localRoot"
// 'hash' creates a 1-deep filestructure, where the filenames are hashed server urls (with extension)
this._mirrorMode = options.mode !== 'hash';
this._retry = options.retry || [500,1500,8000];
this._cacheBuster = !!options.cacheBuster;
// normalize path
this._localRoot = options.localRoot || 'data';
if(this._localRoot[this._localRoot.length -1] !== '/') this._localRoot += '/';
if(this._localRoot[0] !== '/') this._localRoot = '/' + this._localRoot;
this._serverRoot = options.serverRoot || '';
if(!!this._serverRoot && this._serverRoot[this._serverRoot.length-1] !== '/') this._serverRoot += '/';
if(this._serverRoot === './') this._serverRoot = '';
// set internal variables
this._downloading = []; // download promises
this._added = []; // added files
this._cached = {}; // cached files
// list existing cache contents
this.ready = this.list();
}
/**
* Helper to cache all 'internalURL' and 'URL' for quick synchronous access
* to the cached files.
*/
FileCache.prototype.list = function list(){
var self = this;
return new Promise(function(resolve,reject){
self._fs.list(self._localRoot,'rfe').then(function(entries){
self._cached = {};
entries = entries.map(function(entry){
self._cached[entry.fullPath] = {
toInternalURL: isCordova? entry.toInternalURL(): entry.toURL(),
toURL: entry.toURL(),
};
return entry.fullPath;
});
resolve(entries);
},function(){
resolve([]);
});
});
};
FileCache.prototype.add = function add(urls){
if(!urls) urls = [];
if(typeof urls === 'string') urls = [urls];
var self = this;
urls.forEach(function(url){
url = self.toServerURL(url);
if(self._added.indexOf(url) === -1) {
self._added.push(url);
}
});
return self.isDirty();
};
FileCache.prototype.remove = function remove(urls,returnPromises){
if(!urls) urls = [];
var promises = [];
if(typeof urls === 'string') urls = [urls];
var self = this;
urls.forEach(function(url){
var index = self._added.indexOf(self.toServerURL(url));
if(index >= 0) self._added.splice(index,1);
var path = self.toPath(url);
promises.push(self._fs.remove(path));
delete self._cached[path];
});
return returnPromises? Promise.all(promises): self.isDirty();
};
FileCache.prototype.getDownloadQueue = function(){
var self = this;
var queue = self._added.filter(function(url){
return !self.isCached(url);
});
return queue;
};
FileCache.prototype.getAdded = function() {
return this._added;
};
FileCache.prototype.isDirty = function isDirty(){
return this.getDownloadQueue().length > 0;
};
FileCache.prototype.download = function download(onprogress){
var fs = this._fs;
var self = this;
self.abort();
return new Promise(function(resolve,reject){
// make sure cache directory exists and that
// we have retrieved the latest cache contents
// to avoid downloading files we already have!
fs.ensure(self._localRoot).then(function(){
return self.list();
}).then(function(){
// no dowloads needed, resolve
if(!self.isDirty()) {
resolve(self);
return;
}
// keep track of number of downloads!
var queue = self.getDownloadQueue();
var started = [];
var index = self._downloading.length;
var done = self._downloading.length;
var total = self._downloading.length + queue.length;
// download every file in the queue (which is the diff from _added with _cached)
queue.forEach(function(url){
var path = self.toPath(url);
// augment progress event with index/total stats
var onSingleDownloadProgress;
if(typeof onprogress === 'function') {
onSingleDownloadProgress = function(ev){
ev.queueIndex = index;
ev.queueSize = total;
ev.url = url;
ev.path = path;
ev.percentage = index / total;
if(ev.loaded > 0 && ev.total > 0 && index !== total){
ev.percentage += (ev.loaded / ev.total) / total;
}
if(started.indexOf(url) < 0) {
started.push(url);
index++;
}
onprogress(ev);
};
}
// callback
var onDone = function(){
done++;
// when we're done
if(done === total) {
// reset downloads
self._downloading = [];
// check if we got everything
self.list().then(function(){
// final progress event!
if(onSingleDownloadProgress) onSingleDownloadProgress(new ProgressEvent());
// Yes, we're not dirty anymore!
if(!self.isDirty()) {
resolve(self);
// Aye, some files got left behind!
} else {
reject(self.getDownloadQueue());
}
},reject);
}
};
var downloadUrl = url;
if(self._cacheBuster) downloadUrl += "?"+Date.now();
var download = fs.download(url,path,{retry:self._retry},onSingleDownloadProgress);
download.then(onDone,onDone);
self._downloading.push(download);
});
},reject);
});
};
FileCache.prototype.abort = function abort(){
this._downloading.forEach(function(download){
download.abort();
});
this._downloading = [];
};
FileCache.prototype.isCached = function isCached(url){
url = this.toPath(url);
return !!this._cached[url];
};
FileCache.prototype.clear = function clear(){
this._cached = {};
return this._fs.removeDir(this._localRoot);
};
/**
* Helpers to output to various formats
*/
FileCache.prototype.toInternalURL = function toInternalURL(url){
path = this.toPath(url);
if(this._cached[path]) return this._cached[path].toInternalURL;
return this._fs.toInternalURLSync(path);
};
FileCache.prototype.get = function get(url){
path = this.toPath(url);
if(this._cached[path]) return this._cached[path].toInternalURL;
return this.toServerURL(url);
};
FileCache.prototype.toDataURL = function toDataURL(url){
return this._fs.toDataURL(this.toPath(url));
};
FileCache.prototype.toURL = function toURL(url){
path = this.toPath(url);
return this._cached[path]? this._cached[path].toURL: url;
};
FileCache.prototype.toServerURL = function toServerURL(path){
if(path[0] === '/') path = path.substr(1);
return path.indexOf('://') < 0? this._serverRoot + path: path;
};
/**
* Helper to transform remote URL to a local path (for cordova-promise-fs)
*/
FileCache.prototype.toPath = function toPath(url){
if(this._mirrorMode) {
url = url || '';
len = this._serverRoot.length;
if(url.substr(0,len) !== this._serverRoot) {
if(url[0] === '/') url = url.substr(1);
return this._localRoot + url;
} else {
return this._localRoot + url.substr(len);
}
} else {
return this._localRoot + hash(url) + url.substr(url.lastIndexOf('.'));
}
};
module.exports = FileCache;
/***/ },
/* 5 */
/***/ function(module, exports, __webpack_require__) {
/**
* JS Implementation of MurmurHash3 (r136) (as of May 20, 2011)
*
* @author <a href="mailto:gary.court@gmail.com">Gary Court</a>
* @see http://github.com/garycourt/murmurhash-js
* @author <a href="mailto:aappleby@gmail.com">Austin Appleby</a>
* @see http://sites.google.com/site/murmurhash/
*
* @param {string} key ASCII only
* @param {number} seed Positive integer only
* @return {number} 32-bit positive integer hash
*/
function murmurhash3_32_gc(key, seed) {
var remainder, bytes, h1, h1b, c1, c1b, c2, c2b, k1, i;
remainder = key.length & 3; // key.length % 4
bytes = key.length - remainder;
h1 = seed;
c1 = 0xcc9e2d51;
c2 = 0x1b873593;
i = 0;
while (i < bytes) {
k1 =
((key.charCodeAt(i) & 0xff)) |
((key.charCodeAt(++i) & 0xff) << 8) |
((key.charCodeAt(++i) & 0xff) << 16) |
((key.charCodeAt(++i) & 0xff) << 24);
++i;
k1 = ((((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16))) & 0xffffffff;
k1 = (k1 << 15) | (k1 >>> 17);
k1 = ((((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16))) & 0xffffffff;
h1 ^= k1;
h1 = (h1 << 13) | (h1 >>> 19);
h1b = ((((h1 & 0xffff) * 5) + ((((h1 >>> 16) * 5) & 0xffff) << 16))) & 0xffffffff;
h1 = (((h1b & 0xffff) + 0x6b64) + ((((h1b >>> 16) + 0xe654) & 0xffff) << 16));
}
k1 = 0;
switch (remainder) {
case 3: k1 ^= (key.charCodeAt(i + 2) & 0xff) << 16;
case 2: k1 ^= (key.charCodeAt(i + 1) & 0xff) << 8;
case 1: k1 ^= (key.charCodeAt(i) & 0xff);
k1 = (((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff;
k1 = (k1 << 15) | (k1 >>> 17);
k1 = (((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff;
h1 ^= k1;
}
h1 ^= key.length;
h1 ^= h1 >>> 16;
h1 = (((h1 & 0xffff) * 0x85ebca6b) + ((((h1 >>> 16) * 0x85ebca6b) & 0xffff) << 16)) & 0xffffffff;
h1 ^= h1 >>> 13;
h1 = ((((h1 & 0xffff) * 0xc2b2ae35) + ((((h1 >>> 16) * 0xc2b2ae35) & 0xffff) << 16))) & 0xffffffff;
h1 ^= h1 >>> 16;
return h1 >>> 0;
}
module.exports = murmurhash3_32_gc;
/***/ }
/******/ ])
// 3. Chrome: On page becomes visible again
function handleVisibilityChange() {
if (!document.webkitHidden) {
check();
}
}
document.addEventListener("webkitvisibilitychange", handleVisibilityChange, false);
})();

@@ -1,1 +0,1 @@

!function(t){function e(o){if(n[o])return n[o].exports;var r=n[o]={exports:{},id:o,loaded:!1};return t[o].call(r.exports,r,r.exports,e),r.loaded=!0,r.exports}var n={};return e.m=t,e.c=n,e.p="",e(0)}([function(t,e,n){function o(){a.check().then(function(){return a.download()}).then(function(){return a.update()},function(t){console.error("Auto-update error:",t)})}function r(){document.webkitHidden||o()}var i=n(1),s=n(2),u=n(3);window.setImmediate=window.setTimeout;var c,a,f,h,d="undefined"!=typeof cordova;if(f=document.querySelector("script[server]"),f&&(h=f.getAttribute("server")),!h)throw new Error('Add a "server" attribute to the autoupdate.js script!');c=new s({persistent:d,Promise:u}),a=new i({fs:c,localRoot:"app",serverRoot:h,mode:"mirror",cacheBuster:!0}),o(),c.deviceready.then(function(){document.addEventListener("resume",o)}),document.addEventListener("webkitvisibilitychange",r,!1)},function(t,e,n){function o(t){var e={};return Object.keys(t).forEach(function(n){e[t[n].filename]=t[n]}),e}function r(t){if(!t)throw new Error("CordovaAppLoader has no options!");if(!t.fs)throw new Error('CordovaAppLoader has no "fs" option (cordova-promise-fs)');if(!t.serverRoot)throw new Error('CordovaAppLoader has no "serverRoot" option.');if(!window.pegasus||!window.Manifest)throw new Error("CordovaAppLoader bootstrap.js is missing.");s=t.fs.Promise,this.manifest=window.Manifest,this.newManifest=null,t.serverRoot=t.serverRoot||"",t.serverRoot&&"/"!==t.serverRoot[t.serverRoot.length-1]&&(t.serverRoot+="/"),this.newManifestUrl=t.serverRoot+(t.manifest||"manifest.json"),t.mode&&(t.mode="mirror"),this.cache=new i(t),this._toBeDeleted=[],this._toBeDownloaded=[],this._updateReady=!1,this._checkTimeout=t.checkTimeout||1e4}var i=n(4),s=null;r.prototype.check=function(t){var e=this,n=this.manifest;return new s(function(r,i){function s(t){e.cache.ready.then(function(){if(!t.files)return void i('Downloaded Manifest has no "files" attribute.');var s=o(t.files),u=o(n.files);e._toBeDownloaded=Object.keys(s).filter(function(t){return!u[t]||u[t].version!==s[t].version||!e.cache.isCached(t)}),e.cache.list().then(function(n){e._toBeDeleted=n.map(function(t){return t.substr(e.cache._localRoot.length)}).filter(function(t){return!s[t]}).concat(e._toBeDownloaded),e._toBeDeleted.length>0||e._toBeDownloaded.length>0?(e.newManifest=t,e.newManifest.root=e.cache.toInternalURL("/")+(e.newManifest.root||""),r(!0)):r(!1)},i)},i)}"string"==typeof t&&(e.newManifestUrl=t,t=void 0),"object"==typeof t?s(t):(pegasus(e.newManifestUrl).then(s,i),setTimeout(function(){i(new Error("timeout"))},e._checkTimeout))})},r.prototype.canDownload=function(){return!!this.newManifest&&!this._updateReady},r.prototype.canUpdate=function(){return this._updateReady},r.prototype.download=function(t){var e=this;return e.canDownload()?(localStorage.removeItem("manifest"),this.manifest.files=Manifest.files={},e.cache.remove(e._toBeDeleted,!0).then(function(){return e.cache.add(e._toBeDownloaded),e.cache.download(t)}).then(function(){return e._toBeDeleted=[],e._toBeDownloaded=[],e._updateReady=!0,e.newManifest},function(t){return t&&t.length&&e.cache.remove(t),t})):s.resolve(null)},r.prototype.update=function(t){return this._updateReady?(localStorage.setItem("manifest",JSON.stringify(this.newManifest)),t!==!1&&location.reload(),!0):!1},r.prototype.clear=function(){return localStorage.removeItem("manifest"),this.cache.clear()},r.prototype.reset=function(){return this.clear().then(function(){location.reload()},function(){location.reload()})},t.exports=r},function(t){function e(t,n,o,r){t.getDirectory(n[0],{create:!0},function(t){n.length>1?e(t,n.slice(1),o,r):o(t)},r)}function n(t){var e=t.split("/");return e.length>1?(e.splice(e.length-1,1),e.join("/")):""}function o(t){var e=t.split("/");return e[e.length-1]}var r=[],i=0;t.exports=function(t){function s(t){return u(n(t)).then(function(){return h(t,{create:!0})})}function u(t){return new S(function(n,o){return P.then(function(r){t?(t=t.split("/").filter(function(t){return t&&t.length>0&&"."!==t[0]}),e(r.root,t,n,o)):n(r.root)},o)})}function c(t){return new S(function(e,n){h(t).then(function(t){e(t)},function(t){1===t.code?e(!1):n(t)})})}function a(t){return h(t).then(function(t){return t.toURL()})}function f(t){return l(t,"readAsDataURL")}function h(t,e){return e=e||{},new S(function(n,o){return P.then(function(r){r.root.getFile(t,e,n,o)},o)})}function d(t,e){return e=e||{},new S(function(n,o){return P.then(function(r){t&&"/"!==t?r.root.getDirectory(t,e,n,o):n(r.root)},o)})}function l(t,e){return e=e||"readAsText",h(t).then(function(t){return new S(function(n,o){t.file(function(t){var o=new FileReader;o.onloadend=function(){n(this.result)},o[e](t)},o)})})}function p(t){return l(t).then(JSON.parse)}function v(t,e,o){return u(n(t)).then(function(){return h(t,{create:!0})}).then(function(t){return new S(function(n,r){t.createWriter(function(t){t.onwriteend=n,t.onerror=r,"string"==typeof e?e=new Blob([e],{type:o||"text/plain"}):e instanceof Blob!=!0&&(e=new Blob([JSON.stringify(e,null,4)],{type:o||"application/json"})),t.write(e)},r)})})}function w(t,e){return u(n(e)).then(function(n){return h(t).then(function(t){return new S(function(r,i){t.moveTo(n,o(e),r,i)})})})}function y(t,e){return u(n(e)).then(function(n){return h(t).then(function(t){return new S(function(r,i){t.copyTo(n,o(e),r,i)})})})}function _(t,e){var n=e?h:c;return new S(function(e,o){n(t).then(function(t){t!==!1?t.remove(e,o):e()},o)})}function m(t){return d(t).then(function(t){return new S(function(e,n){t.removeRecursively(e,n)})})}function g(t,e){e=e||"";var n=e.indexOf("r")>-1,o=e.indexOf("e")>-1,r=e.indexOf("f")>-1,i=e.indexOf("d")>-1;return r&&i&&(r=!1,i=!1),new S(function(e,s){return d(t).then(function(t){var u=t.createReader();u.readEntries(function(t){var u=[S.resolve(t)];n&&t.filter(function(t){return t.isDirectory}).forEach(function(t){u.push(g(t.fullPath,"re"))}),S.all(u).then(function(t){var n=[];n=n.concat.apply(n,t),r&&(n=n.filter(function(t){return t.isFile})),i&&(n=n.filter(function(t){return t.isDirectory})),o||(n=n.map(function(t){return t.fullPath})),e(n)},s)},s)},s)})}function R(){for(;r.length>0&&i<t.concurrency;){i++;var e=r.pop(),n=e.shift(),o=e.shift(),s=e.shift(),u=e.shift(),c=e.shift(),a=e.shift(),f=e.shift(),h=e.shift();n._aborted?i--:o?(n.download.call(n,s,u,c,a,f,h),n.onprogress&&n.onprogress(new ProgressEvent)):n.upload.call(n,u,s,c,a,h,f)}}function D(t){return i--,R(),t}function L(e,n,o,s,u){"function"==typeof s&&(u=s,s={}),n=encodeURI(n),x&&(o=B(o)),s=s||{},s.retry&&s.retry.length||(s.retry=t.retry),s.retry=s.retry.concat();var c=new FileTransfer;"function"==typeof u&&(c.onprogress=u);var a=new S(function(t,u){var a=function(i){if(0===s.retry.length)u(i);else{r.unshift([c,e,n,o,t,a,s.trustAllHosts||!1,s]);var f=s.retry.shift();f>0?setTimeout(D,f):D()}};s.retry.unshift(0),i++,a()});return a.then(D,D),a.progress=function(t){return c.onprogress=t,a},a.abort=function(){return c._aborted=!0,c.abort(),a},a}function U(t,e,n,o){return L(!0,t,e,n,o)}function b(t,e,n,o){return L(!1,e,t,n,o)}var S=t.Promise||window.Promise;if(!S)throw new Error("No Promise library given in options.Promise");this.options=t=t||{},t.persistent=void 0!==t.persistent?t.persistent:!0,t.storageSize=t.storageSize||20971520,t.concurrency=t.concurrency||3,t.retry=t.retry||[];var E,x="undefined"!=typeof cordova;x?E=new S(function(t,e){document.addEventListener("deviceready",t,!1),setTimeout(function(){e(new Error("deviceready has not fired after 5 seconds."))},5100)}):(E=S.resolve(),"undefined"!=typeof webkitRequestFileSystem?(window.requestFileSystem=webkitRequestFileSystem,window.FileTransfer=function(){},FileTransfer.prototype.download=function(t,e,n,o){var r=new XMLHttpRequest;return r.open("GET",t),r.onreadystatechange=function(){4==r.readyState&&(200===r.status?v(e,r.responseText).then(n,o):o(r.status))},r.send(),r}):window.requestFileSystem=function(t,e,n,o){o(new Error("requestFileSystem not supported!"))});var P=new S(function(e,n){E.then(function(){window.requestFileSystem(t.persistent?1:0,t.storageSize,e,n),setTimeout(function(){n(new Error("Could not retrieve FileSystem after 5 seconds."))},5100)},n)});P.then(function(t){window.__fs=t},function(t){console.error("Could not get Cordova FileSystem:",t)});var A,B;return x?(B=function(e){return"/"!==e[0]&&(e="/"+e),"cdvfile://localhost/"+(t.persistent?"persistent":"temporary")+e},A=function(t){return h(t).then(function(t){return t.toInternalURL()})}):(B=function(e){return"/"!==e[0]&&(e="/"+e),"filesystem:"+location.origin+(t.persistent?"/persistent":"/temporary")+e},A=function(t){return h(t).then(function(t){return t.toURL()})}),{fs:P,file:h,filename:o,dir:d,dirname:n,create:s,read:l,readJSON:p,write:v,move:w,copy:y,remove:_,removeDir:m,list:g,ensure:u,exists:c,download:U,upload:b,toURL:a,isCordova:x,toInternalURLSync:B,toInternalURL:A,toDataURL:f,deviceready:E,options:t,Promise:S}}},function(t){!function(e,n){function o(t,e){return(typeof e)[0]==t}function r(t,s){return s=function u(c,a,f,h,d,l){function p(t){return function(e){d&&(d=0,u(o,t,e))}}if(h=u.q,c!=o)return r(function(t,e){h.push({p:this,r:t,j:e,1:c,0:a})});if(f&&o(e,f)|o(n,f))try{d=f.then}catch(t){a=0,f=t}if(o(e,d))try{d.call(f,p(1),a=p(0))}catch(t){a(t)}else for(s=function(n,s){return o(e,n=a?n:s)?r(function(t,e){i(this,t,e,f,n)}):t},l=0;l<h.length;)d=h[l++],o(e,c=d[a])?i(d.p,d.r,d.j,f,c):(a?d.r:d.j)(f)},s.q=[],t.call(t={then:function(t,e){return s(t,e)},catch:function(t){return s(0,t)}},function(t){s(o,1,t)},function(t){s(o,0,t)}),t}function i(t,r,i,s,u){setImmediate(function(){try{s=u(s),u=s&&o(n,s)|o(e,s)&&s.then,o(e,u)?s==t?i(TypeError()):u.call(s,r,i):r(s)}catch(t){i(t)}})}function s(t){return r(function(e){e(t)})}t.exports=r,r.resolve=s,r.reject=function(t){return r(function(e,n){n(t)})},r.all=function(t){return r(function(e,n,o,r){r=[],o=t.length||e(r),t.map(function(t,i){s(t).then(function(t){r[i]=t,--o||e(r)},n)})})}}("f","o")},function(t,e,n){function o(t){if(this._fs=t.fs,!this._fs)throw new Error('Missing required option "fs". Add an instance of cordova-promise-fs.');i=this._fs.Promise,this._mirrorMode="hash"!==t.mode,this._retry=t.retry||[500,1500,8e3],this._cacheBuster=!!t.cacheBuster,this._localRoot=t.localRoot||"data","/"!==this._localRoot[this._localRoot.length-1]&&(this._localRoot+="/"),"/"!==this._localRoot[0]&&(this._localRoot="/"+this._localRoot),this._serverRoot=t.serverRoot||"",this._serverRoot&&"/"!==this._serverRoot[this._serverRoot.length-1]&&(this._serverRoot+="/"),"./"===this._serverRoot&&(this._serverRoot=""),this._downloading=[],this._added=[],this._cached={},this.ready=this.list()}var r=n(5),i=null,s="undefined"!=typeof cordova;s||(window.ProgressEvent=function(){}),o.prototype.list=function(){var t=this;return new i(function(e){t._fs.list(t._localRoot,"rfe").then(function(n){t._cached={},n=n.map(function(e){return t._cached[e.fullPath]={toInternalURL:s?e.toInternalURL():e.toURL(),toURL:e.toURL()},e.fullPath}),e(n)},function(){e([])})})},o.prototype.add=function(t){t||(t=[]),"string"==typeof t&&(t=[t]);var e=this;return t.forEach(function(t){t=e.toServerURL(t),-1===e._added.indexOf(t)&&e._added.push(t)}),e.isDirty()},o.prototype.remove=function(t,e){t||(t=[]);var n=[];"string"==typeof t&&(t=[t]);var o=this;return t.forEach(function(t){var e=o._added.indexOf(o.toServerURL(t));e>=0&&o._added.splice(e,1);var r=o.toPath(t);n.push(o._fs.remove(r)),delete o._cached[r]}),e?i.all(n):o.isDirty()},o.prototype.getDownloadQueue=function(){var t=this,e=t._added.filter(function(e){return!t.isCached(e)});return e},o.prototype.getAdded=function(){return this._added},o.prototype.isDirty=function(){return this.getDownloadQueue().length>0},o.prototype.download=function(t){var e=this._fs,n=this;return n.abort(),new i(function(o,r){e.ensure(n._localRoot).then(function(){return n.list()}).then(function(){if(!n.isDirty())return void o(n);var i=n.getDownloadQueue(),s=[],u=n._downloading.length,c=n._downloading.length,a=n._downloading.length+i.length;i.forEach(function(i){var f,h=n.toPath(i);"function"==typeof t&&(f=function(e){e.queueIndex=u,e.queueSize=a,e.url=i,e.path=h,e.percentage=u/a,e.loaded>0&&e.total>0&&u!==a&&(e.percentage+=e.loaded/e.total/a),s.indexOf(i)<0&&(s.push(i),u++),t(e)});var d=function(){c++,c===a&&(n._downloading=[],n.list().then(function(){f&&f(new ProgressEvent),n.isDirty()?r(n.getDownloadQueue()):o(n)},r))},l=i;n._cacheBuster&&(l+="?"+Date.now());var p=e.download(i,h,{retry:n._retry},f);p.then(d,d),n._downloading.push(p)})},r)})},o.prototype.abort=function(){this._downloading.forEach(function(t){t.abort()}),this._downloading=[]},o.prototype.isCached=function(t){return t=this.toPath(t),!!this._cached[t]},o.prototype.clear=function(){return this._cached={},this._fs.removeDir(this._localRoot)},o.prototype.toInternalURL=function(t){return path=this.toPath(t),this._cached[path]?this._cached[path].toInternalURL:this._fs.toInternalURLSync(path)},o.prototype.get=function(t){return path=this.toPath(t),this._cached[path]?this._cached[path].toInternalURL:this.toServerURL(t)},o.prototype.toDataURL=function(t){return this._fs.toDataURL(this.toPath(t))},o.prototype.toURL=function(t){return path=this.toPath(t),this._cached[path]?this._cached[path].toURL:t},o.prototype.toServerURL=function(t){return"/"===t[0]&&(t=t.substr(1)),t.indexOf("://")<0?this._serverRoot+t:t},o.prototype.toPath=function(t){return this._mirrorMode?(t=t||"",len=this._serverRoot.length,t.substr(0,len)!==this._serverRoot?("/"===t[0]&&(t=t.substr(1)),this._localRoot+t):this._localRoot+t.substr(len)):this._localRoot+r(t)+t.substr(t.lastIndexOf("."))},t.exports=o},function(t){function e(t,e){var n,o,r,i,s,u,c,a;for(n=3&t.length,o=t.length-n,r=e,s=3432918353,u=461845907,a=0;o>a;)c=255&t.charCodeAt(a)|(255&t.charCodeAt(++a))<<8|(255&t.charCodeAt(++a))<<16|(255&t.charCodeAt(++a))<<24,++a,c=(65535&c)*s+(((c>>>16)*s&65535)<<16)&4294967295,c=c<<15|c>>>17,c=(65535&c)*u+(((c>>>16)*u&65535)<<16)&4294967295,r^=c,r=r<<13|r>>>19,i=5*(65535&r)+((5*(r>>>16)&65535)<<16)&4294967295,r=(65535&i)+27492+(((i>>>16)+58964&65535)<<16);switch(c=0,n){case 3:c^=(255&t.charCodeAt(a+2))<<16;case 2:c^=(255&t.charCodeAt(a+1))<<8;case 1:c^=255&t.charCodeAt(a),c=(65535&c)*s+(((c>>>16)*s&65535)<<16)&4294967295,c=c<<15|c>>>17,c=(65535&c)*u+(((c>>>16)*u&65535)<<16)&4294967295,r^=c}return r^=t.length,r^=r>>>16,r=2246822507*(65535&r)+((2246822507*(r>>>16)&65535)<<16)&4294967295,r^=r>>>13,r=3266489909*(65535&r)+((3266489909*(r>>>16)&65535)<<16)&4294967295,r^=r>>>16,r>>>0}t.exports=e}]);
!function(){function e(){o.check().then(function(){return o.download()}).then(function(){return o.update()},function(e){console.error("Auto-update error:",e)})}function t(){document.webkitHidden||e()}var r,o,n,i,d="undefined"!=typeof cordova;if(n=document.querySelector("script[server]"),n&&(i=n.getAttribute("server")),!i)throw new Error('Add a "server" attribute to the bootstrap.js script!');r=new CordovaPromiseFS({persistent:d,Promise:Promise}),o=new CordovaAppLoader({fs:r,localRoot:"app",serverRoot:i,mode:"mirror",cacheBuster:!0}),e(),r.deviceready.then(function(){document.addEventListener("resume",e)}),document.addEventListener("webkitvisibilitychange",t,!1)}();

@@ -234,3 +234,3 @@ var CordovaAppLoader =

if(this._localRoot[this._localRoot.length -1] !== '/') this._localRoot += '/';
if(this._localRoot[0] !== '/') this._localRoot = '/' + this._localRoot;
if(this._localRoot[0] === '/') this._localRoot = this._localRoot.substr(1);

@@ -237,0 +237,0 @@ this._serverRoot = options.serverRoot || '';

@@ -1,1 +0,1 @@

var CordovaAppLoader=function(t){function e(n){if(o[n])return o[n].exports;var r=o[n]={exports:{},id:n,loaded:!1};return t[n].call(r.exports,r,r.exports,e),r.loaded=!0,r.exports}var o={};return e.m=t,e.c=o,e.p="",e(0)}([function(t,e,o){function n(t){var e={};return Object.keys(t).forEach(function(o){e[t[o].filename]=t[o]}),e}function r(t){if(!t)throw new Error("CordovaAppLoader has no options!");if(!t.fs)throw new Error('CordovaAppLoader has no "fs" option (cordova-promise-fs)');if(!t.serverRoot)throw new Error('CordovaAppLoader has no "serverRoot" option.');if(!window.pegasus||!window.Manifest)throw new Error("CordovaAppLoader bootstrap.js is missing.");a=t.fs.Promise,this.manifest=window.Manifest,this.newManifest=null,t.serverRoot=t.serverRoot||"",t.serverRoot&&"/"!==t.serverRoot[t.serverRoot.length-1]&&(t.serverRoot+="/"),this.newManifestUrl=t.serverRoot+(t.manifest||"manifest.json"),t.mode&&(t.mode="mirror"),this.cache=new i(t),this._toBeDeleted=[],this._toBeDownloaded=[],this._updateReady=!1,this._checkTimeout=t.checkTimeout||1e4}var i=o(1),a=null;r.prototype.check=function(t){var e=this,o=this.manifest;return new a(function(r,i){function a(t){e.cache.ready.then(function(){if(!t.files)return void i('Downloaded Manifest has no "files" attribute.');var a=n(t.files),s=n(o.files);e._toBeDownloaded=Object.keys(a).filter(function(t){return!s[t]||s[t].version!==a[t].version||!e.cache.isCached(t)}),e.cache.list().then(function(o){e._toBeDeleted=o.map(function(t){return t.substr(e.cache._localRoot.length)}).filter(function(t){return!a[t]}).concat(e._toBeDownloaded),e._toBeDeleted.length>0||e._toBeDownloaded.length>0?(e.newManifest=t,e.newManifest.root=e.cache.toInternalURL("/")+(e.newManifest.root||""),r(!0)):r(!1)},i)},i)}"string"==typeof t&&(e.newManifestUrl=t,t=void 0),"object"==typeof t?a(t):(pegasus(e.newManifestUrl).then(a,i),setTimeout(function(){i(new Error("timeout"))},e._checkTimeout))})},r.prototype.canDownload=function(){return!!this.newManifest&&!this._updateReady},r.prototype.canUpdate=function(){return this._updateReady},r.prototype.download=function(t){var e=this;return e.canDownload()?(localStorage.removeItem("manifest"),this.manifest.files=Manifest.files={},e.cache.remove(e._toBeDeleted,!0).then(function(){return e.cache.add(e._toBeDownloaded),e.cache.download(t)}).then(function(){return e._toBeDeleted=[],e._toBeDownloaded=[],e._updateReady=!0,e.newManifest},function(t){return t&&t.length&&e.cache.remove(t),t})):a.resolve(null)},r.prototype.update=function(t){return this._updateReady?(localStorage.setItem("manifest",JSON.stringify(this.newManifest)),t!==!1&&location.reload(),!0):!1},r.prototype.clear=function(){return localStorage.removeItem("manifest"),this.cache.clear()},r.prototype.reset=function(){return this.clear().then(function(){location.reload()},function(){location.reload()})},t.exports=r},function(t,e,o){function n(t){if(this._fs=t.fs,!this._fs)throw new Error('Missing required option "fs". Add an instance of cordova-promise-fs.');i=this._fs.Promise,this._mirrorMode="hash"!==t.mode,this._retry=t.retry||[500,1500,8e3],this._cacheBuster=!!t.cacheBuster,this._localRoot=t.localRoot||"data","/"!==this._localRoot[this._localRoot.length-1]&&(this._localRoot+="/"),"/"!==this._localRoot[0]&&(this._localRoot="/"+this._localRoot),this._serverRoot=t.serverRoot||"",this._serverRoot&&"/"!==this._serverRoot[this._serverRoot.length-1]&&(this._serverRoot+="/"),"./"===this._serverRoot&&(this._serverRoot=""),this._downloading=[],this._added=[],this._cached={},this.ready=this.list()}var r=o(2),i=null,a="undefined"!=typeof cordova;a||(window.ProgressEvent=function(){}),n.prototype.list=function(){var t=this;return new i(function(e){t._fs.list(t._localRoot,"rfe").then(function(o){t._cached={},o=o.map(function(e){return t._cached[e.fullPath]={toInternalURL:a?e.toInternalURL():e.toURL(),toURL:e.toURL()},e.fullPath}),e(o)},function(){e([])})})},n.prototype.add=function(t){t||(t=[]),"string"==typeof t&&(t=[t]);var e=this;return t.forEach(function(t){t=e.toServerURL(t),-1===e._added.indexOf(t)&&e._added.push(t)}),e.isDirty()},n.prototype.remove=function(t,e){t||(t=[]);var o=[];"string"==typeof t&&(t=[t]);var n=this;return t.forEach(function(t){var e=n._added.indexOf(n.toServerURL(t));e>=0&&n._added.splice(e,1);var r=n.toPath(t);o.push(n._fs.remove(r)),delete n._cached[r]}),e?i.all(o):n.isDirty()},n.prototype.getDownloadQueue=function(){var t=this,e=t._added.filter(function(e){return!t.isCached(e)});return e},n.prototype.getAdded=function(){return this._added},n.prototype.isDirty=function(){return this.getDownloadQueue().length>0},n.prototype.download=function(t){var e=this._fs,o=this;return o.abort(),new i(function(n,r){e.ensure(o._localRoot).then(function(){return o.list()}).then(function(){if(!o.isDirty())return void n(o);var i=o.getDownloadQueue(),a=[],s=o._downloading.length,h=o._downloading.length,c=o._downloading.length+i.length;i.forEach(function(i){var d,u=o.toPath(i);"function"==typeof t&&(d=function(e){e.queueIndex=s,e.queueSize=c,e.url=i,e.path=u,e.percentage=s/c,e.loaded>0&&e.total>0&&s!==c&&(e.percentage+=e.loaded/e.total/c),a.indexOf(i)<0&&(a.push(i),s++),t(e)});var l=function(){h++,h===c&&(o._downloading=[],o.list().then(function(){d&&d(new ProgressEvent),o.isDirty()?r(o.getDownloadQueue()):n(o)},r))},f=i;o._cacheBuster&&(f+="?"+Date.now());var p=e.download(i,u,{retry:o._retry},d);p.then(l,l),o._downloading.push(p)})},r)})},n.prototype.abort=function(){this._downloading.forEach(function(t){t.abort()}),this._downloading=[]},n.prototype.isCached=function(t){return t=this.toPath(t),!!this._cached[t]},n.prototype.clear=function(){return this._cached={},this._fs.removeDir(this._localRoot)},n.prototype.toInternalURL=function(t){return path=this.toPath(t),this._cached[path]?this._cached[path].toInternalURL:this._fs.toInternalURLSync(path)},n.prototype.get=function(t){return path=this.toPath(t),this._cached[path]?this._cached[path].toInternalURL:this.toServerURL(t)},n.prototype.toDataURL=function(t){return this._fs.toDataURL(this.toPath(t))},n.prototype.toURL=function(t){return path=this.toPath(t),this._cached[path]?this._cached[path].toURL:t},n.prototype.toServerURL=function(t){return"/"===t[0]&&(t=t.substr(1)),t.indexOf("://")<0?this._serverRoot+t:t},n.prototype.toPath=function(t){return this._mirrorMode?(t=t||"",len=this._serverRoot.length,t.substr(0,len)!==this._serverRoot?("/"===t[0]&&(t=t.substr(1)),this._localRoot+t):this._localRoot+t.substr(len)):this._localRoot+r(t)+t.substr(t.lastIndexOf("."))},t.exports=n},function(t){function e(t,e){var o,n,r,i,a,s,h,c;for(o=3&t.length,n=t.length-o,r=e,a=3432918353,s=461845907,c=0;n>c;)h=255&t.charCodeAt(c)|(255&t.charCodeAt(++c))<<8|(255&t.charCodeAt(++c))<<16|(255&t.charCodeAt(++c))<<24,++c,h=(65535&h)*a+(((h>>>16)*a&65535)<<16)&4294967295,h=h<<15|h>>>17,h=(65535&h)*s+(((h>>>16)*s&65535)<<16)&4294967295,r^=h,r=r<<13|r>>>19,i=5*(65535&r)+((5*(r>>>16)&65535)<<16)&4294967295,r=(65535&i)+27492+(((i>>>16)+58964&65535)<<16);switch(h=0,o){case 3:h^=(255&t.charCodeAt(c+2))<<16;case 2:h^=(255&t.charCodeAt(c+1))<<8;case 1:h^=255&t.charCodeAt(c),h=(65535&h)*a+(((h>>>16)*a&65535)<<16)&4294967295,h=h<<15|h>>>17,h=(65535&h)*s+(((h>>>16)*s&65535)<<16)&4294967295,r^=h}return r^=t.length,r^=r>>>16,r=2246822507*(65535&r)+((2246822507*(r>>>16)&65535)<<16)&4294967295,r^=r>>>13,r=3266489909*(65535&r)+((3266489909*(r>>>16)&65535)<<16)&4294967295,r^=r>>>16,r>>>0}t.exports=e}]);
var CordovaAppLoader=function(t){function e(n){if(o[n])return o[n].exports;var r=o[n]={exports:{},id:n,loaded:!1};return t[n].call(r.exports,r,r.exports,e),r.loaded=!0,r.exports}var o={};return e.m=t,e.c=o,e.p="",e(0)}([function(t,e,o){function n(t){var e={};return Object.keys(t).forEach(function(o){e[t[o].filename]=t[o]}),e}function r(t){if(!t)throw new Error("CordovaAppLoader has no options!");if(!t.fs)throw new Error('CordovaAppLoader has no "fs" option (cordova-promise-fs)');if(!t.serverRoot)throw new Error('CordovaAppLoader has no "serverRoot" option.');if(!window.pegasus||!window.Manifest)throw new Error("CordovaAppLoader bootstrap.js is missing.");a=t.fs.Promise,this.manifest=window.Manifest,this.newManifest=null,t.serverRoot=t.serverRoot||"",t.serverRoot&&"/"!==t.serverRoot[t.serverRoot.length-1]&&(t.serverRoot+="/"),this.newManifestUrl=t.serverRoot+(t.manifest||"manifest.json"),t.mode&&(t.mode="mirror"),this.cache=new i(t),this._toBeDeleted=[],this._toBeDownloaded=[],this._updateReady=!1,this._checkTimeout=t.checkTimeout||1e4}var i=o(1),a=null;r.prototype.check=function(t){var e=this,o=this.manifest;return new a(function(r,i){function a(t){e.cache.ready.then(function(){if(!t.files)return void i('Downloaded Manifest has no "files" attribute.');var a=n(t.files),s=n(o.files);e._toBeDownloaded=Object.keys(a).filter(function(t){return!s[t]||s[t].version!==a[t].version||!e.cache.isCached(t)}),e.cache.list().then(function(o){e._toBeDeleted=o.map(function(t){return t.substr(e.cache._localRoot.length)}).filter(function(t){return!a[t]}).concat(e._toBeDownloaded),e._toBeDeleted.length>0||e._toBeDownloaded.length>0?(e.newManifest=t,e.newManifest.root=e.cache.toInternalURL("/")+(e.newManifest.root||""),r(!0)):r(!1)},i)},i)}"string"==typeof t&&(e.newManifestUrl=t,t=void 0),"object"==typeof t?a(t):(pegasus(e.newManifestUrl).then(a,i),setTimeout(function(){i(new Error("timeout"))},e._checkTimeout))})},r.prototype.canDownload=function(){return!!this.newManifest&&!this._updateReady},r.prototype.canUpdate=function(){return this._updateReady},r.prototype.download=function(t){var e=this;return e.canDownload()?(localStorage.removeItem("manifest"),this.manifest.files=Manifest.files={},e.cache.remove(e._toBeDeleted,!0).then(function(){return e.cache.add(e._toBeDownloaded),e.cache.download(t)}).then(function(){return e._toBeDeleted=[],e._toBeDownloaded=[],e._updateReady=!0,e.newManifest},function(t){return t&&t.length&&e.cache.remove(t),t})):a.resolve(null)},r.prototype.update=function(t){return this._updateReady?(localStorage.setItem("manifest",JSON.stringify(this.newManifest)),t!==!1&&location.reload(),!0):!1},r.prototype.clear=function(){return localStorage.removeItem("manifest"),this.cache.clear()},r.prototype.reset=function(){return this.clear().then(function(){location.reload()},function(){location.reload()})},t.exports=r},function(t,e,o){function n(t){if(this._fs=t.fs,!this._fs)throw new Error('Missing required option "fs". Add an instance of cordova-promise-fs.');i=this._fs.Promise,this._mirrorMode="hash"!==t.mode,this._retry=t.retry||[500,1500,8e3],this._cacheBuster=!!t.cacheBuster,this._localRoot=t.localRoot||"data","/"!==this._localRoot[this._localRoot.length-1]&&(this._localRoot+="/"),"/"===this._localRoot[0]&&(this._localRoot=this._localRoot.substr(1)),this._serverRoot=t.serverRoot||"",this._serverRoot&&"/"!==this._serverRoot[this._serverRoot.length-1]&&(this._serverRoot+="/"),"./"===this._serverRoot&&(this._serverRoot=""),this._downloading=[],this._added=[],this._cached={},this.ready=this.list()}var r=o(2),i=null,a="undefined"!=typeof cordova;a||(window.ProgressEvent=function(){}),n.prototype.list=function(){var t=this;return new i(function(e){t._fs.list(t._localRoot,"rfe").then(function(o){t._cached={},o=o.map(function(e){return t._cached[e.fullPath]={toInternalURL:a?e.toInternalURL():e.toURL(),toURL:e.toURL()},e.fullPath}),e(o)},function(){e([])})})},n.prototype.add=function(t){t||(t=[]),"string"==typeof t&&(t=[t]);var e=this;return t.forEach(function(t){t=e.toServerURL(t),-1===e._added.indexOf(t)&&e._added.push(t)}),e.isDirty()},n.prototype.remove=function(t,e){t||(t=[]);var o=[];"string"==typeof t&&(t=[t]);var n=this;return t.forEach(function(t){var e=n._added.indexOf(n.toServerURL(t));e>=0&&n._added.splice(e,1);var r=n.toPath(t);o.push(n._fs.remove(r)),delete n._cached[r]}),e?i.all(o):n.isDirty()},n.prototype.getDownloadQueue=function(){var t=this,e=t._added.filter(function(e){return!t.isCached(e)});return e},n.prototype.getAdded=function(){return this._added},n.prototype.isDirty=function(){return this.getDownloadQueue().length>0},n.prototype.download=function(t){var e=this._fs,o=this;return o.abort(),new i(function(n,r){e.ensure(o._localRoot).then(function(){return o.list()}).then(function(){if(!o.isDirty())return void n(o);var i=o.getDownloadQueue(),a=[],s=o._downloading.length,h=o._downloading.length,c=o._downloading.length+i.length;i.forEach(function(i){var d,u=o.toPath(i);"function"==typeof t&&(d=function(e){e.queueIndex=s,e.queueSize=c,e.url=i,e.path=u,e.percentage=s/c,e.loaded>0&&e.total>0&&s!==c&&(e.percentage+=e.loaded/e.total/c),a.indexOf(i)<0&&(a.push(i),s++),t(e)});var l=function(){h++,h===c&&(o._downloading=[],o.list().then(function(){d&&d(new ProgressEvent),o.isDirty()?r(o.getDownloadQueue()):n(o)},r))},f=i;o._cacheBuster&&(f+="?"+Date.now());var p=e.download(i,u,{retry:o._retry},d);p.then(l,l),o._downloading.push(p)})},r)})},n.prototype.abort=function(){this._downloading.forEach(function(t){t.abort()}),this._downloading=[]},n.prototype.isCached=function(t){return t=this.toPath(t),!!this._cached[t]},n.prototype.clear=function(){return this._cached={},this._fs.removeDir(this._localRoot)},n.prototype.toInternalURL=function(t){return path=this.toPath(t),this._cached[path]?this._cached[path].toInternalURL:this._fs.toInternalURLSync(path)},n.prototype.get=function(t){return path=this.toPath(t),this._cached[path]?this._cached[path].toInternalURL:this.toServerURL(t)},n.prototype.toDataURL=function(t){return this._fs.toDataURL(this.toPath(t))},n.prototype.toURL=function(t){return path=this.toPath(t),this._cached[path]?this._cached[path].toURL:t},n.prototype.toServerURL=function(t){return"/"===t[0]&&(t=t.substr(1)),t.indexOf("://")<0?this._serverRoot+t:t},n.prototype.toPath=function(t){return this._mirrorMode?(t=t||"",len=this._serverRoot.length,t.substr(0,len)!==this._serverRoot?("/"===t[0]&&(t=t.substr(1)),this._localRoot+t):this._localRoot+t.substr(len)):this._localRoot+r(t)+t.substr(t.lastIndexOf("."))},t.exports=n},function(t){function e(t,e){var o,n,r,i,a,s,h,c;for(o=3&t.length,n=t.length-o,r=e,a=3432918353,s=461845907,c=0;n>c;)h=255&t.charCodeAt(c)|(255&t.charCodeAt(++c))<<8|(255&t.charCodeAt(++c))<<16|(255&t.charCodeAt(++c))<<24,++c,h=(65535&h)*a+(((h>>>16)*a&65535)<<16)&4294967295,h=h<<15|h>>>17,h=(65535&h)*s+(((h>>>16)*s&65535)<<16)&4294967295,r^=h,r=r<<13|r>>>19,i=5*(65535&r)+((5*(r>>>16)&65535)<<16)&4294967295,r=(65535&i)+27492+(((i>>>16)+58964&65535)<<16);switch(h=0,o){case 3:h^=(255&t.charCodeAt(c+2))<<16;case 2:h^=(255&t.charCodeAt(c+1))<<8;case 1:h^=255&t.charCodeAt(c),h=(65535&h)*a+(((h>>>16)*a&65535)<<16)&4294967295,h=h<<15|h>>>17,h=(65535&h)*s+(((h>>>16)*s&65535)<<16)&4294967295,r^=h}return r^=t.length,r^=r>>>16,r=2246822507*(65535&r)+((2246822507*(r>>>16)&65535)<<16)&4294967295,r^=r>>>13,r=3266489909*(65535&r)+((3266489909*(r>>>16)&65535)<<16)&4294967295,r^=r>>>16,r>>>0}t.exports=e}]);
{
"name": "cordova-app-loader",
"version": "0.6.0",
"version": "0.6.1",
"description": "Cordova App Loader - remote update your cordova app",

@@ -10,6 +10,7 @@ "main": "index.js",

"bootstrap": "cp bootstrap.js www/bootstrap.js",
"autoupdate": "webpack autoupdate.js www/autoupdate.js",
"prepublish": "npm run autoupdate && npm run bootstrap && npm run cordova-promise-fs && npm run cordova-app-loader && npm run copy-to-dist && npm run minify-dist",
"autoupdate": "cp autoupdate.js www/autoupdate.js",
"bundle":" webpack bundle.js dist/cordova-app-loader-complete.js",
"prepublish": "npm run autoupdate && npm run bootstrap && npm run cordova-promise-fs && npm run cordova-app-loader && npm run copy-to-dist && npm run bundle && npm run minify-dist",
"copy-to-dist":"cp www/lib/CordovaAppLoader.js dist/ && cp www/lib/CordovaPromiseFS.js dist/ && cp www/bootstrap.js dist/ && cp www/autoupdate.js dist/",
"minify-dist":" uglifyjs -c -m --screw-ie8 dist/bootstrap.js -o dist/bootstrap.min.js && uglifyjs -c -m --screw-ie8 dist/autoupdate.js -o dist/autoupdate.min.js && uglifyjs -c -m --screw-ie8 dist/CordovaPromiseFS.js -o dist/CordovaPromiseFS.min.js && uglifyjs -c -m --screw-ie8 dist/CordovaAppLoader.js -o dist/CordovaAppLoader.min.js",
"minify-dist":" uglifyjs -c -m --screw-ie8 dist/bootstrap.js -o dist/bootstrap.min.js && uglifyjs -c -m --screw-ie8 dist/autoupdate.js -o dist/autoupdate.min.js && uglifyjs -c -m --screw-ie8 dist/CordovaPromiseFS.js -o dist/CordovaPromiseFS.min.js && uglifyjs -c -m --screw-ie8 dist/CordovaAppLoader.js -o dist/CordovaAppLoader.min.js && uglifyjs -c -m --screw-ie8 dist/cordova-app-loader-complete.js > dist/cordova-app-loader-complete.min.js",
"test": "echo \"Error: no test specified\" && exit 1"

@@ -27,4 +28,4 @@ },

"dependencies": {
"cordova-file-cache": "^0.5.1"
"cordova-file-cache": "^0.6.0"
}
}

@@ -5,7 +5,5 @@ cordova-app-loader

## How it works:
1. Write a **manifest.json** to **bootstrap.js** your app.
2. Build and deploy your app.
2. Write a **manifest.json** to **bootstrap.js** your app.
3. Build and deploy your app.
A little later...

@@ -35,80 +33,23 @@

**Note:** Want to run your own server? Modify `serverRoot` in `www/app.js`!
All code is in the `www` directory. Modify `serverRoot` in `www/app.js` to run your own server.
## Installation
## Quick Start
### Setup Cordova:
Check out [autoupdate.js](https://github.com/markmarijnissen/cordova-app-loader/blob/master/autoupdate.js) - it automatically updates when you open or resume the app.
```bash
cordova platform add ios@3.7.0
cordova plugin add org.apache.cordova.file
cordova plugin add org.apache.cordova.file-transfer
```
Automatic updates have a few downsides:
**IMPORTANT:** For iOS, use Cordova 3.7.0 or higher (due to a [bug](https://github.com/AppGyver/steroids/issues/534) that affects requestFileSystem).
* Downloading files in the background can slow down performance (sluggish UI).
* Automatically updating can interrupt the user.
### Get javascript:
### Step by step instruction:
You need:
* **bootstrap.js** ([github](https://github.com/markmarijnissen/cordova-app-loader/), [file](https://raw.githubusercontent.com/markmarijnissen/cordova-app-loader/master/bootstrap.js)): reads the manifest.json to start your app.
* **cordova-app-loader** ([github](https://github.com/markmarijnissen/cordova-app-loader/), [file](https://raw.githubusercontent.com/markmarijnissen/cordova-app-loader/master/www/lib/CordovaAppLoader.js)): to check,download and update a **manifest.json**
* **cordova-promise-fs** ([github](https://github.com/markmarijnissen/cordova-promise-fs), [file](https://github.com/markmarijnissen/cordova-app-loader/blob/master/www/lib/CordovaPromiseFS.js)): to deal with the FileSystem
* a **Promise** libary such as bluebird ([github](https://github.com/petkaantonov/bluebird), [file](https://raw.githubusercontent.com/markmarijnissen/cordova-app-loader/master/www/lib/bluebird.js)) or promiscuous ([github](https://github.com/RubenVerborgh/promiscuous),[file](https://raw.githubusercontent.com/RubenVerborgh/promiscuous/master/promiscuous.js))
CordovaAppLoader includes [cordova-file-cache](https://github.com/markmarijnissen/cordova-file-cache) to download and cache the files.
```bash
bower install cordova-app-loader cordova-promise-fs bluebird
npm install cordova-app-loader cordova-promise-fs bluebird
```
### Getting started
1. Write a **manifest.json** (see below)
2. Include the **bootstrap.js** script to load your CSS and JS from the **manifest.json**
3. Use **CordovaAppLoader** to `check()`, `download()` and `apply()` updates:
```javascript
// When using NPM, require these first.
// When using the ready-made files, these are available as global variables.
var CordovaPromiseFS = require('cordova-promise-fs');
var CordovaAppLoader = require('cordova-app-loader');
var Promise = require('bluebird');
// Initialize a FileSystem
var fs = new CordovaPromiseFS({
Promise: Promise
});
// Initialize a CordovaAppLoader
var loader = new CordovaAppLoader({
fs: fs,
serverRoot: 'http://data.madebymark.nl/cordova-app-loader/'
});
// Write your own "check", "download" and "update" logic:
loader.check()
.then(function(){
return loader.download();
}).then(function(){
return loader.update();
})
```
See [an example](https://github.com/markmarijnissen/cordova-app-loader/blob/master/autoupdate.js).
### Quickstart
If you don't need full control, you can use a ready-made solution: [autoupdate.js](https://raw.githubusercontent.com/markmarijnissen/cordova-app-loader/master/www/autoupdate.js)
[autoupdate.js](https://raw.githubusercontent.com/markmarijnissen/cordova-app-loader/master/www/autoupdate.js) includes everything except the **bootloader.js** ([a Promise library](https://raw.githubusercontent.com/RubenVerborgh/promiscuous/master/promiscuous.js), [CordovaPromiseFS.js](https://github.com/markmarijnissen/cordova-app-loader/blob/master/www/lib/CordovaPromiseFS.js) and [CordovaAppLoader.js](https://raw.githubusercontent.com/markmarijnissen/cordova-app-loader/master/www/lib/CordovaAppLoader.js)).
Autoupdate initializes everything as described above, and automatically updates your app [when you open or resume it](https://github.com/markmarijnissen/cordova-app-loader/blob/master/autoupdate.js#L58).
#### Steps
1. Download [index.html](https://raw.githubusercontent.com/markmarijnissen/cordova-app-loader/master/www/autoupdate.html), [bootstrap.js](https://raw.githubusercontent.com/markmarijnissen/cordova-app-loader/master/bootstrap.js) and [autoupdate.js](https://raw.githubusercontent.com/markmarijnissen/cordova-app-loader/master/www/autoupdate.js) to your `www` directory.
2. Write a **manifest.json** (see below). Include `autoupdate.js` in it.
3. Make sure you set the correct options in `index.html`:
1. Setup Cordova (see below)
1. Download to your `www` directory:
* [index.html](https://raw.githubusercontent.com/markmarijnissen/cordova-app-loader/master/www/autoupdate.html) (Cordova entry point)
* [bootstrap.js](https://raw.githubusercontent.com/markmarijnissen/cordova-app-loader/master/dist/bootstrap.js) (Dynamically loads JS/CSS)
* [cordova-app-loader-complete.js](https://raw.githubusercontent.com/markmarijnissen/cordova-app-loader/master/dist/cordova-app-loader-complete.js) (Complete CordovaAppLoader library with dependencies)
* [autoupdate.js](https://raw.githubusercontent.com/markmarijnissen/cordova-app-loader/master/dist/autoupdate.js) (Example implementation)
2. Write a **manifest.json** (see below). Include `autoupdate.js` and `cordova-app-loader-complete.js`.
3. Set the correct server in `index.html`:
```html

@@ -124,35 +65,27 @@ <script

5. Launch your app.
Now you can remote update your app:
6. Upload a new **manifest.json** (+ files) to your server.
7. Reopen your app to download and apply the update.
This implementation is **not** recommended because:
## The Manifest
* Downloading files in the background can slow down performance (sluggish UI).
* The update (reload) can interrupt an important user action.
Before you start, you need to write a **manifest.json** to describe:
**Note:** You cannot update `bootstrap.js` - therefore `autoupdate.js` is a seperate file. (So you can update `autoupdate` itself).
* Which files to download,
* Which JS/CSS to load during bootstrap.
## Manifest.json
### Writing manifest.json
Describe which files to download and which files to load during bootstrap.
```javascript
{
"files": { // these files are downloaded (only when "version" is different from current version!)
"jquery": {
"version": "afb90752e0a90c24b7f724faca86c5f3d15d1178",
"filename": "lib/jquery.min.js"
"files": { // these files are downloaded
"cordova-app-loader-complete": {
"version": "76f1eecd3887e69d7b08c60be4f14f90069ca8b8",
"filename": "cordova-app-loader-complete.js"
},
"bluebird": {
"version": "f37ff9832449594d1cefe98260cae9fdc13e0749",
"filename": "lib/bluebird.js"
},
"CordovaPromiseFS": {
"version": "635bd29385fe6664b1cf86dc16fb3d801aa9461a",
"filename": "lib/CordovaPromiseFS.js"
},
"CordovaAppLoader": {
"autoupdate": {
"version": "76f1eecd3887e69d7b08c60be4f14f90069ca8b8",
"filename": "lib/CordovaAppLoader.js"
"filename": "autoupdate.js"
},

@@ -173,10 +106,8 @@ "template": {

"load": [ // these files are loaded in your index.html
"lib/jquery.min.js",
"lib/bluebird.js",
"lib/CordovaPromiseFS.js",
"lib/CordovaAppLoader.js",
"cordova-app-loader-complete.js",
"autoupdate.js",
"app.js",
"style.css"
],
"root":"./", // root location of files to be loaded. Defaults to current location: `./`
"root":"./", // root location to load files from.
}

@@ -195,9 +126,58 @@ ```

Or check out [this gruntfile](https://gist.github.com/lylepratt/d8bf84b3b7d6932e3549).
Thre is also [a Gruntfile](https://gist.github.com/lylepratt/d8bf84b3b7d6932e3549) available.
## Usage
## Installation
### Setup Cordova
```bash
cordova platform add ios@3.7.0
cordova plugin add org.apache.cordova.file
cordova plugin add org.apache.cordova.file-transfer
```
**IMPORTANT:** For iOS, use Cordova 3.7.0 or higher (due to a [bug](https://github.com/AppGyver/steroids/issues/534) that affects requestFileSystem).
###Download and include bootstrap.js
You need **bootstrap.js** ([github](https://github.com/markmarijnissen/cordova-app-loader/), [file](https://raw.githubusercontent.com/markmarijnissen/cordova-app-loader/master/bootstrap.js)) to read the **manifest.json** to launch your app.
Add **bootstrap.js** to your [index.html](https://raw.githubusercontent.com/markmarijnissen/cordova-app-loader/master/www/index.html).
### Download and include CordovaAppLoader (and dependencies)
**Option 1: Download all dependencies as a single pre-build file (easy)**
Download cordova-app-loader-complete.js ([github](https://github.com/markmarijnissen/cordova-app-loader/blob/master/dist/cordova-app-loader-complete.js), [download](https://raw.githubusercontent.com/markmarijnissen/cordova-app-loader/master/dist/cordova-app-loader-complete.js), [minified](https://raw.githubusercontent.com/markmarijnissen/cordova-app-loader/master/dist/cordova-app-loader-complete.min.js)). This build uses promiscuous ([github](https://github.com/RubenVerborgh/promiscuous),[download](https://raw.githubusercontent.com/RubenVerborgh/promiscuous/master/promiscuous.js)) as Promise library.
**Option 2: Download pre-build files for every module (customizable)**
If you want to use your own Promise library, you have to load every module individually:
* **cordova-app-loader** ([github](https://github.com/markmarijnissen/cordova-app-loader/), [download](https://raw.githubusercontent.com/markmarijnissen/cordova-app-loader/master/www/lib/CordovaAppLoader.js)) - checks, downloads and updates using **manifest.json**
* **cordova-promise-fs** ([github](https://github.com/markmarijnissen/cordova-promise-fs), [download](https://github.com/markmarijnissen/cordova-app-loader/blob/master/www/lib/CordovaPromiseFS.js)) - deals with the Cordova File API
* a **Promise** libary such as bluebird ([github](https://github.com/petkaantonov/bluebird), [download](https://raw.githubusercontent.com/markmarijnissen/cordova-app-loader/master/www/lib/bluebird.js)) or promiscuous ([github](https://github.com/RubenVerborgh/promiscuous),[file](https://raw.githubusercontent.com/RubenVerborgh/promiscuous/master/promiscuous.js))
**Option 3: Use Bower to fetch pre-build modules:**
```bash
bower install cordova-app-loader
bower install cordova-promise-fs
bower install bluebird # or whatever Promise library you want
```
**Option 4: Use NPM to fetch CommonJS modules:**
```bash
npm install cordova-app-loader
npm install cordova-promise-fs
npm install bluebird # or whatever Promise library you want
```
## Usage / API
### Overview
1. Add **bootstrap.js** script to your **index.html**
1. Bootstrap your app.
2. Instantiate a `new CordovaAppLoader()`

@@ -208,6 +188,8 @@ 3. `check()` for updates

### Step 1: Add [bootstrap.js](https://raw.githubusercontent.com/markmarijnissen/cordova-app-loader/master/www/bootstrap.js) to your [index.html](https://raw.githubusercontent.com/markmarijnissen/cordova-app-loader/master/www/index.html)
See [autoupdate.js](https://github.com/markmarijnissen/cordova-app-loader/blob/master/autoupdate.js) for an example of `check()`, `download()` and `update()`.
Retrieves manifest.json and dynamically inserts JS/CSS to the current page.
### Step 1: Bootstrap your app.
Add [bootstrap.js](https://raw.githubusercontent.com/markmarijnissen/cordova-app-loader/master/www/bootstrap.js) to your [index.html](https://raw.githubusercontent.com/markmarijnissen/cordova-app-loader/master/www/index.html). This retrieves **manifest.json** and dynamically inserts JS/CSS to the current page.
```html

@@ -350,15 +332,2 @@ <script type="text/javascript" timeout="5000" manifest="manifest.json" src="bootstrap.js"></script>

### Four files for flexibility
Yes, you need to include four files - but this is to create flexibility.
* [bootstrap.js](https://raw.githubusercontent.com/markmarijnissen/cordova-app-loader/master/bootstrap.js): This file cannot be updated, so it needs to be a minimal script/css loader.
* [A Promise library](https://raw.githubusercontent.com/RubenVerborgh/promiscuous/master/promiscuous.js): I don't want to enforce a particular Promise library.
* [CordovaPromiseFS.js](https://github.com/markmarijnissen/cordova-app-loader/blob/master/www/lib/CordovaPromiseFS.js): I want to reuse a single `CordovaPromiseFS` instance for the entire app.
* [CordovaAppLoader.js](https://raw.githubusercontent.com/markmarijnissen/cordova-app-loader/master/www/lib/CordovaAppLoader.js): `download()` can slow down performance and `update()` can interrupt the user - you need to decide yourself you want to handle this.
If you don't care about this, you can use [autoupdate.js](https://raw.githubusercontent.com/markmarijnissen/cordova-app-loader/master/www/autoupdate.js) as describe in QuickStart above.
**TODO:** Include `CordovaPromiseFS.js` in the `CordovaAppLoader.js` build, just like the CordovaFileCache. I need to make sure CordovaPromiseFS and CordovaFileCache are globally available then.
### More to be considered?

@@ -371,3 +340,2 @@

* Create a demo for **autoupdate.js**
* Include CordovaPromiseFS in the CordovaAppLoader build. Create a default instance if no CordovaPromiseFS instance is passed as option.
* Write automatic tests? (Is this possible?)

@@ -379,2 +347,6 @@ * Document and double-check all the urls and paths. (Especially: Do `serverUrl` and `Manifest.root` work together as expected?)

### 0.6.1 (19/11/2014)
* Updated file-cache dependency for android bugfix
### 0.6.0 (19/11/2014)

@@ -381,0 +353,0 @@

@@ -1,1190 +0,64 @@

/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {
(function(){
// Check for Cordova
var isCordova = typeof cordova !== 'undefined',
// CordovaPromiseFS
fs,
// CordovaFileLoader
loader,
// script-tag...
script,
// ...that contains the serverRoot
serverRoot;
var CordovaAppLoader = __webpack_require__(1);
var CordovaPromiseFS = __webpack_require__(2);
var Promise = __webpack_require__(3);
window.setImmediate = window.setTimeout;
// Get serverRoot from script tag.
script = document.querySelector('script[server]');
if(script) serverRoot= script.getAttribute('server');
if(!serverRoot) {
throw new Error('Add a "server" attribute to the bootstrap.js script!');
}
// Helper variable: Chrome should use temporary storage.
var isCordova = typeof cordova !== 'undefined',
fs,
loader,
script,
serverUrl;
// Initialize filesystem and loader
fs = new CordovaPromiseFS({
persistent: isCordova, // Chrome should use temporary storage.
Promise: Promise
});
// Get SERVER_URL from script tag.
script = document.querySelector('script[server]');
if(script){
serverUrl= script.getAttribute('server');
}
if(!serverUrl) {
throw new Error('Add a "server" attribute to the autoupdate.js script!');
}
loader = new CordovaAppLoader({
fs: fs,
localRoot: 'app',
serverRoot: serverRoot,
mode: 'mirror',
cacheBuster: true
});
// Initialize filesystem and loader
fs = new CordovaPromiseFS({
persistent: isCordova,
Promise: Promise
});
// Check > Download > Update
function check(){
loader.check()
.then(function(){
return loader.download();
})
.then(function(){
return loader.update();
},function(err){
console.error('Auto-update error:',err);
});
}
loader = new CordovaAppLoader({
fs: fs,
localRoot: 'app',
serverRoot: serverUrl,
mode: 'mirror',
cacheBuster: true
});
// Couple events:
// Check > Download > Update
function check(){
loader.check()
.then(function(){
return loader.download();
})
.then(function(){
return loader.update();
},function(err){
console.error('Auto-update error:',err);
});
}
// 1. On launch
check();
// Couple events:
// 2. Cordova: On resume
fs.deviceready.then(function(){
document.addEventListener('resume',check);
});
// On launch
check();
// Cordova: On resume
fs.deviceready.then(function(){
document.addEventListener('resume',check);
});
// Chrome: On page becomes visible again
function handleVisibilityChange() {
if (!document.webkitHidden) {
check();
}
}
document.addEventListener("webkitvisibilitychange", handleVisibilityChange, false);
/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {
var CordovaFileCache = __webpack_require__(4);
var Promise = null;
function createFilemap(files){
var result = {};
Object.keys(files).forEach(function(key){
result[files[key].filename] = files[key];
});
return result;
}
function AppLoader(options){
if(!options) throw new Error('CordovaAppLoader has no options!');
if(!options.fs) throw new Error('CordovaAppLoader has no "fs" option (cordova-promise-fs)');
if(!options.serverRoot) throw new Error('CordovaAppLoader has no "serverRoot" option.');
if(!window.pegasus || !window.Manifest) throw new Error('CordovaAppLoader bootstrap.js is missing.');
Promise = options.fs.Promise;
// initialize variables
this.manifest = window.Manifest;
this.newManifest = null;
// normalize serverRoot and set remote manifest url
options.serverRoot = options.serverRoot || '';
if(!!options.serverRoot && options.serverRoot[options.serverRoot.length-1] !== '/') options.serverRoot += '/';
this.newManifestUrl = options.serverRoot + (options.manifest || 'manifest.json');
// initialize a file cache
if(options.mode) options.mode = 'mirror';
this.cache = new CordovaFileCache(options);
// private stuff
this._toBeDeleted = [];
this._toBeDownloaded = [];
this._updateReady = false;
this._checkTimeout = options.checkTimeout || 10000;
}
AppLoader.prototype.check = function(newManifest){
var self = this, manifest = this.manifest;
return new Promise(function(resolve,reject){
if(typeof newManifest === "string") {
self.newManifestUrl = newManifest;
newManifest = undefined;
}
function checkManifest(newManifest){
// make sure cache is ready for the DIFF operations!
self.cache.ready.then(function(){
if(!newManifest.files){
reject('Downloaded Manifest has no "files" attribute.');
return;
}
var newFiles = createFilemap(newManifest.files);
var oldFiles = createFilemap(manifest.files);
// Create the diff
self._toBeDownloaded = Object.keys(newFiles)
.filter(function(file){
return !oldFiles[file]
|| oldFiles[file].version !== newFiles[file].version
|| !self.cache.isCached(file);
});
self.cache.list().then(function(files){
self._toBeDeleted = files
.map(function(file){
return file.substr(self.cache._localRoot.length);
})
.filter(function(file){
return !newFiles[file];
})
.concat(self._toBeDownloaded);
if(self._toBeDeleted.length > 0 || self._toBeDownloaded.length > 0){
// Save the new Manifest
self.newManifest = newManifest;
self.newManifest.root = self.cache.toInternalURL('/') + (self.newManifest.root || '');
resolve(true);
} else {
resolve(false);
}
},reject);
},reject);
}
if(typeof newManifest === "object") {
checkManifest(newManifest);
} else {
pegasus(self.newManifestUrl).then(checkManifest,reject);
setTimeout(function(){reject(new Error('timeout'));},self._checkTimeout);
}
});
};
AppLoader.prototype.canDownload = function(){
return !!this.newManifest && !this._updateReady;
};
AppLoader.prototype.canUpdate = function(){
return this._updateReady;
};
AppLoader.prototype.download = function(onprogress){
var self = this;
if(!self.canDownload()) {
return Promise.resolve(null);
}
// we will delete files, which will invalidate the current manifest...
localStorage.removeItem('manifest');
this.manifest.files = Manifest.files = {};
return self.cache.remove(self._toBeDeleted,true)
.then(function(){
self.cache.add(self._toBeDownloaded);
return self.cache.download(onprogress);
}).then(function(){
self._toBeDeleted = [];
self._toBeDownloaded = [];
self._updateReady = true;
return self.newManifest;
},function(files){
// on download error, remove files...
if(!!files && files.length){
self.cache.remove(files);
}
return files;
});
};
AppLoader.prototype.update = function(reload){
if(this._updateReady) {
// update manifest
localStorage.setItem('manifest',JSON.stringify(this.newManifest));
if(reload !== false) location.reload();
return true;
}
return false;
};
AppLoader.prototype.clear = function(){
localStorage.removeItem('manifest');
return this.cache.clear();
};
AppLoader.prototype.reset = function(){
return this.clear().then(function(){
location.reload();
},function(){
location.reload();
});
};
module.exports = AppLoader;
/***/ },
/* 2 */
/***/ function(module, exports, __webpack_require__) {
/**
* Static Private functions
*/
/* createDir, recursively */
function __createDir(rootDirEntry, folders, success,error) {
rootDirEntry.getDirectory(folders[0], {create: true}, function(dirEntry) {
// Recursively add the new subfolder (if we still have another to create).
if (folders.length > 1) {
__createDir(dirEntry, folders.slice(1),success,error);
} else {
success(dirEntry);
}
}, error);
}
function dirname(str) {
var parts = str.split('/');
if(parts.length > 1) {
parts.splice(parts.length-1,1);
return parts.join('/');
} else {
return '';
}
}
function filename(str) {
var parts = str.split('/');
return parts[parts.length-1];
}
var transferQueue = [], // queued fileTransfers
inprogress = 0; // currently active filetransfers
/**
* Factory function: Create a single instance (based on single FileSystem)
*/
module.exports = function(options){
/* Promise implementation */
var Promise = options.Promise || window.Promise;
if(!Promise) { throw new Error("No Promise library given in options.Promise"); }
/* default options */
this.options = options = options || {};
options.persistent = options.persistent !== undefined? options.persistent: true;
options.storageSize = options.storageSize || 20*1024*1024;
options.concurrency = options.concurrency || 3;
options.retry = options.retry || [];
/* Cordova deviceready promise */
var deviceready, isCordova = typeof cordova !== 'undefined';
if(isCordova){
deviceready = new Promise(function(resolve,reject){
document.addEventListener("deviceready", resolve, false);
setTimeout(function(){ reject(new Error('deviceready has not fired after 5 seconds.')); },5100);
});
} else {
/* FileTransfer implementation for Chrome */
deviceready = Promise.resolve();
if(typeof webkitRequestFileSystem !== 'undefined'){
window.requestFileSystem = webkitRequestFileSystem;
window.FileTransfer = function FileTransfer(){};
FileTransfer.prototype.download = function download(url,file,win,fail) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.onreadystatechange = function(onSuccess, onError, cb) {
if (xhr.readyState == 4) {
if(xhr.status === 200){
write(file,xhr.responseText).then(win,fail);
} else {
fail(xhr.status);
}
}
};
xhr.send();
return xhr;
};
} else {
window.requestFileSystem = function(x,y,z,fail){
fail(new Error('requestFileSystem not supported!'));
};
}
}
/* the filesystem! */
var fs = new Promise(function(resolve,reject){
deviceready.then(function(){
window.requestFileSystem(options.persistent? 1: 0, options.storageSize, resolve, reject);
setTimeout(function(){ reject(new Error('Could not retrieve FileSystem after 5 seconds.')); },5100);
},reject);
});
/* debug */
fs.then(function(fs){
window.__fs = fs;
},function(err){
console.error('Could not get Cordova FileSystem:',err);
});
function create(path){
return ensure(dirname(path)).then(function(){
return file(path,{create:true});
});
}
/* ensure directory exists */
function ensure(folders) {
return new Promise(function(resolve,reject){
return fs.then(function(fs){
if(!folders) {
resolve(fs.root);
} else {
folders = folders.split('/').filter(function(folder) {
return folder && folder.length > 0 && folder[0] !== '.';
});
__createDir(fs.root,folders,resolve,reject);
}
},reject);
});
}
/* does file exist? If so, resolve with fileEntry, if not, resolve with false. */
function exists(path){
return new Promise(function(resolve,reject){
file(path).then(
function(fileEntry){
resolve(fileEntry);
},
function(err){
if(err.code === 1) {
resolve(false);
} else {
reject(err);
}
}
);
});
}
/* convert path to URL to be used in JS/CSS/HTML */
function toURL(path) {
return file(path).then(function(fileEntry) {
return fileEntry.toURL();
});
}
/* convert path to URL to be used in JS/CSS/HTML */
var toInternalURL,toInternalURLSync;
if(isCordova) {
/* synchronous helper to get internal URL. */
toInternalURLSync = function(path){
if(path[0] !== '/') path = '/' + path;
return 'cdvfile://localhost/'+(options.persistent? 'persistent':'temporary') + path;
};
toInternalURL = function(path) {
return file(path).then(function(fileEntry) {
return fileEntry.toInternalURL();
});
};
} else {
/* synchronous helper to get internal URL. */
toInternalURLSync = function(path){
if(path[0] !== '/') path = '/' + path;
return 'filesystem:'+location.origin+(options.persistent? '/persistent':'/temporary') + path;
};
toInternalURL = function(path) {
return file(path).then(function(fileEntry) {
return fileEntry.toURL();
});
};
}
/* convert path to base64 date URI */
function toDataURL(path) {
return read(path,'readAsDataURL');
}
/* get file file */
function file(path,options){
options = options || {};
return new Promise(function(resolve,reject){
return fs.then(function(fs){
fs.root.getFile(path,options,resolve,reject);
},reject);
});
}
/* get directory entry */
function dir(path,options){
options = options || {};
return new Promise(function(resolve,reject){
return fs.then(function(fs){
if(!path || path === '/') {
resolve(fs.root);
} else {
fs.root.getDirectory(path,options,resolve,reject);
}
},reject);
});
}
/* return contents of a file */
function read(path,method) {
method = method || 'readAsText';
return file(path).then(function(fileEntry) {
return new Promise(function(resolve,reject){
fileEntry.file(function(file){
var reader = new FileReader();
reader.onloadend = function(){
resolve(this.result);
};
reader[method](file);
},reject);
});
});
}
function readJSON(path){
return read(path).then(JSON.parse);
}
/* write contents to a file */
function write(path,blob,mimeType) {
return ensure(dirname(path))
.then(function() { return file(path,{create:true}); })
.then(function(fileEntry) {
return new Promise(function(resolve,reject){
fileEntry.createWriter(function(writer){
writer.onwriteend = resolve;
writer.onerror = reject;
if(typeof blob === 'string') {
blob = new Blob([blob],{type: mimeType || 'text/plain'});
} else if(blob instanceof Blob !== true){
blob = new Blob([JSON.stringify(blob,null,4)],{type: mimeType || 'application/json'});
}
writer.write(blob);
},reject);
});
});
}
/* move a file */
function move(src,dest) {
return ensure(dirname(dest))
.then(function(dir) {
return file(src).then(function(fileEntry){
return new Promise(function(resolve,reject){
fileEntry.moveTo(dir,filename(dest),resolve,reject);
});
});
});
}
/* copy a file */
function copy(src,dest) {
return ensure(dirname(dest))
.then(function(dir) {
return file(src).then(function(fileEntry){
return new Promise(function(resolve,reject){
fileEntry.copyTo(dir,filename(dest),resolve,reject);
});
});
});
}
/* delete a file */
function remove(path,mustExist) {
var method = mustExist? file:exists;
return new Promise(function(resolve,reject){
method(path).then(function(fileEntry){
if(fileEntry !== false) {
fileEntry.remove(resolve,reject);
} else {
resolve();
}
},reject);
});
}
/* delete a directory */
function removeDir(path) {
return dir(path).then(function(dirEntry){
return new Promise(function(resolve,reject) {
dirEntry.removeRecursively(resolve,reject);
});
});
}
/* list contents of a directory */
function list(path,mode) {
mode = mode || '';
var recursive = mode.indexOf('r') > -1;
var getAsEntries = mode.indexOf('e') > -1;
var onlyFiles = mode.indexOf('f') > -1;
var onlyDirs = mode.indexOf('d') > -1;
if(onlyFiles && onlyDirs) {
onlyFiles = false;
onlyDirs = false;
}
return new Promise(function(resolve,reject){
return dir(path).then(function(dirEntry){
var dirReader = dirEntry.createReader();
dirReader.readEntries(function(entries) {
var promises = [Promise.resolve(entries)];
if(recursive) {
entries
.filter(function(entry){return entry.isDirectory; })
.forEach(function(entry){
promises.push(list(entry.fullPath,'re'));
});
}
Promise.all(promises).then(function(values){
var entries = [];
entries = entries.concat.apply(entries,values);
if(onlyFiles) entries = entries.filter(function(entry) { return entry.isFile; });
if(onlyDirs) entries = entries.filter(function(entry) { return entry.isDirectory; });
if(!getAsEntries) entries = entries.map(function(entry) { return entry.fullPath; });
resolve(entries);
},reject);
}, reject);
},reject);
});
}
// Whenever we want to start a transfer, we call popTransferQueue
function popTransferQueue(){
// while we are not at max concurrency
while(transferQueue.length > 0 && inprogress < options.concurrency){
// increment activity counter
inprogress++;
// fetch filetranfer, method-type (isDownload) and arguments
var args = transferQueue.pop();
var ft = args.shift();
var isDownload = args.shift();
var serverUrl = args.shift();
var localPath = args.shift();
var win = args.shift();
var fail = args.shift();
var trustAllHosts = args.shift();
var transferOptions = args.shift();
if(ft._aborted) {
inprogress--;
} else if(isDownload){
ft.download.call(ft,serverUrl,localPath,win,fail,trustAllHosts,transferOptions);
if(ft.onprogress) ft.onprogress(new ProgressEvent());
} else {
ft.upload.call(ft,localPath,serverUrl,win,fail,transferOptions,trustAllHosts);
}
}
// if we are at max concurrency, popTransferQueue() will be called whenever
// the transfer is ready and there is space avaialable.
}
// Promise callback to check if there are any more queued transfers
function nextTransfer(result){
inprogress--; // decrement counter to free up one space to start transfers again!
popTransferQueue(); // check if there are any queued transfers
return result;
}
function filetransfer(isDownload,serverUrl,localPath,transferOptions,onprogress){
if(typeof transferOptions === 'function') {
onprogress = transferOptions;
transferOptions = {};
}
serverUrl = encodeURI(serverUrl);
if(isCordova) localPath = toInternalURLSync(localPath);
transferOptions = transferOptions || {};
if(!transferOptions.retry || !transferOptions.retry.length) {
transferOptions.retry = options.retry;
}
transferOptions.retry = transferOptions.retry.concat();
var ft = new FileTransfer();
if(typeof onprogress === 'function') ft.onprogress = onprogress;
var promise = new Promise(function(resolve,reject){
var attempt = function(err){
if(transferOptions.retry.length === 0) {
reject(err);
} else {
transferQueue.unshift([ft,isDownload,serverUrl,localPath,resolve,attempt,transferOptions.trustAllHosts || false,transferOptions]);
var timeout = transferOptions.retry.shift();
if(timeout > 0) {
setTimeout(nextTransfer,timeout);
} else {
nextTransfer();
}
}
};
transferOptions.retry.unshift(0);
inprogress++;
attempt();
});
promise.then(nextTransfer,nextTransfer);
promise.progress = function(onprogress){
ft.onprogress = onprogress;
return promise;
};
promise.abort = function(){
ft._aborted = true;
ft.abort();
return promise;
};
return promise;
}
function download(url,dest,options,onprogress){
return filetransfer(true,url,dest,options,onprogress);
}
function upload(source,dest,options,onprogress){
return filetransfer(false,dest,source,options,onprogress);
}
return {
fs: fs,
file: file,
filename: filename,
dir: dir,
dirname: dirname,
create:create,
read: read,
readJSON: readJSON,
write: write,
move: move,
copy: copy,
remove: remove,
removeDir: removeDir,
list: list,
ensure: ensure,
exists: exists,
download: download,
upload: upload,
toURL:toURL,
isCordova:isCordova,
toInternalURLSync: toInternalURLSync,
toInternalURL:toInternalURL,
toDataURL:toDataURL,
deviceready: deviceready,
options: options,
Promise: Promise
};
};
/***/ },
/* 3 */
/***/ function(module, exports, __webpack_require__) {
/**@license MIT-promiscuous-©Ruben Verborgh*/
(function (func, obj) {
// Type checking utility function
function is(type, item) { return (typeof item)[0] == type; }
// Creates a promise, calling callback(resolve, reject), ignoring other parameters.
function Promise(callback, handler) {
// The `handler` variable points to the function that will
// 1) handle a .then(resolved, rejected) call
// 2) handle a resolve or reject call (if the first argument === `is`)
// Before 2), `handler` holds a queue of callbacks.
// After 2), `handler` is a finalized .then handler.
handler = function pendingHandler(resolved, rejected, value, queue, then, i) {
queue = pendingHandler.q;
// Case 1) handle a .then(resolved, rejected) call
if (resolved != is) {
return Promise(function (resolve, reject) {
queue.push({ p: this, r: resolve, j: reject, 1: resolved, 0: rejected });
});
}
// Case 2) handle a resolve or reject call
// (`resolved` === `is` acts as a sentinel)
// The actual function signature is
// .re[ject|solve](<is>, success, value)
// Check if the value is a promise and try to obtain its `then` method
if (value && (is(func, value) | is(obj, value))) {
try { then = value.then; }
catch (reason) { rejected = 0; value = reason; }
}
// If the value is a promise, take over its state
if (is(func, then)) {
function valueHandler(resolved) {
return function (value) { then && (then = 0, pendingHandler(is, resolved, value)); };
}
try { then.call(value, valueHandler(1), rejected = valueHandler(0)); }
catch (reason) { rejected(reason); }
}
// The value is not a promise; handle resolve/reject
else {
// Replace this handler with a finalized resolved/rejected handler
handler = function (Resolved, Rejected) {
// If the Resolved or Rejected parameter is not a function,
// return the original promise (now stored in the `callback` variable)
if (!is(func, (Resolved = rejected ? Resolved : Rejected)))
return callback;
// Otherwise, return a finalized promise, transforming the value with the function
return Promise(function (resolve, reject) { finalize(this, resolve, reject, value, Resolved); });
};
// Resolve/reject pending callbacks
i = 0;
while (i < queue.length) {
then = queue[i++];
// If no callback, just resolve/reject the promise
if (!is(func, resolved = then[rejected]))
(rejected ? then.r : then.j)(value);
// Otherwise, resolve/reject the promise with the result of the callback
else
finalize(then.p, then.r, then.j, value, resolved);
}
}
};
// The queue of pending callbacks; garbage-collected when handler is resolved/rejected
handler.q = [];
// Create and return the promise (reusing the callback variable)
callback.call(callback = { then: function (resolved, rejected) { return handler(resolved, rejected); },
catch: function (rejected) { return handler(0, rejected); } },
function (value) { handler(is, 1, value); },
function (reason) { handler(is, 0, reason); });
return callback;
}
// Finalizes the promise by resolving/rejecting it with the transformed value
function finalize(promise, resolve, reject, value, transform) {
setImmediate(function () {
try {
// Transform the value through and check whether it's a promise
value = transform(value);
transform = value && (is(obj, value) | is(func, value)) && value.then;
// Return the result if it's not a promise
if (!is(func, transform))
resolve(value);
// If it's a promise, make sure it's not circular
else if (value == promise)
reject(TypeError());
// Take over the promise's state
else
transform.call(value, resolve, reject);
}
catch (error) { reject(error); }
});
}
// Export the main module
module.exports = Promise;
// Creates a resolved promise
Promise.resolve = ResolvedPromise;
function ResolvedPromise(value) { return Promise(function (resolve) { resolve(value); }); }
// Creates a rejected promise
Promise.reject = function (reason) { return Promise(function (resolve, reject) { reject(reason); }); };
// Transforms an array of promises into a promise for an array
Promise.all = function (promises) {
return Promise(function (resolve, reject, count, values) {
// Array of collected values
values = [];
// Resolve immediately if there are no promises
count = promises.length || resolve(values);
// Transform all elements (`map` is shorter than `forEach`)
promises.map(function (promise, index) {
ResolvedPromise(promise).then(
// Store the value and resolve if it was the last
function (value) {
values[index] = value;
--count || resolve(values);
},
// Reject if one element fails
reject);
});
});
};
})('f', 'o');
/***/ },
/* 4 */
/***/ function(module, exports, __webpack_require__) {
var hash = __webpack_require__(5);
var Promise = null;
var isCordova = typeof cordova !== 'undefined';
if(!isCordova) {
window.ProgressEvent = function ProgressEvent(){}
}
/* Cordova File Cache x */
function FileCache(options){
// cordova-promise-fs
this._fs = options.fs;
if(!this._fs) {
throw new Error('Missing required option "fs". Add an instance of cordova-promise-fs.');
}
// Use Promises from fs.
Promise = this._fs.Promise;
// 'mirror' mirrors files structure from "serverRoot" to "localRoot"
// 'hash' creates a 1-deep filestructure, where the filenames are hashed server urls (with extension)
this._mirrorMode = options.mode !== 'hash';
this._retry = options.retry || [500,1500,8000];
this._cacheBuster = !!options.cacheBuster;
// normalize path
this._localRoot = options.localRoot || 'data';
if(this._localRoot[this._localRoot.length -1] !== '/') this._localRoot += '/';
if(this._localRoot[0] !== '/') this._localRoot = '/' + this._localRoot;
this._serverRoot = options.serverRoot || '';
if(!!this._serverRoot && this._serverRoot[this._serverRoot.length-1] !== '/') this._serverRoot += '/';
if(this._serverRoot === './') this._serverRoot = '';
// set internal variables
this._downloading = []; // download promises
this._added = []; // added files
this._cached = {}; // cached files
// list existing cache contents
this.ready = this.list();
}
/**
* Helper to cache all 'internalURL' and 'URL' for quick synchronous access
* to the cached files.
*/
FileCache.prototype.list = function list(){
var self = this;
return new Promise(function(resolve,reject){
self._fs.list(self._localRoot,'rfe').then(function(entries){
self._cached = {};
entries = entries.map(function(entry){
self._cached[entry.fullPath] = {
toInternalURL: isCordova? entry.toInternalURL(): entry.toURL(),
toURL: entry.toURL(),
};
return entry.fullPath;
});
resolve(entries);
},function(){
resolve([]);
});
});
};
FileCache.prototype.add = function add(urls){
if(!urls) urls = [];
if(typeof urls === 'string') urls = [urls];
var self = this;
urls.forEach(function(url){
url = self.toServerURL(url);
if(self._added.indexOf(url) === -1) {
self._added.push(url);
}
});
return self.isDirty();
};
FileCache.prototype.remove = function remove(urls,returnPromises){
if(!urls) urls = [];
var promises = [];
if(typeof urls === 'string') urls = [urls];
var self = this;
urls.forEach(function(url){
var index = self._added.indexOf(self.toServerURL(url));
if(index >= 0) self._added.splice(index,1);
var path = self.toPath(url);
promises.push(self._fs.remove(path));
delete self._cached[path];
});
return returnPromises? Promise.all(promises): self.isDirty();
};
FileCache.prototype.getDownloadQueue = function(){
var self = this;
var queue = self._added.filter(function(url){
return !self.isCached(url);
});
return queue;
};
FileCache.prototype.getAdded = function() {
return this._added;
};
FileCache.prototype.isDirty = function isDirty(){
return this.getDownloadQueue().length > 0;
};
FileCache.prototype.download = function download(onprogress){
var fs = this._fs;
var self = this;
self.abort();
return new Promise(function(resolve,reject){
// make sure cache directory exists and that
// we have retrieved the latest cache contents
// to avoid downloading files we already have!
fs.ensure(self._localRoot).then(function(){
return self.list();
}).then(function(){
// no dowloads needed, resolve
if(!self.isDirty()) {
resolve(self);
return;
}
// keep track of number of downloads!
var queue = self.getDownloadQueue();
var started = [];
var index = self._downloading.length;
var done = self._downloading.length;
var total = self._downloading.length + queue.length;
// download every file in the queue (which is the diff from _added with _cached)
queue.forEach(function(url){
var path = self.toPath(url);
// augment progress event with index/total stats
var onSingleDownloadProgress;
if(typeof onprogress === 'function') {
onSingleDownloadProgress = function(ev){
ev.queueIndex = index;
ev.queueSize = total;
ev.url = url;
ev.path = path;
ev.percentage = index / total;
if(ev.loaded > 0 && ev.total > 0 && index !== total){
ev.percentage += (ev.loaded / ev.total) / total;
}
if(started.indexOf(url) < 0) {
started.push(url);
index++;
}
onprogress(ev);
};
}
// callback
var onDone = function(){
done++;
// when we're done
if(done === total) {
// reset downloads
self._downloading = [];
// check if we got everything
self.list().then(function(){
// final progress event!
if(onSingleDownloadProgress) onSingleDownloadProgress(new ProgressEvent());
// Yes, we're not dirty anymore!
if(!self.isDirty()) {
resolve(self);
// Aye, some files got left behind!
} else {
reject(self.getDownloadQueue());
}
},reject);
}
};
var downloadUrl = url;
if(self._cacheBuster) downloadUrl += "?"+Date.now();
var download = fs.download(url,path,{retry:self._retry},onSingleDownloadProgress);
download.then(onDone,onDone);
self._downloading.push(download);
});
},reject);
});
};
FileCache.prototype.abort = function abort(){
this._downloading.forEach(function(download){
download.abort();
});
this._downloading = [];
};
FileCache.prototype.isCached = function isCached(url){
url = this.toPath(url);
return !!this._cached[url];
};
FileCache.prototype.clear = function clear(){
this._cached = {};
return this._fs.removeDir(this._localRoot);
};
/**
* Helpers to output to various formats
*/
FileCache.prototype.toInternalURL = function toInternalURL(url){
path = this.toPath(url);
if(this._cached[path]) return this._cached[path].toInternalURL;
return this._fs.toInternalURLSync(path);
};
FileCache.prototype.get = function get(url){
path = this.toPath(url);
if(this._cached[path]) return this._cached[path].toInternalURL;
return this.toServerURL(url);
};
FileCache.prototype.toDataURL = function toDataURL(url){
return this._fs.toDataURL(this.toPath(url));
};
FileCache.prototype.toURL = function toURL(url){
path = this.toPath(url);
return this._cached[path]? this._cached[path].toURL: url;
};
FileCache.prototype.toServerURL = function toServerURL(path){
if(path[0] === '/') path = path.substr(1);
return path.indexOf('://') < 0? this._serverRoot + path: path;
};
/**
* Helper to transform remote URL to a local path (for cordova-promise-fs)
*/
FileCache.prototype.toPath = function toPath(url){
if(this._mirrorMode) {
url = url || '';
len = this._serverRoot.length;
if(url.substr(0,len) !== this._serverRoot) {
if(url[0] === '/') url = url.substr(1);
return this._localRoot + url;
} else {
return this._localRoot + url.substr(len);
}
} else {
return this._localRoot + hash(url) + url.substr(url.lastIndexOf('.'));
}
};
module.exports = FileCache;
/***/ },
/* 5 */
/***/ function(module, exports, __webpack_require__) {
/**
* JS Implementation of MurmurHash3 (r136) (as of May 20, 2011)
*
* @author <a href="mailto:gary.court@gmail.com">Gary Court</a>
* @see http://github.com/garycourt/murmurhash-js
* @author <a href="mailto:aappleby@gmail.com">Austin Appleby</a>
* @see http://sites.google.com/site/murmurhash/
*
* @param {string} key ASCII only
* @param {number} seed Positive integer only
* @return {number} 32-bit positive integer hash
*/
function murmurhash3_32_gc(key, seed) {
var remainder, bytes, h1, h1b, c1, c1b, c2, c2b, k1, i;
remainder = key.length & 3; // key.length % 4
bytes = key.length - remainder;
h1 = seed;
c1 = 0xcc9e2d51;
c2 = 0x1b873593;
i = 0;
while (i < bytes) {
k1 =
((key.charCodeAt(i) & 0xff)) |
((key.charCodeAt(++i) & 0xff) << 8) |
((key.charCodeAt(++i) & 0xff) << 16) |
((key.charCodeAt(++i) & 0xff) << 24);
++i;
k1 = ((((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16))) & 0xffffffff;
k1 = (k1 << 15) | (k1 >>> 17);
k1 = ((((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16))) & 0xffffffff;
h1 ^= k1;
h1 = (h1 << 13) | (h1 >>> 19);
h1b = ((((h1 & 0xffff) * 5) + ((((h1 >>> 16) * 5) & 0xffff) << 16))) & 0xffffffff;
h1 = (((h1b & 0xffff) + 0x6b64) + ((((h1b >>> 16) + 0xe654) & 0xffff) << 16));
}
k1 = 0;
switch (remainder) {
case 3: k1 ^= (key.charCodeAt(i + 2) & 0xff) << 16;
case 2: k1 ^= (key.charCodeAt(i + 1) & 0xff) << 8;
case 1: k1 ^= (key.charCodeAt(i) & 0xff);
k1 = (((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff;
k1 = (k1 << 15) | (k1 >>> 17);
k1 = (((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff;
h1 ^= k1;
}
h1 ^= key.length;
h1 ^= h1 >>> 16;
h1 = (((h1 & 0xffff) * 0x85ebca6b) + ((((h1 >>> 16) * 0x85ebca6b) & 0xffff) << 16)) & 0xffffffff;
h1 ^= h1 >>> 13;
h1 = ((((h1 & 0xffff) * 0xc2b2ae35) + ((((h1 >>> 16) * 0xc2b2ae35) & 0xffff) << 16))) & 0xffffffff;
h1 ^= h1 >>> 16;
return h1 >>> 0;
}
module.exports = murmurhash3_32_gc;
/***/ }
/******/ ])
// 3. Chrome: On page becomes visible again
function handleVisibilityChange() {
if (!document.webkitHidden) {
check();
}
}
document.addEventListener("webkitvisibilitychange", handleVisibilityChange, false);
})();

@@ -234,3 +234,3 @@ var CordovaAppLoader =

if(this._localRoot[this._localRoot.length -1] !== '/') this._localRoot += '/';
if(this._localRoot[0] !== '/') this._localRoot = '/' + this._localRoot;
if(this._localRoot[0] === '/') this._localRoot = this._localRoot.substr(1);

@@ -237,0 +237,0 @@ this._serverRoot = options.serverRoot || '';

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc