From 0aea9b17d6d41962391484d5a6594bd96b404722 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Mon, 21 Nov 2022 14:40:23 +0100 Subject: [PATCH] 2.0.0-beta.5 --- doc/version.py | 2 +- package-lock.json | 4 +- package.json | 2 +- release/remotestorage.js | 10 +- release/remotestorage.js.map | 2 +- release/types/authorize.d.ts | 19 ++- release/types/authorize.d.ts.map | 2 +- release/types/baseclient.d.ts | 1 + release/types/baseclient.d.ts.map | 2 +- release/types/discover.d.ts.map | 2 +- release/types/dropbox.d.ts | 129 ++++++++++++------ release/types/dropbox.d.ts.map | 2 +- release/types/googledrive.d.ts | 41 +++--- release/types/googledrive.d.ts.map | 2 +- .../types/interfaces/authorize_options.d.ts | 12 ++ .../interfaces/authorize_options.d.ts.map | 1 + release/types/remote.d.ts | 83 +++++++++++ release/types/remote.d.ts.map | 1 + release/types/remotestorage.d.ts | 23 ++-- release/types/remotestorage.d.ts.map | 2 +- release/types/requests.d.ts | 23 ++++ release/types/requests.d.ts.map | 1 + release/types/syncedgetputdelete.d.ts.map | 2 +- release/types/util.d.ts | 15 ++ release/types/util.d.ts.map | 2 +- release/types/wireclient.d.ts | 51 ++----- release/types/wireclient.d.ts.map | 2 +- 27 files changed, 299 insertions(+), 139 deletions(-) create mode 100644 release/types/interfaces/authorize_options.d.ts create mode 100644 release/types/interfaces/authorize_options.d.ts.map create mode 100644 release/types/remote.d.ts create mode 100644 release/types/remote.d.ts.map create mode 100644 release/types/requests.d.ts create mode 100644 release/types/requests.d.ts.map diff --git a/doc/version.py b/doc/version.py index 9a4c1bf81..f7a40209b 100644 --- a/doc/version.py +++ b/doc/version.py @@ -1 +1 @@ -__version__ = '2.0.0-beta.4' +__version__ = '2.0.0-beta.5' diff --git a/package-lock.json b/package-lock.json index 3e2c73e9c..a8cdc0583 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "remotestoragejs", - "version": "2.0.0-beta.4", + "version": "2.0.0-beta.5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "remotestoragejs", - "version": "2.0.0-beta.4", + "version": "2.0.0-beta.5", "license": "MIT", "dependencies": { "@types/node": "16.11.59", diff --git a/package.json b/package.json index 73461ec5b..1f5f65b27 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "remotestoragejs", "description": "JavaScript library for integrating remoteStorage", - "version": "2.0.0-beta.4", + "version": "2.0.0-beta.5", "private": false, "license": "MIT", "main": "./release/remotestorage.js", diff --git a/release/remotestorage.js b/release/remotestorage.js index aa0f0de3a..924dc232a 100644 --- a/release/remotestorage.js +++ b/release/remotestorage.js @@ -1,12 +1,14 @@ -/*! remotestorage.js 2.0.0-beta.4, https://remotestorage.io, MIT licensed */ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("RemoteStorage",[],t):"object"==typeof exports?exports.RemoteStorage=t():e.RemoteStorage=t()}(this,(function(){return function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}return r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=17)}([function(e,t,r){"use strict";(function(e,r){Object.defineProperty(t,"__esModule",{value:!0}),t.applyMixins=t.toBase64=t.getTextFromArrayBuffer=t.shouldBeTreatedAsBinary=t.getJSONFromLocalStorage=t.localStorageAvailable=t.pathsFromRoot=t.deepClone=t.equal=t.bindAll=t.cleanPath=t.baseName=t.isDocument=t.isFolder=t.containingFolder=t.extend=t.getGlobalContext=t.globalContext=t.logError=void 0,t.logError=e=>{"string"==typeof e?console.error(e):console.error(e.message,e.stack)},t.globalContext="undefined"!=typeof window?window:"object"==typeof self?self:e,t.getGlobalContext=()=>"undefined"!=typeof window?window:"object"==typeof self?self:e,t.extend=(...e)=>{const t=e[0];return Array.prototype.slice.call(e,1).forEach((function(e){for(const r in e)t[r]=e[r]})),t},t.containingFolder=e=>{if(""===e)return"/";if(!e)throw"Path not given!";return e.replace(/\/+/g,"/").replace(/[^\/]+\/?$/,"")},t.isFolder=e=>"/"===e.slice(-1),t.isDocument=e=>!t.isFolder(e),t.baseName=e=>{const r=e.split("/");return t.isFolder(e)?r[r.length-2]+"/":r[r.length-1]},t.cleanPath=e=>e.replace(/\/+/g,"/").split("/").map(encodeURIComponent).join("/").replace(/'/g,"%27"),t.bindAll=e=>{for(const t in this)"function"==typeof e[t]&&(e[t]=e[t].bind(e))},t.equal=(e,r,n=[])=>{let o;if(typeof e!=typeof r)return!1;if("number"==typeof e||"boolean"==typeof e||"string"==typeof e)return e===r;if("function"==typeof e)return e.toString()===r.toString();if(e instanceof ArrayBuffer&&r instanceof ArrayBuffer&&(e=new Uint8Array(e),r=new Uint8Array(r)),e instanceof Array){if(e.length!==r.length)return!1;for(let o=0,i=e.length;o=0)continue;i=n.slice(),i.push(r[o])}if(!t.equal(e[o],r[o],i))return!1}}return!0},t.deepClone=e=>{if(void 0!==e){const t=JSON.parse(JSON.stringify(e));return function e(t,r){if("object"==typeof t&&!Array.isArray(t)&&null!==t)for(const n in t)if("object"==typeof t[n]&&null!==t[n])if("[object ArrayBuffer]"===t[n].toString()){r[n]=new ArrayBuffer(t[n].byteLength);const e=new Int8Array(t[n]);new Int8Array(r[n]).set(e)}else e(t[n],r[n])}(e,t),t}},t.pathsFromRoot=e=>{const t=[e],r=e.replace(/\/$/,"").split("/");for(;r.length>1;)r.pop(),t.push(r.join("/")+"/");return t},t.localStorageAvailable=()=>{const e=t.getGlobalContext();if(!("localStorage"in e))return!1;try{return e.localStorage.setItem("rs-check","1"),e.localStorage.removeItem("rs-check"),!0}catch(e){return!1}},t.getJSONFromLocalStorage=e=>{const r=t.getGlobalContext();try{return JSON.parse(r.localStorage.getItem(e))}catch(e){}},t.shouldBeTreatedAsBinary=(e,t)=>!!(t&&t.match(/charset=binary/)||/[\x00-\x08\x0E-\x1F\uFFFD]/.test(e)),t.getTextFromArrayBuffer=(e,n)=>new Promise(o=>{if("undefined"==typeof Blob){const t=new r(new Uint8Array(e));o(t.toString(n))}else{let r;const i=t.globalContext;if(i.BlobBuilder=i.BlobBuilder||i.WebKitBlobBuilder,void 0!==i.BlobBuilder){const t=new i.BlobBuilder;t.append(e),r=t.getBlob()}else r=new Blob([e]);const s=new FileReader;"function"==typeof s.addEventListener?s.addEventListener("loadend",(function(e){o(e.target.result)})):s.onloadend=function(e){o(e.target.result)},s.readAsText(r,n)}}),t.toBase64=e=>{const n=t.getGlobalContext();return"btoa"in n?n.btoa(e):r.from(e).toString("base64")},t.applyMixins=function(e,t){t.forEach(t=>{Object.getOwnPropertyNames(t.prototype).forEach(r=>{Object.defineProperty(e.prototype,r,Object.getOwnPropertyDescriptor(t.prototype,r))})})}}).call(this,r(5),r(19).Buffer)},function(e,t,r){"use strict";const n=(this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}})(r(3));e.exports=function(...e){n.default.logging&&console.log(...e)}},function(e,t,r){"use strict";const n=(this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}})(r(1));e.exports=class{addEvents(e){e.forEach(e=>this._addEvent(e))}addEventListener(e,t){if("string"!=typeof e)throw new Error("Argument eventName should be a string");if("function"!=typeof t)throw new Error("Argument handler should be a function");n.default("[EventHandling] Adding event listener",e),this._validateEvent(e),this._handlers[e].push(t)}on(e,t){return this.addEventListener(e,t)}removeEventListener(e,t){this._validateEvent(e);const r=this._handlers[e].length;for(let n=0;n{e.apply(this,t)})}_validateEvent(e){if(!(e in this._handlers))throw new Error("Unknown event: "+e)}_delegateEvent(e,t){t.on(e,t=>{this._emit(e,t)})}_addEvent(e){void 0===this._handlers&&(this._handlers={}),this._handlers[e]=[]}}},function(e,t,r){"use strict";const n={cache:!0,changeEvents:{local:!0,window:!1,remote:!0,conflict:!0},cordovaRedirectUri:void 0,logging:!1,modules:[],backgroundSyncInterval:6e4,disableFeatures:[],discoveryTimeout:1e4,isBackground:!1,requestTimeout:3e4,syncInterval:1e4};e.exports=n},function(e,t,r){"use strict";class n extends Error{constructor(e,t={}){super(),this.name="Unauthorized",this.message=void 0===e?"App authorization expired or revoked.":e,void 0!==t.code&&(this.code=t.code),this.stack=(new Error).stack}}e.exports=n},function(e,t){var r;r=function(){return this}();try{r=r||new Function("return this")()}catch(e){"object"==typeof window&&(r=window)}e.exports=r},function(e,t,r){"use strict";var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const o=n(r(1)),i=r(0),s=n(r(4));let a;function u(e){const t=e||c.getLocation().href,r=t.indexOf("#");if(-1===r)return;const n=t.substring(r+1);return n.includes("=")?n.split("&").reduce((function(e,t){const r=t.split("=");if("state"===r[0]&&r[1].match(/rsDiscovery/)){let t=decodeURIComponent(r[1]);const n=t.substr(t.indexOf("rsDiscovery=")).split("&")[0].split("=")[1];e.rsDiscovery=JSON.parse(atob(n)),t=t.replace(new RegExp("&?rsDiscovery="+n),""),t.length>0&&(e.state=t)}else e[decodeURIComponent(r[0])]=decodeURIComponent(r[1]);return e}),{}):void 0}class c{static authorize(e,{authURL:t,scope:r,redirectUri:n,clientId:s}){if(o.default("[Authorize] authURL = ",t,"scope = ",r,"redirectUri = ",n,"clientId = ",s),!r)throw new Error("Cannot authorize due to undefined or empty scope; did you forget to access.claim()?");if(!r)throw new Error("Cannot authorize due to undefined or empty scope; did you forget to access.claim()?");if(!i.localStorageAvailable()&&"remotestorage"===e.backend){n+=n.indexOf("#")>0?"&":"#";const t={userAddress:e.remote.userAddress,href:e.remote.href,storageApi:e.remote.storageApi,properties:e.remote.properties};n+="rsDiscovery="+i.toBase64(JSON.stringify(t))}const a=function(e,t,r,n){const o=t.indexOf("#");let i=e;return i+=e.indexOf("?")>0?"&":"?",i+="redirect_uri="+encodeURIComponent(t.replace(/#.*$/,"")),i+="&scope="+encodeURIComponent(r),i+="&client_id="+encodeURIComponent(n),-1!==o&&o+1!==t.length&&(i+="&state="+encodeURIComponent(t.substring(o+1))),i+="&response_type=token",i}(t,n,r,s);i.globalContext.cordova?c.openWindow(a,n,"location=yes,clearsessioncache=yes,clearcache=yes").then(t=>{e.remote.configure({token:t.access_token})}):c.setLocation(a)}static setLocation(e){if("string"==typeof e)document.location.href=e;else{if("object"!=typeof e)throw"Invalid location "+e;document.location=e}}static _rs_supported(){return"undefined"!=typeof document}static _rs_cleanup(e){e.removeEventListener("features-loaded",a)}}c.IMPLIED_FAKE_TOKEN=!1,c.getLocation=function(){return document.location},c.openWindow=function(e,t,r){return new Promise((n,o)=>{const i=open(e,"_blank",r);function s(){o("Authorization was canceled")}i&&!i.closed?(i.addEventListener("loadstart",(function(e){if(0!==e.url.indexOf(t))return;i.removeEventListener("exit",s),i.close();const r=u(e.url);r?n(r):o("Authorization error")})),i.addEventListener("exit",s)):o("Authorization popup was blocked")})},c._rs_init=function(e){const t=u();let r;t&&(r=c.getLocation(),r.hash=""),a=function(){let n=!1;if(t){if(t.error)throw"access_denied"===t.error?new s.default("Authorization failed: access denied",{code:"access_denied"}):new s.default(`Authorization failed: ${t.error}`);t.rsDiscovery&&e.remote.configure(t.rsDiscovery),t.access_token&&(e.remote.configure({token:t.access_token}),n=!0),t.remotestorage&&(e.connect(t.remotestorage),n=!0),t.state&&(r=c.getLocation(),c.setLocation(r.href.split("#")[0]+"#"+t.state)),n||e.remote.stopWaitingForToken()}else e.remote.stopWaitingForToken()},e.on("features-loaded",a)},e.exports=c},function(e,t,r){"use strict";var n=this&&this.__awaiter||function(e,t,r,n){return new(r||(r=Promise))((function(o,i){function s(e){try{u(n.next(e))}catch(e){i(e)}}function a(e){try{u(n.throw(e))}catch(e){i(e)}}function u(e){var t;e.done?o(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(s,a)}u((n=n.apply(e,t||[])).next())}))},o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const i=o(r(23)),s=o(r(24)),a=o(r(25)),u=o(r(2)),c=o(r(3)),h=r(0);class l{constructor(e,t){if(this.schemas={configurable:!0,get(){return l.Types.inScope(this.moduleName)}},"/"!==t[t.length-1])throw"Not a folder: "+t;"/"===t&&(this.makePath=e=>("/"===e[0]?"":"/")+e),this.storage=e,this.base=t,this.moduleName=function(e){const t=e.split("/");return e.length>2?t[1]:"root"}(this.base),this.addEvents(["change"]),this.on=this.on.bind(this),e.onChange(this.base,this._fireChange.bind(this))}scope(e){return new l(this.storage,this.makePath(e))}getListing(e,t){return n(this,void 0,void 0,(function*(){if("string"!=typeof e)e="";else if(e.length>0&&!h.isFolder(e))return Promise.reject("Not a folder: "+e);return this.storage.get(this.makePath(e),t).then(e=>404===e.statusCode?{}:e.body)}))}getAll(e,t){return n(this,void 0,void 0,(function*(){if("string"!=typeof e)e="";else if(e.length>0&&!h.isFolder(e))return Promise.reject("Not a folder: "+e);return this.storage.get(this.makePath(e),t).then(r=>{if(404===r.statusCode)return{};if("object"==typeof r.body){const n=Object.keys(r.body);if(0===n.length)return{};const o=n.map(n=>this.storage.get(this.makePath(e+n),t).then(e=>{if("string"==typeof e.body)try{e.body=JSON.parse(e.body)}catch(e){}"object"==typeof e.body&&(r.body[n]=e.body)}));return Promise.all(o).then(()=>r.body)}})}))}getFile(e,t){return n(this,void 0,void 0,(function*(){return"string"!=typeof e?Promise.reject("Argument 'path' of baseClient.getFile must be a string"):this.storage.get(this.makePath(e),t).then(e=>({data:e.body,contentType:e.contentType,revision:e.revision}))}))}storeFile(e,t,r){return n(this,void 0,void 0,(function*(){return"string"!=typeof e?Promise.reject("Argument 'mimeType' of baseClient.storeFile must be a string"):"string"!=typeof t?Promise.reject("Argument 'path' of baseClient.storeFile must be a string"):"string"!=typeof r&&"object"!=typeof r?Promise.reject("Argument 'body' of baseClient.storeFile must be a string, ArrayBuffer, or ArrayBufferView"):(this.storage.access.checkPathPermission(this.makePath(t),"rw")||console.warn("WARNING: Editing a document to which only read access ('r') was claimed"),this.storage.put(this.makePath(t),r,e).then(e=>200===e.statusCode||201===e.statusCode?e.revision:Promise.reject("Request (PUT "+this.makePath(t)+") failed with status: "+e.statusCode)))}))}getObject(e,t){return n(this,void 0,void 0,(function*(){return"string"!=typeof e?Promise.reject("Argument 'path' of baseClient.getObject must be a string"):this.storage.get(this.makePath(e),t).then(t=>{if("object"==typeof t.body)return t.body;if("string"==typeof t.body)try{return JSON.parse(t.body)}catch(t){throw new Error("Not valid JSON: "+this.makePath(e))}else if(void 0!==t.body&&200===t.statusCode)return Promise.reject("Not an object: "+this.makePath(e))})}))}storeObject(e,t,r){return n(this,void 0,void 0,(function*(){if("string"!=typeof e)return Promise.reject("Argument 'typeAlias' of baseClient.storeObject must be a string");if("string"!=typeof t)return Promise.reject("Argument 'path' of baseClient.storeObject must be a string");if("object"!=typeof r)return Promise.reject("Argument 'object' of baseClient.storeObject must be an object");this._attachType(r,e);try{const e=this.validate(r);if(!e.valid)return Promise.reject(e)}catch(e){return Promise.reject(e)}return this.storage.put(this.makePath(t),JSON.stringify(r),"application/json; charset=UTF-8").then(e=>200===e.statusCode||201===e.statusCode?e.revision:Promise.reject("Request (PUT "+this.makePath(t)+") failed with status: "+e.statusCode))}))}remove(e){return"string"!=typeof e?Promise.reject("Argument 'path' of baseClient.remove must be a string"):(this.storage.access.checkPathPermission(this.makePath(e),"rw")||console.warn("WARNING: Removing a document to which only read access ('r') was claimed"),this.storage.delete(this.makePath(e)))}getItemURL(e){if("string"!=typeof e)throw"Argument 'path' of baseClient.getItemURL must be a string";return this.storage.connected?(e=h.cleanPath(this.makePath(e)),this.storage.remote.href+e):void 0}cache(e,t="ALL"){if("string"!=typeof e)throw"Argument 'path' of baseClient.cache must be a string";if("string"!=typeof t)throw"Argument 'strategy' of baseClient.cache must be a string or undefined";if("FLUSH"!==t&&"SEEN"!==t&&"ALL"!==t)throw'Argument \'strategy\' of baseclient.cache must be one of ["FLUSH", "SEEN", "ALL"]';return this.storage.caching.set(this.makePath(e),t),this}flush(e){return this.storage.local.flush(e)}declareType(e,t,r){let n;if(r&&"string"==typeof t)n=t;else if(r||"string"==typeof t){if(!r&&"string"==typeof t)throw new Error("declareType() requires a JSON Schema object to be passed, in order to validate object types/formats")}else r=t,n=this._defaultTypeURI(e);l.Types.declare(this.moduleName,e,n,r)}validate(e){const t=l.Types.getSchema(e["@context"]);if(t)return i.default.validateResult(e,t);throw new a.default(e["@context"])}_defaultTypeURI(e){return"http://remotestorage.io/spec/modules/"+encodeURIComponent(this.moduleName)+"/"+encodeURIComponent(e)}_attachType(e,t){e["@context"]=l.Types.resolveAlias(this.moduleName+"/"+t)||this._defaultTypeURI(t)}makePath(e){return this.base+(e||"")}_fireChange(e){c.default.changeEvents[e.origin]&&(["new","old","lastCommon"].forEach((function(t){if((!e[t+"ContentType"]||/^application\/(.*)json(.*)/.exec(e[t+"ContentType"]))&&"string"==typeof e[t+"Value"])try{e[t+"Value"]=JSON.parse(e[t+"Value"])}catch(e){}})),this._emit("change",e))}static _rs_init(){}}l.Types=s.default,h.applyMixins(l,[u.default]),e.exports=l},function(e,t,r){"use strict";(function(t){var n=this&&this.__awaiter||function(e,t,r,n){return new(r||(r=Promise))((function(o,i){function s(e){try{u(n.next(e))}catch(e){i(e)}}function a(e){try{u(n.throw(e))}catch(e){i(e)}}function u(e){var t;e.done?o(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(s,a)}u((n=n.apply(e,t||[])).next())}))},o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const i=o(r(6)),s=o(r(2)),a=o(r(4)),u=o(r(3)),c=o(r(1)),h=r(0);let l;const d="remotestorage:wireclient",f={"draft-dejong-remotestorage-00":2,"draft-dejong-remotestorage-01":3,"draft-dejong-remotestorage-02":4,"https://www.w3.org/community/rww/wiki/read-write-web-00#simple":1};let p;if("function"==typeof(t||window).ArrayBufferView)p=function(e){return e&&e instanceof(t||window).ArrayBufferView};else{const e=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];p=function(t){for(let r=0;r<8;r++)if(t instanceof e[r])return!0;return!1}}function m(e){return"string"!=typeof e?e:"*"===e?"*":'"'+e+'"'}function g(e){return"string"!=typeof e?e:e.replace(/^["']|["']$/g,"")}class y{constructor(e){if(this._revisionCache={},l=h.localStorageAvailable(),this.rs=e,this.connected=!1,this.addEvents(["connected","not-connected"]),l){const e=function(){const e=h.getJSONFromLocalStorage(d)||{},{userAddress:t,href:r,storageApi:n,token:o,properties:i}=e;return{userAddress:t,href:r,storageApi:n,token:o,properties:i}}();e&&setTimeout(()=>{this.configure(e)},0)}this.connected&&setTimeout(this._emit.bind(this),0,"connected")}get storageType(){if(this.storageApi){const e=this.storageApi.match(/draft-dejong-(remotestorage-\d\d)/);return e?e[1]:"2012.04"}}_request(e,t,r,o,s,u,l){return n(this,void 0,void 0,(function*(){if(function(e,t){return("PUT"===e||"DELETE"===e)&&h.isFolder(t)}(e,t))return Promise.reject(`Don't use ${e} on directories!`);let n;return r!==i.default.IMPLIED_FAKE_TOKEN&&(o.Authorization="Bearer "+r),this.rs._emit("wire-busy",{method:e,isFolder:h.isFolder(t)}),y.request(e,t,{body:s,headers:o,responseType:"arraybuffer"}).then(r=>{if(this.online||(this.online=!0,this.rs._emit("network-online")),this.rs._emit("wire-done",{method:e,isFolder:h.isFolder(t),success:!0}),o=r.status,[401,403,404,412].indexOf(o)>=0)return c.default("[WireClient] Error response status",r.status),n=u?g(r.getResponseHeader("ETag")):void 0,401===r.status&&this.rs._emit("error",new a.default),Promise.resolve({statusCode:r.status,revision:n});if(function(e){return[201,204,304].indexOf(e)>=0}(r.status)||200===r.status&&"GET"!==e)return n=g(r.getResponseHeader("ETag")),c.default("[WireClient] Successful request",n),Promise.resolve({statusCode:r.status,revision:n});{const e=r.getResponseHeader("Content-Type");n=u?g(r.getResponseHeader("ETag")):200===r.status?l:void 0;const t=function(e){let t,r="utf-8";return e&&(t=e.match(/charset=(.+)$/),t&&(r=t[1])),r}(e);return h.shouldBeTreatedAsBinary(r.response,e)?(c.default("[WireClient] Successful request with unknown or binary mime-type",n),Promise.resolve({statusCode:r.status,body:r.response,contentType:e,revision:n})):h.getTextFromArrayBuffer(r.response,t).then(t=>(c.default("[WireClient] Successful request",n),Promise.resolve({statusCode:r.status,body:t,contentType:e,revision:n})))}var o},r=>(this.online&&(this.online=!1,this.rs._emit("network-offline")),this.rs._emit("wire-done",{method:e,isFolder:h.isFolder(t),success:!1}),Promise.reject(r)))}))}configure(e){if("object"!=typeof e)throw new Error("WireClient configure settings parameter should be an object");if(void 0!==e.userAddress&&(this.userAddress=e.userAddress),void 0!==e.href&&(this.href=e.href),void 0!==e.storageApi&&(this.storageApi=e.storageApi),void 0!==e.token&&(this.token=e.token),void 0!==e.properties&&(this.properties=e.properties),"string"==typeof this.storageApi){const e=f[this.storageApi]||5;this.supportsRevs=e>=2}this.href&&this.token?(this.connected=!0,this.online=!0,this._emit("connected")):this.connected=!1,l&&(localStorage[d]=JSON.stringify({userAddress:this.userAddress,href:this.href,storageApi:this.storageApi,token:this.token,properties:this.properties}))}stopWaitingForToken(){this.connected||this._emit("not-connected")}get(e,t={}){if(!this.connected)return Promise.reject("not connected (path: "+e+")");const r={};return this.supportsRevs&&t.ifNoneMatch&&(r["If-None-Match"]=m(t.ifNoneMatch)),this._request("GET",this.href+h.cleanPath(e),this.token,r,void 0,this.supportsRevs,this._revisionCache[e]).then(t=>{if(!h.isFolder(e))return Promise.resolve(t);let r={};if(void 0!==t.body)try{t.body=JSON.parse(t.body)}catch(t){return Promise.reject("Folder description at "+this.href+h.cleanPath(e)+" is not JSON")}if(200===t.statusCode&&"object"==typeof t.body){if(0===Object.keys(t.body).length)t.statusCode=404;else if("http://remotestorage.io/spec/folder-description"===(n=t.body)["@context"]&&"object"==typeof n.items){for(const r in t.body.items)this._revisionCache[e+r]=t.body.items[r].ETag;r=t.body.items}else Object.keys(t.body).forEach(n=>{this._revisionCache[e+n]=t.body[n],r[n]={ETag:t.body[n]}});return t.body=r,Promise.resolve(t)}return Promise.resolve(t);var n})}put(e,t,r,n={}){if(!this.connected)return Promise.reject("not connected (path: "+e+")");!r.match(/charset=/)&&(t instanceof ArrayBuffer||p(t))&&(r+="; charset=binary");const o={"Content-Type":r};return this.supportsRevs&&(n.ifMatch&&(o["If-Match"]=m(n.ifMatch)),n.ifNoneMatch&&(o["If-None-Match"]=m(n.ifNoneMatch))),this._request("PUT",this.href+h.cleanPath(e),this.token,o,t,this.supportsRevs)}delete(e,t={}){if(!this.connected)throw new Error("not connected (path: "+e+")");t||(t={});const r={};return this.supportsRevs&&t.ifMatch&&(r["If-Match"]=m(t.ifMatch)),this._request("DELETE",this.href+h.cleanPath(e),this.token,r,void 0,this.supportsRevs)}static request(e,t,r){return n(this,void 0,void 0,(function*(){return"function"==typeof fetch?y._fetchRequest(e,t,r):"function"==typeof XMLHttpRequest?y._xhrRequest(e,t,r):(c.default("[WireClient] You need to add a polyfill for fetch or XMLHttpRequest"),Promise.reject("[WireClient] You need to add a polyfill for fetch or XMLHttpRequest"))}))}static _fetchRequest(e,t,r){let n;const o={};let i;"function"==typeof AbortController&&(i=new AbortController);const s=fetch(t,{method:e,headers:r.headers,body:r.body,signal:i?i.signal:void 0}).then(e=>{switch(c.default("[WireClient fetch]",e),e.headers.forEach((e,t)=>{o[t.toUpperCase()]=e}),n={readyState:4,status:e.status,statusText:e.statusText,response:void 0,getResponseHeader:e=>o[e.toUpperCase()]||null,responseType:r.responseType,responseURL:t},r.responseType){case"arraybuffer":return e.arrayBuffer();case"blob":return e.blob();case"json":return e.json();case void 0:case"":case"text":return e.text();default:throw new Error("responseType 'document' is not currently supported using fetch")}}).then(e=>(n.response=e,r.responseType&&"text"!==r.responseType||(n.responseText=e),n)),a=new Promise((e,t)=>{setTimeout(()=>{t("timeout"),i&&i.abort()},u.default.requestTimeout)});return Promise.race([s,a])}static _xhrRequest(e,t,r){return new Promise((n,o)=>{c.default("[WireClient]",e,t);let i=!1;const s=setTimeout(()=>{i=!0,o("timeout")},u.default.requestTimeout),a=new XMLHttpRequest;if(a.open(e,t,!0),r.responseType&&(a.responseType=r.responseType),r.headers)for(const e in r.headers)a.setRequestHeader(e,r.headers[e]);a.onload=()=>{i||(clearTimeout(s),n(a))},a.onerror=e=>{i||(clearTimeout(s),o(e))};let h=r.body;"object"==typeof h&&!p(h)&&h instanceof ArrayBuffer&&(h=new Uint8Array(h)),a.send(h)})}static _rs_init(e){e.remote=new y(e),e.remote.online=!0}static _rs_supported(){return"function"==typeof fetch||"function"==typeof XMLHttpRequest}static _rs_cleanup(){l&&delete localStorage[d]}}y.isArrayBufferView=p,h.applyMixins(y,[s.default]),e.exports=y}).call(this,r(5))},function(e,t,r){"use strict";class n extends Error{constructor(e){super(),this.name="SyncError",this.message="Sync failed: ","string"==typeof e?this.message+=e:(this.message+=e.message,this.stack=e.stack,this.originalError=e)}}e.exports=n},function(e,t,r){"use strict";var n=this&&this.__awaiter||function(e,t,r,n){return new(r||(r=Promise))((function(o,i){function s(e){try{u(n.next(e))}catch(e){i(e)}}function a(e){try{u(n.throw(e))}catch(e){i(e)}}function u(e){var t;e.done?o(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(s,a)}u((n=n.apply(e,t||[])).next())}))},o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const i=o(r(2)),s=o(r(3)),a=o(r(1)),u=r(0);function c(e){if("object"==typeof e&&"string"==typeof e.path)if(u.isFolder(e.path)){if(e.local&&e.local.itemsMap)return e.local;if(e.common&&e.common.itemsMap)return e.common}else{if(e.local){if(e.local.body&&e.local.contentType)return e.local;if(!1===e.local.body)return}if(e.common&&e.common.body&&e.common.contentType)return e.common;if(e.body&&e.contentType)return{body:e.body,contentType:e.contentType}}}function h(e,t){for(const r in e){if(e[r]&&e[r].remote)return!0;const n=c(e[r]);if(n&&n.timestamp&&(new Date).getTime()-n.timestamp<=t)return!1;if(!n)return!0}return!0}function l(e){const t={path:e,common:{}};return u.isFolder(e)&&(t.common.itemsMap={}),t}function d(e,t){return e.common||(e.common={itemsMap:{}}),e.common.itemsMap||(e.common.itemsMap={}),e.local||(e.local=u.deepClone(e.common)),e.local.itemsMap||(e.local.itemsMap=e.common.itemsMap),e.local.itemsMap[t]=!0,e}class f{constructor(){this._updateNodesRunning=!1,this._updateNodesQueued=[]}get(e,t,r){return n(this,void 0,void 0,(function*(){return"number"==typeof t?this.getNodes(u.pathsFromRoot(e)).then(n=>{const o=c(n[e]);return h(n,t)?r(e):o?{statusCode:200,body:o.body||o.itemsMap,contentType:o.contentType}:{statusCode:404}}):this.getNodes([e]).then(t=>{const r=c(t[e]);if(r){if(u.isFolder(e))for(const e in r.itemsMap)r.itemsMap.hasOwnProperty(e)&&!1===r.itemsMap[e]&&delete r.itemsMap[e];return{statusCode:200,body:r.body||r.itemsMap,contentType:r.contentType}}return{statusCode:404}})}))}put(e,t,r){return n(this,void 0,void 0,(function*(){const n=u.pathsFromRoot(e);return this._updateNodes(n,(function(e,n){try{for(let o=0,i=e.length;o0)break}else console.error("Cannot delete non-existing node "+n)}return t}))}flush(e){return this._getAllDescendentPaths(e).then(e=>this.getNodes(e)).then(e=>{for(const t in e){const r=e[t];r&&r.common&&r.local&&this._emitChange({path:r.path,origin:"local",oldValue:!1===r.local.body?void 0:r.local.body,newValue:!1===r.common.body?void 0:r.common.body}),e[t]=void 0}return this.setNodes(e)})}_emitChange(e){s.default.changeEvents[e.origin]&&this._emit("change",e)}fireInitial(){s.default.changeEvents.local&&this.forAllNodes(e=>{if(u.isDocument(e.path)){const t=c(e);t&&this._emitChange({path:e.path,origin:"local",oldValue:void 0,oldContentType:void 0,newValue:t.body,newContentType:t.contentType})}}).then(()=>{this._emit("local-events-done")})}onDiff(e){this.diffHandler=e}migrate(e){return"object"!=typeof e||e.common||(e.common={},"string"==typeof e.path?"/"===e.path.substr(-1)&&"object"==typeof e.body&&(e.common.itemsMap=e.body):(e.local||(e.local={}),e.local.body=e.body,e.local.contentType=e.contentType)),e}_updateNodes(e,t){return new Promise((r,n)=>{this._doUpdateNodes(e,t,{resolve:r,reject:n})})}_doUpdateNodes(e,t,r){this._updateNodesRunning?this._updateNodesQueued.push({paths:e,cb:t,promise:r}):(this._updateNodesRunning=!0,this.getNodes(e).then(n=>{const o=u.deepClone(n),i=[];n=t(e,n);for(const e in n){const t=n[e];u.equal(t,o[e])?delete n[e]:u.isDocument(e)&&(u.equal(t.local.body,t.local.previousBody)&&t.local.contentType===t.local.previousContentType||i.push({path:e,origin:"window",oldValue:t.local.previousBody,newValue:!1===t.local.body?void 0:t.local.body,oldContentType:t.local.previousContentType,newContentType:t.local.contentType}),delete t.local.previousBody,delete t.local.previousContentType)}this.setNodes(n).then(()=>{this._emitChangeEvents(i),r.resolve({statusCode:200})})}).then(()=>Promise.resolve(),e=>{r.reject(e)}).then(()=>{this._updateNodesRunning=!1;const e=this._updateNodesQueued.shift();e&&this._doUpdateNodes(e.paths,e.cb,e.promise)}))}_emitChangeEvents(e){for(let t=0,r=e.length;t{const r=[e],n=c(t[e]),o=Object.keys(n.itemsMap).map(t=>this._getAllDescendentPaths(e+t).then(e=>{for(let t=0,n=e.length;tr)}):Promise.resolve([e])}_getInternals(){return{getLatest:c,makeNode:l,isOutdated:h}}}u.applyMixins(f,[i.default]),e.exports=f},function(e,t,r){"use strict";e.exports=class{constructor(){this.reset()}static _rs_init(){}get scopes(){return Object.keys(this.scopeModeMap).map(e=>({name:e,mode:this.scopeModeMap[e]}))}get scopeParameter(){return this.scopes.map(e=>`${this._scopeNameForParameter(e)}:${e.mode}`).join(" ")}claim(e,t){if("string"!=typeof e||-1!==e.indexOf("/")||0===e.length)throw new Error("Scope should be a non-empty string without forward slashes");if(!t.match(/^rw?$/))throw new Error("Mode should be either 'r' or 'rw'");this._adjustRootPaths(e),this.scopeModeMap[e]=t}get(e){return this.scopeModeMap[e]}remove(e){const t={};for(const e in this.scopeModeMap)t[e]=this.scopeModeMap[e];this.reset(),delete t[e];for(const e in t)this.claim(e,t[e])}checkPermission(e,t){const r=this.get(e);return r&&("r"===t||"rw"===r)}checkPathPermission(e,t){if(this.checkPermission("*",t))return!0;const r=this._getModuleName(e);return!!this.checkPermission(r,t)}reset(){this.rootPaths=[],this.scopeModeMap={}}_getModuleName(e){if("/"!==e[0])throw new Error("Path should start with a slash");const t=e.replace(/^\/public/,"").match(/^\/([^/]*)\//);return t?t[1]:"*"}_adjustRootPaths(e){"*"in this.scopeModeMap||"*"===e?this.rootPaths=["/"]:e in this.scopeModeMap||(this.rootPaths.push("/"+e+"/"),this.rootPaths.push("/public/"+e+"/"))}_scopeNameForParameter(e){if("*"===e.name&&this.storageType){if("2012.04"===this.storageType)return"";if(this.storageType.match(/remotestorage-0[01]/))return"root"}return e.name}setStorageType(e){this.storageType=e}}},function(e,t,r){"use strict";var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const o=r(0),i=n(r(1));e.exports=class{constructor(){this.pendingActivations=[],this.reset()}set(e,t){if("string"!=typeof e)throw new Error("path should be a string");if(!o.isFolder(e))throw new Error("path should be a folder");if(!t.match(/^(FLUSH|SEEN|ALL)$/))throw new Error("strategy should be 'FLUSH', 'SEEN', or 'ALL'");this._rootPaths[e]=t,"ALL"===t&&(this.activateHandler?this.activateHandler(e):this.pendingActivations.push(e))}enable(e){this.set(e,"ALL")}disable(e){this.set(e,"FLUSH")}onActivate(e){i.default("[Caching] Setting activate handler",e,this.pendingActivations),this.activateHandler=e;for(let t=0;t=r-this.maxAge?t.v:void 0}set(e,t){this._items[e]={v:t,t:(new Date).getTime()}}}class y{constructor(e,t){if(this.connected=!1,this.online=!0,this.addEvents(["connected","not-connected"]),this.rs=e,this.clientId=t,this._fileIdCache=new g(300),h=a.localStorageAvailable(),h){const e=a.getJSONFromLocalStorage(c);e&&this.configure(e)}}configure(e){void 0!==e.userAddress&&(this.userAddress=e.userAddress),void 0!==e.token&&(this.token=e.token);const t=function(){h&&localStorage.setItem(c,JSON.stringify({userAddress:this.userAddress,token:this.token}))},r=function(){this.connected=!1,delete this.token,h&&localStorage.removeItem(c)};this.token?(this.connected=!0,this.userAddress?(this._emit("connected"),t.apply(this)):this.info().then(e=>{this.userAddress=e.user.emailAddress,this._emit("connected"),t.apply(this)}).catch(()=>{r.apply(this),this.rs._emit("error",new Error("Could not fetch user info."))})):r.apply(this)}connect(){this.rs.setBackend("googledrive"),this.rs.authorize({authURL:"https://accounts.google.com/o/oauth2/auth",scope:"https://www.googleapis.com/auth/drive",clientId:this.clientId})}stopWaitingForToken(){this.connected||this._emit("not-connected")}get(e,t){return a.isFolder(e)?this._getFolder(p(e)):this._getFile(p(e),t)}put(e,t,r,n){const o=p(e);function i(e){if(e.status>=200&&e.status<300){const t=JSON.parse(e.responseText),r=m(t.etag);return Promise.resolve({statusCode:200,contentType:t.mimeType,revision:r})}return 412===e.status?Promise.resolve({statusCode:412,revision:"conflict"}):Promise.reject("PUT failed with status "+e.status+" ("+e.responseText+")")}return this._getFileId(o).then(e=>e?n&&"*"===n.ifNoneMatch?i({status:412}):this._updateFile(e,o,t,r,n).then(i):this._createFile(o,t,r).then(i))}delete(e,t){const r=p(e);return this._getFileId(r).then(e=>e?this._getMeta(e).then(r=>{let n;return"object"==typeof r&&"string"==typeof r.etag&&(n=m(r.etag)),t&&t.ifMatch&&t.ifMatch!==n?{statusCode:412,revision:n}:this._request("DELETE",u+"/drive/v2/files/"+e,{}).then(e=>200===e.status||204===e.status?{statusCode:200}:Promise.reject("Delete failed: "+e.status+" ("+e.responseText+")"))}):Promise.resolve({statusCode:200}))}info(){return this._request("GET","https://www.googleapis.com/drive/v2/about?fields=user",{}).then((function(e){try{const t=JSON.parse(e.responseText);return Promise.resolve(t)}catch(e){return Promise.reject(e)}}))}_updateFile(e,t,r,n,o){const i={mimeType:n},s={"Content-Type":"application/json; charset=UTF-8"};return o&&o.ifMatch&&(s["If-Match"]='"'+o.ifMatch+'"'),this._request("PUT",u+"/upload/drive/v2/files/"+e+"?uploadType=resumable",{body:JSON.stringify(i),headers:s}).then(e=>412===e.status?e:this._request("PUT",e.getResponseHeader("Location"),{body:n.match(/^application\/json/)?JSON.stringify(r):r}))}_createFile(e,t,r){return this._getParentId(e).then(n=>{const o={title:l(f(e)),mimeType:r,parents:[{kind:"drive#fileLink",id:n}]};return this._request("POST",u+"/upload/drive/v2/files?uploadType=resumable",{body:JSON.stringify(o),headers:{"Content-Type":"application/json; charset=UTF-8"}}).then(e=>this._request("POST",e.getResponseHeader("Location"),{body:r.match(/^application\/json/)?JSON.stringify(t):t}))})}_getFile(e,t){return this._getFileId(e).then(e=>this._getMeta(e).then(e=>{let r;if("object"==typeof e&&"string"==typeof e.etag&&(r=m(e.etag)),t&&t.ifNoneMatch&&r===t.ifNoneMatch)return Promise.resolve({statusCode:304});if(!e.downloadUrl){if(!e.exportLinks||!e.exportLinks["text/html"])return Promise.resolve({statusCode:200,body:"",contentType:e.mimeType,revision:r});e.mimeType+=";export=text/html",e.downloadUrl=e.exportLinks["text/html"]}return this._request("GET",e.downloadUrl,{responseType:"arraybuffer"}).then(t=>a.getTextFromArrayBuffer(t.response,"UTF-8").then((function(n){let o=n;if(e.mimeType.match(/^application\/json/))try{o=JSON.parse(o)}catch(e){}else a.shouldBeTreatedAsBinary(n,e.mimeType)&&(o=t.response);return{statusCode:200,body:o,contentType:e.mimeType,revision:r}})))}))}_getFolder(e){return this._getFileId(e).then(t=>{let r,n,o;if(!t)return Promise.resolve({statusCode:404});const i="'"+t+"' in parents";return this._request("GET",u+"/drive/v2/files?q="+encodeURIComponent(i)+"&fields="+encodeURIComponent("items(downloadUrl,etag,fileSize,id,mimeType,title,labels)")+"&maxResults=1000&trashed=false",{}).then(t=>{var i;if(200!==t.status)return Promise.reject("request failed or something: "+t.status);try{r=JSON.parse(t.responseText)}catch(e){return Promise.reject("non-JSON response from GoogleDrive")}o={};for(const t of r.items)null!==(i=t.labels)&&void 0!==i&&i.trashed||(n=m(t.etag),"application/vnd.google-apps.folder"===t.mimeType?(this._fileIdCache.set(e+a.cleanPath(t.title)+"/",t.id),o[t.title+"/"]={ETag:n}):(this._fileIdCache.set(e+a.cleanPath(t.title),t.id),o[t.title]={ETag:n,"Content-Type":t.mimeType,"Content-Length":t.fileSize}));return Promise.resolve({statusCode:200,body:o,contentType:"application/json; charset=UTF-8",revision:void 0})})})}_getParentId(e){const t=d(e);return this._getFileId(t).then(e=>e?Promise.resolve(e):this._createFolder(t))}_createFolder(e){return this._getParentId(e).then(t=>this._request("POST",u+"/drive/v2/files",{body:JSON.stringify({title:l(f(e)),mimeType:"application/vnd.google-apps.folder",parents:[{id:t}]}),headers:{"Content-Type":"application/json; charset=UTF-8"}}).then(e=>{const t=JSON.parse(e.responseText);return Promise.resolve(t.id)}))}_getFileId(e){let t;return"/"===e?Promise.resolve("root"):(t=this._fileIdCache.get(e))?Promise.resolve(t):this._getFolder(d(e)).then(()=>(t=this._fileIdCache.get(e),t?Promise.resolve(t):"/"===e.substr(-1)?this._createFolder(e).then(()=>this._getFileId(e)):Promise.resolve()))}_getMeta(e){return this._request("GET",u+"/drive/v2/files/"+e,{}).then((function(t){return 200===t.status?Promise.resolve(JSON.parse(t.responseText)):Promise.reject("request (getting metadata for "+e+") failed with status: "+t.status)}))}_request(e,t,r){return r.headers||(r.headers={}),r.headers.Authorization="Bearer "+this.token,this.rs._emit("wire-busy",{method:e,isFolder:a.isFolder(t)}),i.default.request.call(this,e,t,r).then(r=>r&&401===r.status?void this.connect():(this.online||(this.online=!0,this.rs._emit("network-online")),this.rs._emit("wire-done",{method:e,isFolder:a.isFolder(t),success:!0}),Promise.resolve(r)),r=>(this.online&&(this.online=!1,this.rs._emit("network-offline")),this.rs._emit("wire-done",{method:e,isFolder:a.isFolder(t),success:!1}),Promise.reject(r)))}static _rs_init(e){const t=e.apiKeys.googledrive;var r;t&&(e.googledrive=new y(e,t.clientId),"googledrive"===e.backend&&(e._origRemote=e.remote,e.remote=e.googledrive,(r=e)._origBaseClientGetItemURL||(r._origBaseClientGetItemURL=o.default.prototype.getItemURL,o.default.prototype.getItemURL=function(){throw new Error("getItemURL is not implemented for Google Drive yet")})))}static _rs_supported(){return!0}static _rs_cleanup(e){var t;e.setBackend(void 0),e._origRemote&&(e.remote=e._origRemote,delete e._origRemote),(t=e)._origBaseClientGetItemURL&&(o.default.prototype.getItemURL=t._origBaseClientGetItemURL,delete t._origBaseClientGetItemURL)}}a.applyMixins(y,[s.default]),e.exports=y},function(e,t,r){"use strict";var n=this&&this.__awaiter||function(e,t,r,n){return new(r||(r=Promise))((function(o,i){function s(e){try{u(n.next(e))}catch(e){i(e)}}function a(e){try{u(n.throw(e))}catch(e){i(e)}}function u(e){var t;e.done?o(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(s,a)}u((n=n.apply(e,t||[])).next())}))},o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const i=o(r(2)),s=o(r(8)),a=o(r(7)),u=o(r(26)),c=o(r(9)),h=o(r(4)),l=r(0);let d;const f="remotestorage:dropbox";function p(e){return l.cleanPath("/remotestorage/"+e).replace(/\/$/,"")}function m(e,t){return new RegExp("^"+t.join("\\/")+"(\\/|$)").test(e.error_summary)}function g(e){return e instanceof ArrayBuffer||s.default.isArrayBufferView(e)}class y{constructor(e){if(this.rs=e,this.connected=!1,this.online=!0,this._initialFetchDone=!1,this.addEvents(["connected","not-connected"]),this.clientId=e.apiKeys.dropbox.appKey,this._revCache=new u.default("rev"),this._fetchDeltaCursor=null,this._fetchDeltaPromise=null,this._itemRefs={},d=l.localStorageAvailable(),d){const e=l.getJSONFromLocalStorage(f);e&&this.configure(e),this._itemRefs=l.getJSONFromLocalStorage(`${f}:shares`)||{}}this.connected&&setTimeout(this._emit.bind(this),0,"connected")}connect(){this.rs.setBackend("dropbox"),this.token?b(this.rs):this.rs.authorize({authURL:"https://www.dropbox.com/oauth2/authorize",scope:"",clientId:this.clientId})}configure(e){void 0!==e.userAddress&&(this.userAddress=e.userAddress),void 0!==e.token&&(this.token=e.token);const t=function(){d&&localStorage.setItem(f,JSON.stringify({userAddress:this.userAddress,token:this.token}))},r=function(){this.connected=!1,d&&localStorage.removeItem(f)};this.token?(this.connected=!0,this.userAddress?(this._emit("connected"),t.apply(this)):this.info().then(function(e){this.userAddress=e.email,this._emit("connected"),t.apply(this)}.bind(this)).catch(function(){r.apply(this),this.rs._emit("error",new Error("Could not fetch user info."))}.bind(this))):r.apply(this)}stopWaitingForToken(){this.connected||this._emit("not-connected")}_getFolder(e){const t=this._revCache,r=r=>{let o;if(200!==r.status&&409!==r.status)return Promise.reject("Unexpected response status: "+r.status);try{o=JSON.parse(r.responseText)}catch(e){return Promise.reject(e)}if(409===r.status)return m(o,["path","not_found"])?Promise.resolve({}):Promise.reject(new Error("API returned an error: "+o.error_summary));const i=o.entries.reduce((r,n)=>{const o="folder"===n[".tag"],i=n.path_lower.split("/").slice(-1)[0]+(o?"/":"");return o?r[i]={ETag:t.get(e+i)}:(r[i]={ETag:n.rev},this._revCache.set(e+i,n.rev)),r},{});return o.has_more?n(o.cursor).then((function(e){return Object.assign(i,e)})):Promise.resolve(i)},n=e=>{const t={body:{cursor:e}};return this._request("POST","https://api.dropboxapi.com/2/files/list_folder/continue",t).then(r)};return this._request("POST","https://api.dropboxapi.com/2/files/list_folder",{body:{path:p(e)}}).then(r).then((function(r){return Promise.resolve({statusCode:200,body:r,contentType:"application/json; charset=UTF-8",revision:t.get(e)})}))}get(e,t){if(!this.connected)return Promise.reject("not connected (path: "+e+")");const r=this._revCache.get(e);if(null===r)return Promise.resolve({statusCode:404});if(t&&t.ifNoneMatch){if(!this._initialFetchDone)return this.fetchDelta().then(()=>this.get(e,t));if(r&&r===t.ifNoneMatch)return Promise.resolve({statusCode:304})}if("/"===e.substr(-1))return this._getFolder(e);const n={headers:{"Dropbox-API-Arg":JSON.stringify({path:p(e)})},responseType:"arraybuffer"};return t&&t.ifNoneMatch&&(n.headers["If-None-Match"]=t.ifNoneMatch),this._request("GET","https://content.dropboxapi.com/2/files/download",n).then(t=>{const r=t.status;let n,o,i,s;return 200!==r&&409!==r?Promise.resolve({statusCode:r}):(n=t.getResponseHeader("Dropbox-API-Result"),l.getTextFromArrayBuffer(t.response,"UTF-8").then(a=>{o=a,409===r&&(n=o);try{n=JSON.parse(n)}catch(e){return Promise.reject(e)}if(409===r)return m(n,["path","not_found"])?{statusCode:404}:Promise.reject(new Error('API error while downloading file ("'+e+'"): '+n.error_summary));if(i=t.getResponseHeader("Content-Type"),s=n.rev,this._revCache.set(e,s),this._shareIfNeeded(e),l.shouldBeTreatedAsBinary(a,i))o=t.response;else try{o=JSON.parse(o),i="application/json; charset=UTF-8"}catch(e){}return{statusCode:r,body:o,contentType:i,revision:s}}))})}put(e,t,r,n){if(!this.connected)throw new Error("not connected (path: "+e+")");const o=this._revCache.get(e);if(n&&n.ifMatch&&o&&o!==n.ifMatch)return Promise.resolve({statusCode:412,revision:o});if(n&&"*"===n.ifNoneMatch&&o&&"rev"!==o)return Promise.resolve({statusCode:412,revision:o});if(!r.match(/charset=/)&&g(t)&&(r+="; charset=binary"),t.length>157286400)return Promise.reject(new Error("Cannot upload file larger than 150MB"));let i;const s=n&&(n.ifMatch||"*"===n.ifNoneMatch),a={body:t,contentType:r,path:e};return i=s?this._getMetadata(e).then(e=>n&&"*"===n.ifNoneMatch&&e?Promise.resolve({statusCode:412,revision:e.rev}):n&&n.ifMatch&&e&&e.rev!==n.ifMatch?Promise.resolve({statusCode:412,revision:e.rev}):this._uploadSimple(a)):this._uploadSimple(a),i.then(t=>(this._shareIfNeeded(e),t))}delete(e,t){if(!this.connected)throw new Error("not connected (path: "+e+")");const r=this._revCache.get(e);return t&&t.ifMatch&&r&&t.ifMatch!==r?Promise.resolve({statusCode:412,revision:r}):t&&t.ifMatch?this._getMetadata(e).then(r=>t&&t.ifMatch&&r&&r.rev!==t.ifMatch?Promise.resolve({statusCode:412,revision:r.rev}):this._deleteSimple(e)):this._deleteSimple(e)}_shareIfNeeded(e){e.match(/^\/public\/.*[^/]$/)&&void 0===this._itemRefs[e]&&this.share(e)}share(e){const t={body:{path:p(e)}};return this._request("POST","https://api.dropboxapi.com/2/sharing/create_shared_link_with_settings",t).then(t=>{if(200!==t.status&&409!==t.status)return Promise.reject(new Error("Invalid response status:"+t.status));let r;try{r=JSON.parse(t.responseText)}catch(e){return Promise.reject(new Error("Invalid response body: "+t.responseText))}return 409===t.status?m(r,["shared_link_already_exists"])?this._getSharedLink(e):Promise.reject(new Error("API error: "+r.error_summary)):Promise.resolve(r.url)}).then(t=>(this._itemRefs[e]=t,d&&localStorage.setItem(f+":shares",JSON.stringify(this._itemRefs)),Promise.resolve(t)),t=>(t.message='Sharing Dropbox file or folder ("'+e+'") failed: '+t.message,Promise.reject(t)))}info(){return this._request("POST","https://api.dropboxapi.com/2/users/get_current_account",{}).then((function(e){let t=e.responseText;try{t=JSON.parse(t)}catch(e){return Promise.reject(new Error("Could not query current account info: Invalid API response: "+t))}return Promise.resolve({email:t.email})}))}_request(e,t,r){return r.headers||(r.headers={}),r.headers.Authorization="Bearer "+this.token,"object"!=typeof r.body||g(r.body)||(r.body=JSON.stringify(r.body),r.headers["Content-Type"]="application/json; charset=UTF-8"),this.rs._emit("wire-busy",{method:e,isFolder:l.isFolder(t)}),s.default.request.call(this,e,t,r).then(n=>n&&503===n.status?(this.online&&(this.online=!1,this.rs._emit("network-offline")),setTimeout(this._request(e,t,r),3210)):(this.online||(this.online=!0,this.rs._emit("network-online")),this.rs._emit("wire-done",{method:e,isFolder:l.isFolder(t),success:!0}),Promise.resolve(n)),r=>(this.online&&(this.online=!1,this.rs._emit("network-offline")),this.rs._emit("wire-done",{method:e,isFolder:l.isFolder(t),success:!1}),Promise.reject(r)))}fetchDelta(...e){if(this._fetchDeltaPromise)return this._fetchDeltaPromise;const t=r=>{let n,o="https://api.dropboxapi.com/2/files/list_folder";return"string"==typeof r?(o+="/continue",n={cursor:r}):n={path:"/remotestorage",recursive:!0,include_deleted:!0},this._request("POST",o,{body:n}).then(n=>{if(401===n.status)return this.rs._emit("error",new h.default),Promise.resolve(e);if(200!==n.status&&409!==n.status)return Promise.reject(new Error("Invalid response status: "+n.status));let o;try{o=JSON.parse(n.responseText)}catch(e){return Promise.reject(new Error("Invalid response body: "+n.responseText))}if(409===n.status){if(!m(o,["path","not_found"]))return Promise.reject(new Error("API returned an error: "+o.error_summary));o={cursor:null,entries:[],has_more:!1}}if(r||this._revCache.deactivatePropagation(),o.entries.forEach(e=>{const t=e.path_lower.substr("/remotestorage".length);"deleted"===e[".tag"]?(this._revCache.delete(t),this._revCache.delete(t+"/")):"file"===e[".tag"]&&this._revCache.set(t,e.rev)}),this._fetchDeltaCursor=o.cursor,o.has_more)return t(o.cursor);this._revCache.activatePropagation(),this._initialFetchDone=!0}).catch(e=>"timeout"===e||e instanceof ProgressEvent?Promise.resolve():Promise.reject(e))};return this._fetchDeltaPromise=t(this._fetchDeltaCursor).catch(e=>("object"==typeof e&&"message"in e?e.message="Dropbox: fetchDelta: "+e.message:e=`Dropbox: fetchDelta: ${e}`,this._fetchDeltaPromise=null,Promise.reject(e))).then(()=>(this._fetchDeltaPromise=null,Promise.resolve(e))),this._fetchDeltaPromise}_getMetadata(e){const t={path:p(e)};return this._request("POST","https://api.dropboxapi.com/2/files/get_metadata",{body:t}).then(e=>{if(200!==e.status&&409!==e.status)return Promise.reject(new Error("Invalid response status:"+e.status));let t;try{t=JSON.parse(e.responseText)}catch(t){return Promise.reject(new Error("Invalid response body: "+e.responseText))}return 409===e.status?m(t,["path","not_found"])?Promise.resolve():Promise.reject(new Error("API error: "+t.error_summary)):Promise.resolve(t)}).then(void 0,t=>(t.message='Could not load metadata for file or folder ("'+e+'"): '+t.message,Promise.reject(t)))}_uploadSimple(e){const t={path:p(e.path),mode:{".tag":"overwrite",update:void 0},mute:!0};return e.ifMatch&&(t.mode={".tag":"update",update:e.ifMatch}),this._request("POST","https://content.dropboxapi.com/2/files/upload",{body:e.body,headers:{"Content-Type":"application/octet-stream","Dropbox-API-Arg":JSON.stringify(t)}}).then(t=>{if(200!==t.status&&409!==t.status)return Promise.resolve({statusCode:t.status});let r=t.responseText;try{r=JSON.parse(r)}catch(e){return Promise.reject(new Error("Invalid API result: "+r))}return 409===t.status?m(r,["path","conflict"])?this._getMetadata(e.path).then((function(e){return Promise.resolve({statusCode:412,revision:e.rev})})):Promise.reject(new Error("API error: "+r.error_summary)):(this._revCache.set(e.path,r.rev),Promise.resolve({statusCode:t.status,revision:r.rev}))})}_deleteSimple(e){const t={path:p(e)};return this._request("POST","https://api.dropboxapi.com/2/files/delete",{body:t}).then(e=>{if(200!==e.status&&409!==e.status)return Promise.resolve({statusCode:e.status});let t=e.responseText;try{t=JSON.parse(t)}catch(e){return Promise.reject(new Error("Invalid response body: "+t))}return 409===e.status?m(t,["path_lookup","not_found"])?Promise.resolve({statusCode:404}):Promise.reject(new Error("API error: "+t.error_summary)):Promise.resolve({statusCode:200})}).then(t=>(200!==t.statusCode&&404!==t.statusCode||(this._revCache.delete(e),delete this._itemRefs[e]),Promise.resolve(t)),t=>(t.message='Could not delete Dropbox file or folder ("'+e+'"): '+t.message,Promise.reject(t)))}_getSharedLink(e){return n(this,void 0,void 0,(function*(){const t={body:{path:p(e),direct_only:!0}};return this._request("POST","https://api.dropbox.com/2/sharing/list_shared_links",t).then(e=>{if(200!==e.status&&409!==e.status)return Promise.reject(new Error("Invalid response status: "+e.status));let t;try{t=JSON.parse(e.responseText)}catch(t){return Promise.reject(new Error("Invalid response body: "+e.responseText))}return 409===e.status?Promise.reject(new Error("API error: "+e.error_summary)):t.links.length?Promise.resolve(t.links[0].url):Promise.reject(new Error("No links returned"))},t=>(t.message='Could not get link to a shared file or folder ("'+e+'"): '+t.message,Promise.reject(t)))}))}static _rs_init(e){d=l.localStorageAvailable(),e.apiKeys.dropbox&&(e.dropbox=new y(e)),"dropbox"===e.backend&&b(e)}static _rs_supported(){return!0}static _rs_cleanup(e){!function(e){(function(e){e._origRemote&&(e.remote=e._origRemote,delete e._origRemote)})(e),function(e){if(!e._dropboxOrigSync)return;e.sync.sync=e._dropboxOrigSync,delete e._dropboxOrigSync}(e),function(e){if(!e._origBaseClientGetItemURL)return;a.default.prototype.getItemURL=e._origBaseClientGetItemURL,delete e._origBaseClientGetItemURL}(e),_(e)}(e),d&&localStorage.removeItem(f),e.setBackend(void 0)}}function v(e,...t){e._dropboxOrigSync||(e._dropboxOrigSync=e.sync.sync.bind(e.sync),e.sync.sync=function(){return this.dropbox.fetchDelta(e,...t).then(e._dropboxOrigSync,(function(t){e._emit("error",new c.default(t)),e._emit("sync-done")}))}.bind(e))}function _(e){e._dropboxOrigSyncCycle&&(e.syncCycle=e._dropboxOrigSyncCycle,delete e._dropboxOrigSyncCycle)}function b(e){!function(e){e._origRemote||(e._origRemote=e.remote,e.remote=e.dropbox)}(e),e.sync?v(e):function(e,...t){e._dropboxOrigSyncCycle||(e._dropboxOrigSyncCycle=e.syncCycle,e.syncCycle=()=>{if(!e.sync)throw new Error("expected sync to be initialized by now");v(e),e._dropboxOrigSyncCycle(e,...t),_(e)})}(e),function(e){e._origBaseClientGetItemURL||(e._origBaseClientGetItemURL=a.default.prototype.getItemURL,a.default.prototype.getItemURL=function(){throw new Error("getItemURL is not implemented for Dropbox yet")})}(e)}l.applyMixins(y,[i.default]),e.exports=y},function(e,t,r){"use strict";var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const o=n(r(27)),i=n(r(1)),s=r(0);let a,u;let c={};const h=function(e){return new Promise((t,r)=>{if(e in c)return t(c[e]);return new o.default({tls_only:!1,uri_fallback:!0,request_timeout:5e3}).lookup(e,(function(n,o){if(n)return r(n);if("object"!=typeof o.idx.links.remotestorage||"number"!=typeof o.idx.links.remotestorage.length||o.idx.links.remotestorage.length<=0)return i.default("[Discover] WebFinger record for "+e+" does not have remotestorage defined in the links section ",JSON.stringify(o.json)),r("WebFinger record for "+e+" does not have remotestorage defined in the links section.");const s=o.idx.links.remotestorage[0],a=s.properties["http://tools.ietf.org/html/rfc6749#section-4.2"]||s.properties["auth-endpoint"],h=s.properties["http://remotestorage.io/spec/version"]||s.type;return c[e]={href:s.href,storageApi:h,authURL:a,properties:s.properties},u&&(localStorage["remotestorage:discover"]=JSON.stringify({cache:c})),t(c[e])}))})};(h.DiscoveryError=function(e){this.name="DiscoveryError",this.message=e,this.stack=(new Error).stack}).prototype=Object.create(Error.prototype),h.DiscoveryError.prototype.constructor=h.DiscoveryError,h._rs_init=function(){if(u=s.localStorageAvailable(),u)try{const e=JSON.parse(localStorage["remotestorage:discover"]);c=e.cache}catch(e){}},h._rs_supported=function(){return a=Object.prototype.hasOwnProperty.call(s.globalContext,"XMLHttpRequest"),a},h._rs_cleanup=function(){u&&delete localStorage["remotestorage:discover"]},e.exports=h},function(e,t,r){"use strict";const n=(this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}})(r(2));class o{constructor(){this.addEvents(["background","foreground"]),this.mode="undefined"!=typeof window?"browser":"node","browser"===this.mode&&(this.setBrowserPrefixedNames(),document.addEventListener(this.visibilityChangeEvent,this.setVisibility.bind(this),!1),this.setVisibility())}setBrowserPrefixedNames(){"browser"===this.mode&&(void 0!==document.hidden?(this.hiddenProperty="hidden",this.visibilityChangeEvent="visibilitychange"):void 0!==document.mozHidden?(this.hiddenProperty="mozHidden",this.visibilityChangeEvent="mozvisibilitychange"):void 0!==document.msHidden?(this.hiddenProperty="msHidden",this.visibilityChangeEvent="msvisibilitychange"):void 0!==document.webkitHidden&&(this.hiddenProperty="webkitHidden",this.visibilityChangeEvent="webkitvisibilitychange"))}setVisibility(){document[this.hiddenProperty]?this.goBackground():this.goForeground()}isBrowser(){return"browser"===this.mode}isNode(){return"node"===this.mode}goBackground(){this._emit("background")}goForeground(){this._emit("foreground")}static _rs_init(){}static _rs_cleanup(){}}r(0).applyMixins(o,[n.default]),e.exports=o},function(e,t,r){e.exports=r(18)},function(e,t,r){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,r,n){void 0===n&&(n=r),Object.defineProperty(e,n,{enumerable:!0,get:function(){return t[r]}})}:function(e,t,r,n){void 0===n&&(n=r),e[n]=t[r]}),o=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),i=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var r in e)"default"!==r&&Object.hasOwnProperty.call(e,r)&&n(t,e,r);return o(t,e),t},s=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const a=s(r(3)),u=s(r(1)),c=r(0),h=s(r(11)),l=s(r(6)),d=s(r(7)),f=s(r(12)),p=s(r(2)),m=s(r(13)),g=s(r(14)),y=s(r(15)),v=s(r(9)),_=s(r(4)),b=s(r(29)),w=i(r(0)),P=c.getGlobalContext();let E;function T(e){return 403!==e.statusCode&&401!==e.statusCode||this._emit("error",new _.default),Promise.resolve(e)}function A(e){return"number"==typeof e&&e>=2e3&&e<=36e5}class R{constructor(e){this._pending=[],this._cleanups=[],this._pathHandlers={change:{}},this.apiKeys={},this._init=b.default.loadFeatures,this.features=b.default.features,this.loadFeature=b.default.loadFeature,this.featureSupported=b.default.featureSupported,this.featureDone=b.default.featureDone,this.featuresDone=b.default.featuresDone,this.featuresLoaded=b.default.featuresLoaded,this.featureInitialized=b.default.featureInitialized,this.featureFailed=b.default.featureFailed,this.hasFeature=b.default.hasFeature,this._setCachingModule=b.default._setCachingModule,this._collectCleanupFunctions=b.default._collectCleanupFunctions,this._fireReady=b.default._fireReady,this.initFeature=b.default.initFeature,"object"==typeof e&&c.extend(a.default,e),this.addEvents(["ready","authing","connecting","connected","disconnected","not-connected","conflict","error","features-loaded","sync-interval-change","sync-req-done","sync-done","wire-busy","wire-done","network-offline","network-online"]),this._setGPD({get:this._pendingGPD("get"),put:this._pendingGPD("put"),delete:this._pendingGPD("delete")}),E=c.localStorageAvailable(),E&&(this.apiKeys=c.getJSONFromLocalStorage("remotestorage:api-keys")||{},this.setBackend(localStorage.getItem("remotestorage:backend")||"remotestorage"));const t=this.on;this.on=function(e,r){if(this._allLoaded)switch(e){case"features-loaded":setTimeout(r,0);break;case"ready":this.remote&&setTimeout(r,0);break;case"connected":this.remote&&this.remote.connected&&setTimeout(r,0);break;case"not-connected":this.remote&&!this.remote.connected&&setTimeout(r,0)}return t.call(this,e,r)},this._init(),this.fireInitial=function(){this.local&&setTimeout(this.local.fireInitial.bind(this.local),0)}.bind(this),this.on("ready",this.fireInitial.bind(this)),this.loadModules()}get connected(){return this.remote.connected}loadModules(){a.default.modules.forEach(this.addModule.bind(this))}authorize(e){if(this.access.setStorageType(this.remote.storageApi),void 0===e.scope&&(e.scope=this.access.scopeParameter),P.cordova)e.redirectUri=a.default.cordovaRedirectUri;else{const t=l.default.getLocation();let r=t.origin;"/"!==t.pathname&&(r+=t.pathname),e.redirectUri=r}void 0===e.clientId&&(e.clientId=e.redirectUri.match(/^(https?:\/\/[^/]+)/)[0]),l.default.authorize(this,e)}impliedauth(e,t){e=e||this.remote.storageApi,t=t||String(document.location),u.default("ImpliedAuth proceeding due to absent authURL; storageApi = "+e+" redirectUri = "+t),this.remote.configure({token:l.default.IMPLIED_FAKE_TOKEN}),document.location.href=t}connect(e,t){if(this.setBackend("remotestorage"),e.indexOf("@")<0&&!e.match(/^(https?:\/\/)?[^\s\/$\.?#]+\.[^\s]*$/))return void this._emit("error",new R.DiscoveryError("Not a valid user address or URL."));if(e.indexOf("@")<0&&!e.match(/^https?:\/\//)&&(e=`https://${e}`),P.cordova){if("string"!=typeof a.default.cordovaRedirectUri)return void this._emit("error",new R.DiscoveryError("Please supply a custom HTTPS redirect URI for your Cordova app"));if(!P.cordova.InAppBrowser)return void this._emit("error",new R.DiscoveryError("Please include the InAppBrowser Cordova plugin to enable OAuth"))}this.remote.configure({userAddress:e}),this._emit("connecting");const r=setTimeout(()=>{this._emit("error",new R.DiscoveryError("No storage information found for this user address."))},a.default.discoveryTimeout);y.default(e).then(n=>{if(clearTimeout(r),this._emit("authing"),n.userAddress=e,this.remote.configure(n),!this.remote.connected)if(n.authURL)if(void 0===t)this.authorize({authURL:n.authURL});else{if("string"!=typeof t)throw new Error("Supplied bearer token must be a string");u.default("Skipping authorization sequence and connecting with known token"),this.remote.configure({token:t})}else this.impliedauth()},()=>{clearTimeout(r),this._emit("error",new R.DiscoveryError("No storage information found for this user address."))})}reconnect(){this.remote.configure({token:null}),"remotestorage"===this.backend?this.connect(this.remote.userAddress):this.remote.connect()}disconnect(){this.remote&&this.remote.configure({userAddress:null,href:null,storageApi:null,token:null,properties:null}),this._setGPD({get:this._pendingGPD("get"),put:this._pendingGPD("put"),delete:this._pendingGPD("delete")});const e=this._cleanups.length;let t=0;const r=()=>{t++,t>=e&&(this._init(),this._emit("disconnected"))};e>0?this._cleanups.forEach(e=>{const t=e(this);"object"==typeof t&&"function"==typeof t.then?t.then(r):r()}):r()}setBackend(e){this.backend=e,E&&(e?localStorage.setItem("remotestorage:backend",e):localStorage.removeItem("remotestorage:backend"))}onChange(e,t){this._pathHandlers.change[e]||(this._pathHandlers.change[e]=[]),this._pathHandlers.change[e].push(t)}enableLog(){a.default.logging=!0}disableLog(){a.default.logging=!1}log(...e){u.default.apply(R,e)}setApiKeys(e){const t=[S.GOOGLE,S.DROPBOX];if("object"!=typeof e||!Object.keys(e).every(e=>t.includes(e)))return console.error("setApiKeys() was called with invalid arguments"),!1;Object.keys(e).forEach(t=>{const r=e[t];if(r){switch(t){case S.DROPBOX:this.apiKeys[S.DROPBOX]={appKey:r},void 0!==this.dropbox&&this.dropbox.clientId===r||g.default._rs_init(this);break;case S.GOOGLE:this.apiKeys[S.GOOGLE]={clientId:r},void 0!==this.googledrive&&this.googledrive.clientId===r||m.default._rs_init(this)}return!0}delete this.apiKeys[t]}),E&&localStorage.setItem("remotestorage:api-keys",JSON.stringify(this.apiKeys))}setCordovaRedirectUri(e){if("string"!=typeof e||!e.match(/http(s)?:\/\//))throw new Error("Cordova redirect URI must be a URI string");a.default.cordovaRedirectUri=e}_setGPD(e,t){function r(e){return function(...r){return e.apply(t,r).then(T.bind(this))}}this.get=r(e.get),this.put=r(e.put),this.delete=r(e.delete)}_pendingGPD(e){return(...t)=>{const r=Array.prototype.slice.call(t);return new Promise((t,n)=>{this._pending.push({method:e,args:r,promise:{resolve:t,reject:n}})})}}_processPending(){this._pending.forEach(e=>{try{this[e.method](...e.args).then(e.promise.resolve,e.promise.reject)}catch(t){e.promise.reject(t)}}),this._pending=[]}_bindChange(e){e.on("change",this._dispatchEvent.bind(this,"change"))}_dispatchEvent(e,t){Object.keys(this._pathHandlers[e]).forEach(r=>{const n=r.length;t.path.substr(0,n)===r&&this._pathHandlers[e][r].forEach(e=>{const n={};for(const e in t)n[e]=t[e];n.relativePath=t.path.replace(new RegExp("^"+r),"");try{e(n)}catch(e){console.error("'change' handler failed: ",e,e.stack),this._emit("error",e)}})})}scope(e){if("string"!=typeof e)throw"Argument 'path' of baseClient.scope must be a string";return this.access.checkPathPermission(e,"r")||console.warn("WARNING: Please use remoteStorage.access.claim() to ask for access permissions first: https://remotestoragejs.readthedocs.io/en/latest/js-api/access.html#claim"),new d.default(this,e)}getSyncInterval(){return a.default.syncInterval}setSyncInterval(e){if(!A(e))throw e+" is not a valid sync interval";const t=a.default.syncInterval;a.default.syncInterval=e,this._emit("sync-interval-change",{oldValue:t,newValue:e})}getBackgroundSyncInterval(){return a.default.backgroundSyncInterval}setBackgroundSyncInterval(e){if(!A(e))throw e+" is not a valid sync interval";const t=a.default.backgroundSyncInterval;a.default.backgroundSyncInterval=e,this._emit("sync-interval-change",{oldValue:t,newValue:e})}getCurrentSyncInterval(){return a.default.isBackground?a.default.backgroundSyncInterval:a.default.syncInterval}getRequestTimeout(){return a.default.requestTimeout}setRequestTimeout(e){if("number"!=typeof e)throw e+" is not a valid request timeout";a.default.requestTimeout=e}syncCycle(){this.sync&&!this.sync.stopped&&(this.on("sync-done",()=>{this.sync&&!this.sync.stopped&&(this._syncTimer&&(clearTimeout(this._syncTimer),this._syncTimer=void 0),this._syncTimer=setTimeout(this.sync.sync.bind(this.sync),this.getCurrentSyncInterval()))}),this.sync.sync())}startSync(){return a.default.cache?(this.sync.stopped=!1,this.syncStopped=!1,this.sync.sync()):(console.warn("Nothing to sync, because caching is disabled."),Promise.resolve())}stopSync(){clearTimeout(this._syncTimer),this._syncTimer=void 0,this.sync?this.sync.stopped=!0:this.syncStopped=!0}addModule(e){const t=e.name,r=e.builder;if(Object.defineProperty(this,t,{configurable:!0,get:function(){const e=this._loadModule(t,r);return Object.defineProperty(this,t,{value:e}),e}}),-1!==t.indexOf("-")){const e=t.replace(/\-[a-z]/g,(function(e){return e[1].toUpperCase()}));Object.defineProperty(this,e,{get:function(){return this[t]}})}}_loadModule(e,t){if(t){return t(new d.default(this,"/"+e+"/"),new d.default(this,"/public/"+e+"/")).exports}throw"Unknown module: "+e}}var S;R.Authorize=l.default,R.SyncError=v.default,R.Unauthorized=_.default,R.DiscoveryError=y.default.DiscoveryError,R.util=w,Object.defineProperty(R.prototype,"access",{get:function(){const e=new h.default;return Object.defineProperty(this,"access",{value:e}),e},configurable:!0}),Object.defineProperty(R.prototype,"caching",{configurable:!0,get:function(){const e=new f.default;return Object.defineProperty(this,"caching",{value:e}),e}}),c.applyMixins(R,[p.default]),function(e){e.GOOGLE="googledrive",e.DROPBOX="dropbox"}(S||(S={})),e.exports=R},function(e,t,r){"use strict";(function(e){ +/*! remotestorage.js 2.0.0-beta.5, https://remotestorage.io, MIT licensed */ +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("RemoteStorage",[],t):"object"==typeof exports?exports.RemoteStorage=t():e.RemoteStorage=t()}(this,(function(){return function(e){var t={};function r(o){if(t[o])return t[o].exports;var n=t[o]={i:o,l:!1,exports:{}};return e[o].call(n.exports,n,n.exports,r),n.l=!0,n.exports}return r.m=e,r.c=t,r.d=function(e,t,o){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(r.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)r.d(o,n,function(t){return e[t]}.bind(null,n));return o},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=18)}([function(e,t,r){"use strict";(function(e,r){var o=this&&this.__awaiter||function(e,t,r,o){return new(r||(r=Promise))((function(n,i){function s(e){try{u(o.next(e))}catch(e){i(e)}}function a(e){try{u(o.throw(e))}catch(e){i(e)}}function u(e){var t;e.done?n(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(s,a)}u((o=o.apply(e,t||[])).next())}))};Object.defineProperty(t,"__esModule",{value:!0}),t.applyMixins=t.generateCodeVerifier=t.toBase64=t.getTextFromArrayBuffer=t.shouldBeTreatedAsBinary=t.getJSONFromLocalStorage=t.localStorageAvailable=t.pathsFromRoot=t.deepClone=t.equal=t.bindAll=t.cleanPath=t.baseName=t.isDocument=t.isFolder=t.containingFolder=t.extend=t.getGlobalContext=t.globalContext=t.logError=void 0;t.logError=e=>{"string"==typeof e?console.error(e):console.error(e.message,e.stack)},t.globalContext="undefined"!=typeof window?window:"object"==typeof self?self:e;t.getGlobalContext=()=>"undefined"!=typeof window?window:"object"==typeof self?self:e;t.extend=(...e)=>{const t=e[0];return Array.prototype.slice.call(e,1).forEach((function(e){for(const r in e)t[r]=e[r]})),t};t.containingFolder=e=>{if(""===e)return"/";if(!e)throw"Path not given!";return e.replace(/\/+/g,"/").replace(/[^\/]+\/?$/,"")};t.isFolder=e=>"/"===e.slice(-1);t.isDocument=e=>!(0,t.isFolder)(e);t.baseName=e=>{const r=e.split("/");return(0,t.isFolder)(e)?r[r.length-2]+"/":r[r.length-1]};t.cleanPath=e=>e.replace(/\/+/g,"/").split("/").map(encodeURIComponent).join("/").replace(/'/g,"%27");t.bindAll=e=>{for(const t in this)"function"==typeof e[t]&&(e[t]=e[t].bind(e))};t.equal=(e,r,o=[])=>{let n;if(typeof e!=typeof r)return!1;if("number"==typeof e||"boolean"==typeof e||"string"==typeof e)return e===r;if("function"==typeof e)return e.toString()===r.toString();if(e instanceof ArrayBuffer&&r instanceof ArrayBuffer&&(e=new Uint8Array(e),r=new Uint8Array(r)),e instanceof Array){if(e.length!==r.length)return!1;for(let n=0,i=e.length;n=0)continue;i=o.slice(),i.push(r[n])}if(!(0,t.equal)(e[n],r[n],i))return!1}}return!0};t.deepClone=e=>{if(void 0!==e){const t=JSON.parse(JSON.stringify(e));return function e(t,r){if("object"==typeof t&&!Array.isArray(t)&&null!==t)for(const o in t)if("object"==typeof t[o]&&null!==t[o])if("[object ArrayBuffer]"===t[o].toString()){r[o]=new ArrayBuffer(t[o].byteLength);const e=new Int8Array(t[o]);new Int8Array(r[o]).set(e)}else e(t[o],r[o])}(e,t),t}};t.pathsFromRoot=e=>{const t=[e],r=e.replace(/\/$/,"").split("/");for(;r.length>1;)r.pop(),t.push(r.join("/")+"/");return t};t.localStorageAvailable=()=>{const e=(0,t.getGlobalContext)();if(!("localStorage"in e))return!1;try{return e.localStorage.setItem("rs-check","1"),e.localStorage.removeItem("rs-check"),!0}catch(e){return!1}};t.getJSONFromLocalStorage=e=>{const r=(0,t.getGlobalContext)();try{return JSON.parse(r.localStorage.getItem(e))}catch(e){}};t.shouldBeTreatedAsBinary=(e,t)=>!!(t&&t.match(/charset=binary/)||/[\x00-\x08\x0E-\x1F\uFFFD]/.test(e));t.getTextFromArrayBuffer=(e,o)=>new Promise(n=>{if("undefined"==typeof Blob){const t=r.from(e);n(t.toString(o))}else{let r;const i=t.globalContext;if(i.BlobBuilder=i.BlobBuilder||i.WebKitBlobBuilder,void 0!==i.BlobBuilder){const t=new i.BlobBuilder;t.append(e),r=t.getBlob()}else r=new Blob([e]);const s=new FileReader;"function"==typeof s.addEventListener?s.addEventListener("loadend",(function(e){n(e.target.result)})):s.onloadend=function(e){n(e.target.result)},s.readAsText(r,o)}});t.toBase64=e=>{const o=(0,t.getGlobalContext)();return"btoa"in o?o.btoa(e):r.from(e).toString("base64")},t.generateCodeVerifier=function(e=128){return o(this,void 0,void 0,(function*(){const t=new Uint8Array(e);crypto.getRandomValues(t);const r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~",o=Array.from(t).map(e=>r[e%r.length]),n=o.join(""),i=Uint8Array.from(o.map(e=>e.charCodeAt(0))),s=yield crypto.subtle.digest("SHA-256",i),a=(u=s,btoa(String.fromCharCode.apply(null,new Uint8Array(u))).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,""));var u;crypto.getRandomValues(t);return{codeVerifier:n,codeChallenge:a,state:Array.from(t).map(e=>r[e%r.length]).join("")}}))},t.applyMixins=function(e,t){t.forEach(t=>{Object.getOwnPropertyNames(t.prototype).forEach(r=>{Object.defineProperty(e.prototype,r,Object.getOwnPropertyDescriptor(t.prototype,r))})})}}).call(this,r(6),r(20).Buffer)},function(e,t,r){"use strict";const o=(this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}})(r(3));e.exports=function(...e){o.default.logging&&console.log(...e)}},function(e,t,r){"use strict";const o=(this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}})(r(1));e.exports=class{addEvents(e){e.forEach(e=>this._addEvent(e))}addEventListener(e,t){if("string"!=typeof e)throw new Error("Argument eventName should be a string");if("function"!=typeof t)throw new Error("Argument handler should be a function");(0,o.default)("[EventHandling] Adding event listener",e),this._validateEvent(e),this._handlers[e].push(t)}on(e,t){return this.addEventListener(e,t)}removeEventListener(e,t){this._validateEvent(e);const r=this._handlers[e].length;for(let o=0;o{e.apply(this,t)})}_validateEvent(e){if(!(e in this._handlers))throw new Error("Unknown event: "+e)}_delegateEvent(e,t){t.on(e,t=>{this._emit(e,t)})}_addEvent(e){void 0===this._handlers&&(this._handlers={}),this._handlers[e]=[]}}},function(e,t,r){"use strict";const o={cache:!0,changeEvents:{local:!0,window:!1,remote:!0,conflict:!0},cordovaRedirectUri:void 0,logging:!1,modules:[],backgroundSyncInterval:6e4,disableFeatures:[],discoveryTimeout:1e4,isBackground:!1,requestTimeout:3e4,syncInterval:1e4};e.exports=o},function(e,t,r){"use strict";var o=this&&this.__awaiter||function(e,t,r,o){return new(r||(r=Promise))((function(n,i){function s(e){try{u(o.next(e))}catch(e){i(e)}}function a(e){try{u(o.throw(e))}catch(e){i(e)}}function u(e){var t;e.done?n(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(s,a)}u((o=o.apply(e,t||[])).next())}))},n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const i=n(r(1)),s=r(0),a=n(r(5)),u=r(7);let c;function h(e){const t=e||l.getLocation().href,r={};for(const[e,o]of new URL(t).searchParams)r[e]=o;const o=t.indexOf("#");if(-1===o)return r;const n=t.substring(o+1);return n.includes("=")?n.split("&").reduce((function(e,t){const r=t.split("=");if("state"===r[0]&&r[1].match(/rsDiscovery/)){let t=decodeURIComponent(r[1]);const o=t.substr(t.indexOf("rsDiscovery=")).split("&")[0].split("=")[1];e.rsDiscovery=JSON.parse(atob(o)),t=t.replace(new RegExp("&?rsDiscovery="+o),""),t.length>0&&(e.state=t)}else e[decodeURIComponent(r[0])]=decodeURIComponent(r[1]);return e}),r):r}class l{static authorize(e,t){if((0,i.default)("[Authorize] authURL = ",t.authURL,"scope = ",t.scope,"redirectUri = ",t.redirectUri,"clientId = ",t.clientId,"response_type =",t.response_type),!t.scope)throw new Error("Cannot authorize due to undefined or empty scope; did you forget to access.claim()?");if(!(0,s.localStorageAvailable)()&&"remotestorage"===e.backend){t.redirectUri+=t.redirectUri.indexOf("#")>0?"&":"#";const r={userAddress:e.remote.userAddress,href:e.remote.href,storageApi:e.remote.storageApi,properties:e.remote.properties};t.redirectUri+="rsDiscovery="+(0,s.toBase64)(JSON.stringify(r))}const r=function(e){const t=new URL(e.redirectUri);e.state||(e.state=t.hash?t.hash.substring(1):""),e.response_type||(e.response_type="token");const r=new URL(e.authURL);r.searchParams.set("redirect_uri",e.redirectUri.replace(/#.*$/,"")),r.searchParams.set("scope",e.scope),r.searchParams.set("client_id",e.clientId);for(const t of["state","response_type","code_challenge","code_challenge_method","token_access_type"]){const o=e[t];o&&r.searchParams.set(t,o)}return r.href}(t);s.globalContext.cordova?l.openWindow(r,t.redirectUri,"location=yes,clearsessioncache=yes,clearcache=yes").then(t=>{e.remote.configure({token:t.access_token})}):l.setLocation(r)}static refreshAccessToken(e,t,r){var n,s,c;return o(this,void 0,void 0,(function*(){yield t.configure({token:null,tokenType:null});const e=new URLSearchParams({grant_type:"refresh_token",client_id:t.clientId,refresh_token:r}),o=yield(0,u.requestWithTimeout)("POST",t.TOKEN_URL,{headers:{"Content-Type":"application/x-www-form-urlencoded"},body:e.toString(),responseType:"json"});if(200!==(null==o?void 0:o.status))throw yield t.configure({refreshToken:null}),new a.default("refresh token rejected:"+JSON.stringify(o.response));{(0,i.default)(`[Authorize] access token good for ${null===(n=null==o?void 0:o.response)||void 0===n?void 0:n.expires_in} seconds`);const e={token:null===(s=null==o?void 0:o.response)||void 0===s?void 0:s.access_token,tokenType:null===(c=null==o?void 0:o.response)||void 0===c?void 0:c.token_type};if(!e.token)throw new Error('no access_token in "successful" refresh: '+o.response);yield t.configure(e)}}))}static setLocation(e){if("string"==typeof e)document.location.href=e;else{if("object"!=typeof e)throw"Invalid location "+e;document.location=e}}static _rs_supported(){return"undefined"!=typeof document}static _rs_cleanup(e){e.removeEventListener("features-loaded",c)}}l.IMPLIED_FAKE_TOKEN=!1,l.getLocation=function(){return document.location},l.openWindow=function(e,t,r){return new Promise((o,n)=>{const i=open(e,"_blank",r);function s(){n("Authorization was canceled")}i&&!i.closed?(i.addEventListener("loadstart",(function(e){if(0!==e.url.indexOf(t))return;i.removeEventListener("exit",s),i.close();const r=h(e.url);r?o(r):n("Authorization error")})),i.addEventListener("exit",s)):n("Authorization popup was blocked")})},l._rs_init=function(e){const t=h();let r;t&&(r=l.getLocation(),r.hash=""),c=function(){let n=!1;if(t){if(t.error)throw"access_denied"===t.error?new a.default("Authorization failed: access denied",{code:"access_denied"}):new a.default("Authorization failed: "+t.error);t.rsDiscovery&&e.remote.configure(t.rsDiscovery),t.access_token&&(e.remote.configure({token:t.access_token}),n=!0),t.remotestorage&&(e.connect(t.remotestorage),n=!0),t.state&&(r=l.getLocation(),l.setLocation(r.href.split("#")[0]+"#"+t.state)),t.code&&(!function(t){var n,s,a,c;o(this,void 0,void 0,(function*(){const o=sessionStorage.getItem("remotestorage:codeVerifier");if(!o)return void(0,i.default)("[Authorize] Ignoring OAuth code parameter, because no PKCE code verifier found in sessionStorage");r=l.getLocation();let h=r.origin;"/"!==r.pathname&&(h+=r.pathname);const d=new URLSearchParams({code:t,grant_type:"authorization_code",client_id:e.remote.clientId,redirect_uri:h,code_verifier:o}),f=yield(0,u.requestWithTimeout)("POST",e.remote.TOKEN_URL,{headers:{"Content-Type":"application/x-www-form-urlencoded"},body:d.toString(),responseType:"json"});switch(f.status){case 200:(0,i.default)(`[Authorize] access token good for ${null===(n=null==f?void 0:f.response)||void 0===n?void 0:n.expires_in} seconds`);const t={token:null===(s=null==f?void 0:f.response)||void 0===s?void 0:s.access_token,refreshToken:null===(a=null==f?void 0:f.response)||void 0===a?void 0:a.refresh_token,tokenType:null===(c=null==f?void 0:f.response)||void 0===c?void 0:c.token_type};t.token?e.remote.configure(t):e._emit("error",new Error('no access_token in "successful" response: '+f.response)),sessionStorage.removeItem("remotestorage:codeVerifier");break;default:e._emit("error",new Error(`${f.statusText}: ${f.response}`))}}))}(t.code),n=!0),n||e.remote.stopWaitingForToken()}else e.remote.stopWaitingForToken()},e.on("features-loaded",c)},e.exports=l},function(e,t,r){"use strict";class o extends Error{constructor(e,t={}){super(),this.name="Unauthorized",this.message=void 0===e?"App authorization expired or revoked.":e,void 0!==t.code&&(this.code=t.code),this.stack=(new Error).stack}}e.exports=o},function(e,t){var r;r=function(){return this}();try{r=r||new Function("return this")()}catch(e){"object"==typeof window&&(r=window)}e.exports=r},function(e,t,r){"use strict";(function(e){var o=this&&this.__awaiter||function(e,t,r,o){return new(r||(r=Promise))((function(n,i){function s(e){try{u(o.next(e))}catch(e){i(e)}}function a(e){try{u(o.throw(e))}catch(e){i(e)}}function u(e){var t;e.done?n(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(s,a)}u((o=o.apply(e,t||[])).next())}))},n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.requestWithTimeout=t.isArrayBufferView=t.retryAfterMs=void 0;const i=n(r(1)),s=n(r(3));if(t.retryAfterMs=function(e){const t=1e3*parseInt(e.getResponseHeader("Retry-After"));return t>=1e3?t:Math.max(1500,Math.min(6e4,Math.round(s.default.syncInterval/(2.9+.2*Math.random()))))},"function"==typeof(e||window).ArrayBufferView)t.isArrayBufferView=function(t){return t&&t instanceof(e||window).ArrayBufferView};else{const e=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];t.isArrayBufferView=function(t){for(let r=0;r<8;r++)if(t instanceof e[r])return!0;return!1}}t.requestWithTimeout=function(e,r,n){return o(this,void 0,void 0,(function*(){return"function"==typeof fetch?function(e,t,r){return o(this,void 0,void 0,(function*(){const o="function"==typeof AbortController?new AbortController:null;let n;const a=new Promise((e,t)=>{n=setTimeout(()=>{o&&o.abort(),t("timeout")},s.default.requestTimeout)});let u;const c={},h=fetch(t,{method:e,headers:r.headers,body:r.body,signal:o?o.signal:void 0}).then(e=>{switch((0,i.default)("[requests fetch]",e),e.headers.forEach((e,t)=>{c[t.toUpperCase()]=e}),u={readyState:4,status:e.status,statusText:e.statusText,response:void 0,getResponseHeader:e=>c[e.toUpperCase()]||null,responseType:r.responseType,responseURL:t},r.responseType){case"arraybuffer":return e.arrayBuffer();case"blob":return e.blob();case"json":return e.json();case void 0:case"":case"text":return e.text();default:throw new Error("responseType 'document' is not currently supported using fetch")}}).then(e=>(u.response=e,r.responseType&&"text"!==r.responseType||(u.responseText=e),u)).finally(()=>{clearTimeout(n)});return Promise.race([h,a])}))}(e,r,n):"function"==typeof XMLHttpRequest?function(e,r,n){return o(this,void 0,void 0,(function*(){return new Promise((o,a)=>{(0,i.default)("[requests XHR]",e,r);let u=!1;const c=setTimeout(()=>{u=!0,a("timeout")},s.default.requestTimeout),h=new XMLHttpRequest;if(h.open(e,r,!0),n.responseType&&(h.responseType=n.responseType),n.headers)for(const e in n.headers)h.setRequestHeader(e,n.headers[e]);h.onload=()=>{u||(clearTimeout(c),o(h))},h.onerror=e=>{u||(clearTimeout(c),a(e))};let l=n.body;"object"==typeof l&&!(0,t.isArrayBufferView)(l)&&l instanceof ArrayBuffer&&(l=new Uint8Array(l)),h.send(l)})}))}(e,r,n):Promise.reject("[Requests] You need to add a polyfill for fetch or XMLHttpRequest")}))}}).call(this,r(6))},function(e,t,r){"use strict";var o=this&&this.__awaiter||function(e,t,r,o){return new(r||(r=Promise))((function(n,i){function s(e){try{u(o.next(e))}catch(e){i(e)}}function a(e){try{u(o.throw(e))}catch(e){i(e)}}function u(e){var t;e.done?n(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(s,a)}u((o=o.apply(e,t||[])).next())}))},n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const i=n(r(24)),s=n(r(25)),a=n(r(26)),u=n(r(2)),c=n(r(3)),h=r(0);class l{constructor(e,t){if(this.schemas={configurable:!0,get(){return l.Types.inScope(this.moduleName)}},"/"!==t[t.length-1])throw"Not a folder: "+t;"/"===t&&(this.makePath=e=>("/"===e[0]?"":"/")+e),this.storage=e,this.base=t,this.moduleName=function(e){const t=e.split("/");return e.length>2?t[1]:"root"}(this.base),this.addEvents(["change"]),this.on=this.on.bind(this),e.onChange(this.base,this._fireChange.bind(this))}scope(e){return new l(this.storage,this.makePath(e))}getListing(e,t){return o(this,void 0,void 0,(function*(){if("string"!=typeof e)e="";else if(e.length>0&&!(0,h.isFolder)(e))return Promise.reject("Not a folder: "+e);return this.storage.get(this.makePath(e),t).then(e=>404===e.statusCode?{}:e.body)}))}getAll(e,t){return o(this,void 0,void 0,(function*(){if("string"!=typeof e)e="";else if(e.length>0&&!(0,h.isFolder)(e))return Promise.reject("Not a folder: "+e);return this.storage.get(this.makePath(e),t).then(r=>{if(404===r.statusCode)return{};if("object"==typeof r.body){const o=Object.keys(r.body);if(0===o.length)return{};const n=o.map(o=>this.storage.get(this.makePath(e+o),t).then(e=>{if("string"==typeof e.body)try{e.body=JSON.parse(e.body)}catch(e){}"object"==typeof e.body&&(r.body[o]=e.body)}));return Promise.all(n).then(()=>r.body)}})}))}getFile(e,t){return o(this,void 0,void 0,(function*(){return"string"!=typeof e?Promise.reject("Argument 'path' of baseClient.getFile must be a string"):this.storage.get(this.makePath(e),t).then(e=>({data:e.body,contentType:e.contentType,revision:e.revision}))}))}storeFile(e,t,r){return o(this,void 0,void 0,(function*(){return"string"!=typeof e?Promise.reject("Argument 'mimeType' of baseClient.storeFile must be a string"):"string"!=typeof t?Promise.reject("Argument 'path' of baseClient.storeFile must be a string"):"string"!=typeof r&&"object"!=typeof r?Promise.reject("Argument 'body' of baseClient.storeFile must be a string, ArrayBuffer, or ArrayBufferView"):(this.storage.access.checkPathPermission(this.makePath(t),"rw")||console.warn("WARNING: Editing a document to which only read access ('r') was claimed"),this.storage.put(this.makePath(t),r,e).then(e=>200===e.statusCode||201===e.statusCode?e.revision:Promise.reject("Request (PUT "+this.makePath(t)+") failed with status: "+e.statusCode)))}))}getObject(e,t){return o(this,void 0,void 0,(function*(){return"string"!=typeof e?Promise.reject("Argument 'path' of baseClient.getObject must be a string"):this.storage.get(this.makePath(e),t).then(t=>{if("object"==typeof t.body)return t.body;if("string"==typeof t.body)try{return JSON.parse(t.body)}catch(t){throw new Error("Not valid JSON: "+this.makePath(e))}else if(void 0!==t.body&&200===t.statusCode)return Promise.reject("Not an object: "+this.makePath(e))})}))}storeObject(e,t,r){return o(this,void 0,void 0,(function*(){if("string"!=typeof e)return Promise.reject("Argument 'typeAlias' of baseClient.storeObject must be a string");if("string"!=typeof t)return Promise.reject("Argument 'path' of baseClient.storeObject must be a string");if("object"!=typeof r)return Promise.reject("Argument 'object' of baseClient.storeObject must be an object");this._attachType(r,e);try{const e=this.validate(r);if(!e.valid)return Promise.reject(e)}catch(e){return Promise.reject(e)}return this.storage.put(this.makePath(t),JSON.stringify(r),"application/json; charset=UTF-8").then(e=>200===e.statusCode||201===e.statusCode?e.revision:Promise.reject("Request (PUT "+this.makePath(t)+") failed with status: "+e.statusCode))}))}remove(e){return"string"!=typeof e?Promise.reject("Argument 'path' of baseClient.remove must be a string"):(this.storage.access.checkPathPermission(this.makePath(e),"rw")||console.warn("WARNING: Removing a document to which only read access ('r') was claimed"),this.storage.delete(this.makePath(e)))}getItemURL(e){if("string"!=typeof e)throw"Argument 'path' of baseClient.getItemURL must be a string";return this.storage.connected?(e=(0,h.cleanPath)(this.makePath(e)),this.storage.remote.href+e):void 0}cache(e,t="ALL"){if("string"!=typeof e)throw"Argument 'path' of baseClient.cache must be a string";if("string"!=typeof t)throw"Argument 'strategy' of baseClient.cache must be a string or undefined";if("FLUSH"!==t&&"SEEN"!==t&&"ALL"!==t)throw'Argument \'strategy\' of baseclient.cache must be one of ["FLUSH", "SEEN", "ALL"]';return this.storage.caching.set(this.makePath(e),t),this}flush(e){return this.storage.local.flush(e)}declareType(e,t,r){let o;if(r&&"string"==typeof t)o=t;else if(r||"string"==typeof t){if(!r&&"string"==typeof t)throw new Error("declareType() requires a JSON Schema object to be passed, in order to validate object types/formats")}else r=t,o=this._defaultTypeURI(e);l.Types.declare(this.moduleName,e,o,r)}validate(e){const t=l.Types.getSchema(e["@context"]);if(t)return i.default.validateResult(e,t);throw new a.default(e["@context"])}_defaultTypeURI(e){return"http://remotestorage.io/spec/modules/"+encodeURIComponent(this.moduleName)+"/"+encodeURIComponent(e)}_attachType(e,t){e["@context"]=l.Types.resolveAlias(this.moduleName+"/"+t)||this._defaultTypeURI(t)}makePath(e){return this.base+(e||"")}_fireChange(e){c.default.changeEvents[e.origin]&&(["new","old","lastCommon"].forEach((function(t){if((!e[t+"ContentType"]||/^application\/(.*)json(.*)/.exec(e[t+"ContentType"]))&&"string"==typeof e[t+"Value"])try{e[t+"Value"]=JSON.parse(e[t+"Value"])}catch(e){}})),this._emit("change",e))}static _rs_init(){}}l.Types=s.default,(0,h.applyMixins)(l,[u.default]),e.exports=l},function(e,t,r){"use strict";var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.RemoteBase=void 0;const n=o(r(2)),i=r(0);class s extends n.default{constructor(e){super(),this.rs=e,this.connected=!1}stopWaitingForToken(){this.connected||this._emit("not-connected")}addQuotes(e){return"string"!=typeof e?e:"*"===e?"*":'"'+e+'"'}stripQuotes(e){return"string"!=typeof e?e:e.replace(/^["']|["']$/g,"")}isForbiddenRequestMethod(e,t){return("PUT"===e||"DELETE"===e)&&(0,i.isFolder)(t)}}t.RemoteBase=s},function(e,t,r){"use strict";class o extends Error{constructor(e){super(),this.name="SyncError",this.message="Sync failed: ","string"==typeof e?this.message+=e:(this.message+=e.message,this.stack=e.stack,this.originalError=e)}}e.exports=o},function(e,t,r){"use strict";var o=this&&this.__awaiter||function(e,t,r,o){return new(r||(r=Promise))((function(n,i){function s(e){try{u(o.next(e))}catch(e){i(e)}}function a(e){try{u(o.throw(e))}catch(e){i(e)}}function u(e){var t;e.done?n(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(s,a)}u((o=o.apply(e,t||[])).next())}))},n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const i=n(r(2)),s=n(r(3)),a=n(r(1)),u=r(0);function c(e){if("object"==typeof e&&"string"==typeof e.path)if((0,u.isFolder)(e.path)){if(e.local&&e.local.itemsMap)return e.local;if(e.common&&e.common.itemsMap)return e.common}else{if(e.local){if(e.local.body&&e.local.contentType)return e.local;if(!1===e.local.body)return}if(e.common&&e.common.body&&e.common.contentType)return e.common;if(e.body&&e.contentType)return{body:e.body,contentType:e.contentType}}}function h(e,t){for(const r in e){if(e[r]&&e[r].remote)return!0;const o=c(e[r]);if(o&&o.timestamp&&(new Date).getTime()-o.timestamp<=t)return!1;if(!o)return!0}return!0}function l(e){const t={path:e,common:{}};return(0,u.isFolder)(e)&&(t.common.itemsMap={}),t}function d(e,t){return e.common||(e.common={itemsMap:{}}),e.common.itemsMap||(e.common.itemsMap={}),e.local||(e.local=(0,u.deepClone)(e.common)),e.local.itemsMap||(e.local.itemsMap=e.common.itemsMap),e.local.itemsMap[t]=!0,e}class f{constructor(){this._updateNodesRunning=!1,this._updateNodesQueued=[]}get(e,t,r){return o(this,void 0,void 0,(function*(){return"number"==typeof t?this.getNodes((0,u.pathsFromRoot)(e)).then(o=>{const n=c(o[e]);return h(o,t)?r(e):n?{statusCode:200,body:n.body||n.itemsMap,contentType:n.contentType}:{statusCode:404}}):this.getNodes([e]).then(t=>{const r=c(t[e]);if(r){if((0,u.isFolder)(e))for(const e in r.itemsMap)r.itemsMap.hasOwnProperty(e)&&!1===r.itemsMap[e]&&delete r.itemsMap[e];return{statusCode:200,body:r.body||r.itemsMap,contentType:r.contentType}}return{statusCode:404}})}))}put(e,t,r){return o(this,void 0,void 0,(function*(){const o=(0,u.pathsFromRoot)(e);return this._updateNodes(o,(function(e,o){try{for(let n=0,i=e.length;n0)break}else console.error("Cannot delete non-existing node "+o)}return t}))}flush(e){return this._getAllDescendentPaths(e).then(e=>this.getNodes(e)).then(e=>{for(const t in e){const r=e[t];r&&r.common&&r.local&&this._emitChange({path:r.path,origin:"local",oldValue:!1===r.local.body?void 0:r.local.body,newValue:!1===r.common.body?void 0:r.common.body}),e[t]=void 0}return this.setNodes(e)})}_emitChange(e){s.default.changeEvents[e.origin]&&this._emit("change",e)}fireInitial(){s.default.changeEvents.local&&this.forAllNodes(e=>{if((0,u.isDocument)(e.path)){const t=c(e);t&&this._emitChange({path:e.path,origin:"local",oldValue:void 0,oldContentType:void 0,newValue:t.body,newContentType:t.contentType})}}).then(()=>{this._emit("local-events-done")})}onDiff(e){this.diffHandler=e}migrate(e){return"object"!=typeof e||e.common||(e.common={},"string"==typeof e.path?"/"===e.path.substr(-1)&&"object"==typeof e.body&&(e.common.itemsMap=e.body):(e.local||(e.local={}),e.local.body=e.body,e.local.contentType=e.contentType)),e}_updateNodes(e,t){return new Promise((r,o)=>{this._doUpdateNodes(e,t,{resolve:r,reject:o})})}_doUpdateNodes(e,t,r){this._updateNodesRunning?this._updateNodesQueued.push({paths:e,cb:t,promise:r}):(this._updateNodesRunning=!0,this.getNodes(e).then(o=>{const n=(0,u.deepClone)(o),i=[];o=t(e,o);for(const e in o){const t=o[e];(0,u.equal)(t,n[e])?delete o[e]:(0,u.isDocument)(e)&&((0,u.equal)(t.local.body,t.local.previousBody)&&t.local.contentType===t.local.previousContentType||i.push({path:e,origin:"window",oldValue:t.local.previousBody,newValue:!1===t.local.body?void 0:t.local.body,oldContentType:t.local.previousContentType,newContentType:t.local.contentType}),delete t.local.previousBody,delete t.local.previousContentType)}this.setNodes(o).then(()=>{this._emitChangeEvents(i),r.resolve({statusCode:200})})}).then(()=>Promise.resolve(),e=>{r.reject(e)}).then(()=>{this._updateNodesRunning=!1;const e=this._updateNodesQueued.shift();e&&this._doUpdateNodes(e.paths,e.cb,e.promise)}))}_emitChangeEvents(e){for(let t=0,r=e.length;t{const r=[e],o=c(t[e]),n=Object.keys(o.itemsMap).map(t=>this._getAllDescendentPaths(e+t).then(e=>{for(let t=0,o=e.length;tr)}):Promise.resolve([e])}_getInternals(){return{getLatest:c,makeNode:l,isOutdated:h}}}(0,u.applyMixins)(f,[i.default]),e.exports=f},function(e,t,r){"use strict";e.exports=class{constructor(){this.reset()}static _rs_init(){}get scopes(){return Object.keys(this.scopeModeMap).map(e=>({name:e,mode:this.scopeModeMap[e]}))}get scopeParameter(){return this.scopes.map(e=>`${this._scopeNameForParameter(e)}:${e.mode}`).join(" ")}claim(e,t){if("string"!=typeof e||-1!==e.indexOf("/")||0===e.length)throw new Error("Scope should be a non-empty string without forward slashes");if(!t.match(/^rw?$/))throw new Error("Mode should be either 'r' or 'rw'");this._adjustRootPaths(e),this.scopeModeMap[e]=t}get(e){return this.scopeModeMap[e]}remove(e){const t={};for(const e in this.scopeModeMap)t[e]=this.scopeModeMap[e];this.reset(),delete t[e];for(const e in t)this.claim(e,t[e])}checkPermission(e,t){const r=this.get(e);return r&&("r"===t||"rw"===r)}checkPathPermission(e,t){if(this.checkPermission("*",t))return!0;const r=this._getModuleName(e);return!!this.checkPermission(r,t)}reset(){this.rootPaths=[],this.scopeModeMap={}}_getModuleName(e){if("/"!==e[0])throw new Error("Path should start with a slash");const t=e.replace(/^\/public/,"").match(/^\/([^/]*)\//);return t?t[1]:"*"}_adjustRootPaths(e){"*"in this.scopeModeMap||"*"===e?this.rootPaths=["/"]:e in this.scopeModeMap||(this.rootPaths.push("/"+e+"/"),this.rootPaths.push("/public/"+e+"/"))}_scopeNameForParameter(e){if("*"===e.name&&this.storageType){if("2012.04"===this.storageType)return"";if(this.storageType.match(/remotestorage-0[01]/))return"root"}return e.name}setStorageType(e){this.storageType=e}}},function(e,t,r){"use strict";var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const n=r(0),i=o(r(1));e.exports=class{constructor(){this.pendingActivations=[],this.reset()}set(e,t){if("string"!=typeof e)throw new Error("path should be a string");if(!(0,n.isFolder)(e))throw new Error("path should be a folder");if(!t.match(/^(FLUSH|SEEN|ALL)$/))throw new Error("strategy should be 'FLUSH', 'SEEN', or 'ALL'");this._rootPaths[e]=t,"ALL"===t&&(this.activateHandler?this.activateHandler(e):this.pendingActivations.push(e))}enable(e){this.set(e,"ALL")}disable(e){this.set(e,"FLUSH")}onActivate(e){(0,i.default)("[Caching] Setting activate handler",e,this.pendingActivations),this.activateHandler=e;for(let t=0;t=r-this.maxAge?t.v:void 0}set(e,t){this._items[e]={v:t,t:(new Date).getTime()}}}class y extends u.RemoteBase{constructor(e,t){if(super(e),this.online=!0,this.storageApi="draft-dejong-remotestorage-19",this.addEvents(["connected","not-connected"]),this.clientId=t,this._fileIdCache=new g(300),l=(0,s.localStorageAvailable)(),l){const e=(0,s.getJSONFromLocalStorage)(h);e&&this.configure(e)}}configure(e){void 0!==e.userAddress&&(this.userAddress=e.userAddress),void 0!==e.token&&(this.token=e.token);const t=function(){l&&localStorage.setItem(h,JSON.stringify({userAddress:this.userAddress,token:this.token}))},r=function(){this.connected=!1,delete this.token,l&&localStorage.removeItem(h)};this.token?(this.connected=!0,this.userAddress?(this._emit("connected"),t.apply(this)):this.info().then(e=>{this.userAddress=e.user.emailAddress,this._emit("connected"),t.apply(this)}).catch(()=>{r.apply(this),this.rs._emit("error",new Error("Could not fetch user info."))})):r.apply(this)}connect(){this.rs.setBackend("googledrive"),this.rs.authorize({authURL:"https://accounts.google.com/o/oauth2/auth",scope:"https://www.googleapis.com/auth/drive",clientId:this.clientId})}get(e,t={}){return(0,s.isFolder)(e)?this._getFolder(m(e)):this._getFile(m(e),t)}put(e,t,r,o={}){const n=m(e);function i(e){if(e.status>=200&&e.status<300){const t=JSON.parse(e.responseText),r=this.stripQuotes(t.etag);return Promise.resolve({statusCode:200,contentType:t.mimeType,revision:r})}return 412===e.status?Promise.resolve({statusCode:412,revision:"conflict"}):Promise.reject("PUT failed with status "+e.status+" ("+e.responseText+")")}return this._getFileId(n).then(e=>e?o&&"*"===o.ifNoneMatch?i({status:412}):this._updateFile(e,n,t,r,o).then(i):this._createFile(n,t,r).then(i))}delete(e,t={}){const r=m(e);return this._getFileId(r).then(e=>e?this._getMeta(e).then(r=>{let o;return"object"==typeof r&&"string"==typeof r.etag&&(o=this.stripQuotes(r.etag)),t&&t.ifMatch&&t.ifMatch!==o?{statusCode:412,revision:o}:this._request("DELETE",c+"/drive/v2/files/"+e,{}).then(e=>200===e.status||204===e.status?{statusCode:200}:Promise.reject("Delete failed: "+e.status+" ("+e.responseText+")"))}):Promise.resolve({statusCode:200}))}info(){return this._request("GET","https://www.googleapis.com/drive/v2/about?fields=user",{}).then((function(e){try{const t=JSON.parse(e.responseText);return Promise.resolve(t)}catch(e){return Promise.reject(e)}}))}_updateFile(e,t,r,o,n){const i={mimeType:o},s={"Content-Type":"application/json; charset=UTF-8"};return n&&n.ifMatch&&(s["If-Match"]=this.addQuotes(n.ifMatch)),this._request("PUT",c+"/upload/drive/v2/files/"+e+"?uploadType=resumable",{body:JSON.stringify(i),headers:s}).then(e=>412===e.status?e:this._request("PUT",e.getResponseHeader("Location"),{body:o.match(/^application\/json/)?JSON.stringify(r):r}))}_createFile(e,t,r){return this._getParentId(e).then(o=>{const n={title:d(p(e)),mimeType:r,parents:[{kind:"drive#fileLink",id:o}]};return this._request("POST",c+"/upload/drive/v2/files?uploadType=resumable",{body:JSON.stringify(n),headers:{"Content-Type":"application/json; charset=UTF-8"}}).then(e=>this._request("POST",e.getResponseHeader("Location"),{body:r.match(/^application\/json/)?JSON.stringify(t):t}))})}_getFile(e,t){return this._getFileId(e).then(e=>this._getMeta(e).then(e=>{let r;if("object"==typeof e&&"string"==typeof e.etag&&(r=this.stripQuotes(e.etag)),t&&t.ifNoneMatch&&r===t.ifNoneMatch)return Promise.resolve({statusCode:304});if(!e.downloadUrl){if(!e.exportLinks||!e.exportLinks["text/html"])return Promise.resolve({statusCode:200,body:"",contentType:e.mimeType,revision:r});e.mimeType+=";export=text/html",e.downloadUrl=e.exportLinks["text/html"]}return this._request("GET",e.downloadUrl,{responseType:"arraybuffer"}).then(t=>(0,s.getTextFromArrayBuffer)(t.response,"UTF-8").then((function(o){let n=o;if(e.mimeType.match(/^application\/json/))try{n=JSON.parse(n)}catch(e){}else(0,s.shouldBeTreatedAsBinary)(o,e.mimeType)&&(n=t.response);return{statusCode:200,body:n,contentType:e.mimeType,revision:r}})))}))}_getFolder(e){return this._getFileId(e).then(t=>{let r,o,n;if(!t)return Promise.resolve({statusCode:404});const i="'"+t+"' in parents";return this._request("GET",c+"/drive/v2/files?q="+encodeURIComponent(i)+"&fields="+encodeURIComponent("items(downloadUrl,etag,fileSize,id,mimeType,title,labels)")+"&maxResults=1000&trashed=false",{}).then(t=>{var i;if(200!==t.status)return Promise.reject("request failed or something: "+t.status);try{r=JSON.parse(t.responseText)}catch(e){return Promise.reject("non-JSON response from GoogleDrive")}n={};for(const t of r.items)(null===(i=t.labels)||void 0===i?void 0:i.trashed)||(o=this.stripQuotes(t.etag),"application/vnd.google-apps.folder"===t.mimeType?(this._fileIdCache.set(e+(0,s.cleanPath)(t.title)+"/",t.id),n[t.title+"/"]={ETag:o}):(this._fileIdCache.set(e+(0,s.cleanPath)(t.title),t.id),n[t.title]={ETag:o,"Content-Type":t.mimeType,"Content-Length":t.fileSize}));return Promise.resolve({statusCode:200,body:n,contentType:"application/json; charset=UTF-8",revision:void 0})})})}_getParentId(e){const t=f(e);return this._getFileId(t).then(e=>e?Promise.resolve(e):this._createFolder(t))}_createFolder(e){return this._getParentId(e).then(t=>this._request("POST",c+"/drive/v2/files",{body:JSON.stringify({title:d(p(e)),mimeType:"application/vnd.google-apps.folder",parents:[{id:t}]}),headers:{"Content-Type":"application/json; charset=UTF-8"}}).then(e=>{const t=JSON.parse(e.responseText);return Promise.resolve(t.id)}))}_getFileId(e){let t;return"/"===e?Promise.resolve("root"):(t=this._fileIdCache.get(e))?Promise.resolve(t):this._getFolder(f(e)).then(()=>(t=this._fileIdCache.get(e),t?Promise.resolve(t):"/"===e.substr(-1)?this._createFolder(e).then(()=>this._getFileId(e)):Promise.resolve()))}_getMeta(e){return this._request("GET",c+"/drive/v2/files/"+e,{}).then((function(t){return 200===t.status?Promise.resolve(JSON.parse(t.responseText)):Promise.reject("request (getting metadata for "+e+") failed with status: "+t.status)}))}_request(e,t,r){return this.isForbiddenRequestMethod(e,t)?Promise.reject(`Don't use ${e} on directories!`):(r.headers||(r.headers={}),r.headers.Authorization="Bearer "+this.token,this.rs._emit("wire-busy",{method:e,isFolder:(0,s.isFolder)(t)}),(0,a.requestWithTimeout)(e,t,r).then(r=>r&&401===r.status?void this.connect():(this.online||(this.online=!0,this.rs._emit("network-online")),this.rs._emit("wire-done",{method:e,isFolder:(0,s.isFolder)(t),success:!0}),Promise.resolve(r)),r=>(this.online&&(this.online=!1,this.rs._emit("network-offline")),this.rs._emit("wire-done",{method:e,isFolder:(0,s.isFolder)(t),success:!1}),Promise.reject(r))))}static _rs_init(e){const t=e.apiKeys.googledrive;var r;t&&(e.googledrive=new y(e,t.clientId),"googledrive"===e.backend&&(e._origRemote=e.remote,e.remote=e.googledrive,(r=e)._origBaseClientGetItemURL||(r._origBaseClientGetItemURL=n.default.prototype.getItemURL,n.default.prototype.getItemURL=function(){throw new Error("getItemURL is not implemented for Google Drive yet")})))}static _rs_supported(){return!0}static _rs_cleanup(e){var t;e.setBackend(void 0),e._origRemote&&(e.remote=e._origRemote,delete e._origRemote),(t=e)._origBaseClientGetItemURL&&(n.default.prototype.getItemURL=t._origBaseClientGetItemURL,delete t._origBaseClientGetItemURL)}}(0,s.applyMixins)(y,[i.default]),e.exports=y},function(e,t,r){"use strict";var o=this&&this.__awaiter||function(e,t,r,o){return new(r||(r=Promise))((function(n,i){function s(e){try{u(o.next(e))}catch(e){i(e)}}function a(e){try{u(o.throw(e))}catch(e){i(e)}}function u(e){var t;e.done?n(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(s,a)}u((o=o.apply(e,t||[])).next())}))},n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const i=n(r(2)),s=n(r(8)),a=n(r(27)),u=n(r(10)),c=n(r(5)),h=r(0),l=r(7),d=r(9),f=n(r(4));let p;const m="remotestorage:dropbox",g="https://api.dropboxapi.com/2/files/list_folder",y="https://api.dropboxapi.com/2/files/list_folder/continue";function v(e){return("/remotestorage/"+e).replace(/\/+$/,"").replace(/\/+/g,"/")}const _=/[\u007f-\uffff]/g;function b(e){return JSON.stringify(e).replace(_,(function(e){return"\\u"+("000"+e.charCodeAt(0).toString(16)).slice(-4)}))}function w(e,t){return new RegExp("^"+t.join("\\/")+"(\\/|$)").test(e.error_summary)}function P(e){return e instanceof ArrayBuffer||(0,l.isArrayBufferView)(e)}class E extends d.RemoteBase{constructor(e){if(super(e),this.online=!0,this.storageApi="draft-dejong-remotestorage-19",this._initialFetchDone=!1,this.addEvents(["connected","not-connected"]),this.clientId=e.apiKeys.dropbox.appKey,this.TOKEN_URL="https://api.dropboxapi.com/oauth2/token",this._revCache=new a.default("rev"),this._fetchDeltaCursor=null,this._fetchDeltaPromise=null,this._itemRefs={},p=(0,h.localStorageAvailable)(),p){const e=(0,h.getJSONFromLocalStorage)(m);e&&this.configure(e),this._itemRefs=(0,h.getJSONFromLocalStorage)(m+":shares")||{}}this.connected&&setTimeout(this._emit.bind(this),0,"connected")}connect(){return o(this,void 0,void 0,(function*(){try{if(this.rs.setBackend("dropbox"),this.token)R(this.rs);else{const{codeVerifier:e,codeChallenge:t,state:r}=yield(0,h.generateCodeVerifier)();sessionStorage.setItem("remotestorage:codeVerifier",e),sessionStorage.setItem("remotestorage:state",r),this.rs.authorize({authURL:"https://www.dropbox.com/oauth2/authorize",scope:"account_info.read files.content.read files.content.write files.metadata.read files.metadata.write",clientId:this.clientId,response_type:"code",state:r,code_challenge:t,code_challenge_method:"S256",token_access_type:"offline"})}}catch(e){throw this.rs._emit("error",e),this.rs.setBackend(void 0),e}}))}configure(e){return o(this,void 0,void 0,(function*(){void 0!==e.userAddress&&(this.userAddress=e.userAddress),void 0!==e.token&&(this.token=e.token),void 0!==e.refreshToken&&(this.refreshToken=e.refreshToken),void 0!==e.tokenType&&(this.tokenType=e.tokenType);const t=()=>{p&&localStorage.setItem(m,JSON.stringify({userAddress:this.userAddress,token:this.token,refreshToken:this.refreshToken,tokenType:this.tokenType}))},r=()=>{this.connected=!1,p&&localStorage.removeItem(m),this.rs.setBackend(void 0)};if(this.refreshToken||this.token)if(this.connected=!0,this.userAddress)this._emit("connected"),t();else try{const e=yield this.info();this.userAddress=e.email,this._emit("connected"),t()}catch(e){this.connected=!1,this.rs._emit("error",new Error("Could not fetch user info.")),t.apply(this)}else r()}))}_getFolder(e){const t=this._revCache,r=r=>{let n;if(200!==r.status&&409!==r.status)return Promise.reject("Unexpected response status: "+r.status);try{n=JSON.parse(r.responseText)}catch(e){return Promise.reject(e)}if(409===r.status)return w(n,["path","not_found"])?Promise.resolve({}):Promise.reject(new Error("API returned an error: "+n.error_summary));const i=n.entries.reduce((r,o)=>{try{const n="folder"===o[".tag"],i=o.path_display.split("/").slice(-1)[0]+(n?"/":"");if(n)r[i]={ETag:t.get(e+i)};else{const t=new Date(o.server_modified);r[i]={ETag:o.rev,"Content-Length":o.size,"Last-Modified":t.toUTCString()},this._revCache.set(e+i,o.rev)}}catch(t){console.error(`[Dropbox] folder “${e}” has entry ${JSON.stringify(o)}:`,t)}return r},{});return n.has_more?o(n.cursor).then((function(e){return Object.assign(i,e)})):Promise.resolve(i)},o=e=>{const t={body:{cursor:e}};return this._request("POST",y,t).then(r)};return this._request("POST",g,{body:{path:v(e)}}).then(r).then((function(r){return Promise.resolve({statusCode:200,body:r,contentType:"application/json; charset=UTF-8",revision:t.get(e)})}))}get(e,t={}){if(!this.connected)return Promise.reject("not connected (path: "+e+")");const r=this._revCache.get(e);if(null===r)return Promise.resolve({statusCode:404});if(t&&t.ifNoneMatch){if(!this._initialFetchDone)return this.fetchDelta().then(()=>this.get(e,t));if(r&&r===t.ifNoneMatch)return Promise.resolve({statusCode:304})}if("/"===e.slice(-1))return this._getFolder(e);const o={headers:{"Dropbox-API-Arg":b({path:v(e)})},responseType:"arraybuffer"};return t&&t.ifNoneMatch&&(o.headers["If-None-Match"]=t.ifNoneMatch),this._request("GET","https://content.dropboxapi.com/2/files/download",o).then(t=>{const r=t.status;let o,n,i,s;return 200!==r&&409!==r?Promise.resolve({statusCode:r}):(o=t.getResponseHeader("Dropbox-API-Result"),(0,h.getTextFromArrayBuffer)(t.response,"UTF-8").then(a=>{n=a,409===r&&(o=n);try{o=JSON.parse(o)}catch(e){return Promise.reject(e)}if(409===r)return w(o,["path","not_found"])?{statusCode:404}:Promise.reject(new Error('API error while downloading file ("'+e+'"): '+o.error_summary));if(i=t.getResponseHeader("Content-Type"),s=o.rev,this._revCache.set(e,s),this._shareIfNeeded(e),(0,h.shouldBeTreatedAsBinary)(a,i))n=t.response;else try{n=JSON.parse(n),i="application/json; charset=UTF-8"}catch(e){}return{statusCode:r,body:n,contentType:i,revision:s}}))})}put(e,t,r,n={}){return o(this,void 0,void 0,(function*(){if(!this.connected)throw new Error("not connected (path: "+e+")");const o=this._revCache.get(e);if(n&&n.ifMatch&&o&&o!==n.ifMatch)return{statusCode:412,revision:o};if(n&&"*"===n.ifNoneMatch&&o&&"rev"!==o)return{statusCode:412,revision:o};if(!r.match(/charset=/)&&P(t)&&(r+="; charset=binary"),t.length>157286400)throw new Error("Cannot upload file larger than 150MB");const i=n&&(n.ifMatch||"*"===n.ifNoneMatch),s={body:t,contentType:r,path:e};if(i){const t=yield this._getMetadata(e);if(n&&"*"===n.ifNoneMatch&&t)return{statusCode:412,revision:t.rev};if(n&&n.ifMatch&&t&&t.rev!==n.ifMatch)return{statusCode:412,revision:t.rev}}const a=yield this._uploadSimple(s);return this._shareIfNeeded(e),a}))}delete(e,t={}){return o(this,void 0,void 0,(function*(){if(!this.connected)throw new Error("not connected (path: "+e+")");const r=this._revCache.get(e);if((null==t?void 0:t.ifMatch)&&r&&t.ifMatch!==r)return{statusCode:412,revision:r};if(null==t?void 0:t.ifMatch){const r=yield this._getMetadata(e);if((null==t?void 0:t.ifMatch)&&r&&r.rev!==t.ifMatch)return{statusCode:412,revision:r.rev}}return this._deleteSimple(e)}))}_shareIfNeeded(e){if(e.match(/^\/public\/.*[^/]$/)&&void 0===this._itemRefs[e])return this.share(e)}share(e){const t={body:{path:v(e)}};return this._request("POST","https://api.dropboxapi.com/2/sharing/create_shared_link_with_settings",t).then(t=>{if(200!==t.status&&409!==t.status)return Promise.reject(new Error("Invalid response status:"+t.status));let r;try{r=JSON.parse(t.responseText)}catch(e){return Promise.reject(new Error("Invalid response body: "+t.responseText))}return 409===t.status?w(r,["shared_link_already_exists"])?this._getSharedLink(e):Promise.reject(new Error("API error: "+r.error_summary)):Promise.resolve(r.url)}).then(t=>(this._itemRefs[e]=t,p&&localStorage.setItem(m+":shares",JSON.stringify(this._itemRefs)),Promise.resolve(t)),t=>(t.message='Sharing Dropbox file or folder ("'+e+'") failed: '+t.message,Promise.reject(t)))}info(){return this._request("POST","https://api.dropboxapi.com/2/users/get_current_account",{}).then((function(e){let t;try{const r=JSON.parse(e.responseText);t=null==r?void 0:r.email}catch(t){return Promise.reject(new Error("Could not query current account info: Invalid API response: "+e.responseText))}return Promise.resolve({email:t})}))}_request(e,t,r,n=1){return o(this,void 0,void 0,(function*(){if(this.isForbiddenRequestMethod(e,t))throw`Don't use ${e} on directories!`;if(!this.token)throw new c.default("No access token");r.headers||(r.headers={}),r.headers.Authorization="Bearer "+this.token,"object"!=typeof r.body||P(r.body)||(r.body=JSON.stringify(r.body),r.headers["Content-Type"]="application/json; charset=UTF-8"),this.rs._emit("wire-busy",{method:e,isFolder:(0,h.isFolder)(t)});try{const o=yield(0,l.requestWithTimeout)(e,t,r);return this.online||(this.online=!0,this.rs._emit("network-online")),this.rs._emit("wire-done",{method:e,isFolder:(0,h.isFolder)(t),success:!0}),401===(null==o?void 0:o.status)&&this.refreshToken?n>=3?(console.error(`Abandoned after ${n} attempts: ${e} ${t}`),o):(this.rs._emit("wire-busy",{method:e,isFolder:(0,h.isFolder)(t)}),yield f.default.refreshAccessToken(this.rs,this,this.refreshToken),this.rs._emit("wire-done",{method:e,isFolder:(0,h.isFolder)(t),success:!0}),this._request(e,t,r,n+1)):[503,429].includes(null==o?void 0:o.status)?(this.online&&(this.online=!1,this.rs._emit("network-offline")),n>=3?(console.warn(`Abandoned after ${n} attempts: ${e} ${t}`),o):(yield new Promise(e=>setTimeout(e,(0,l.retryAfterMs)(o))),this._request(e,t,r,n+1))):o}catch(r){throw this.online&&(this.online=!1,this.rs._emit("network-offline")),this.rs._emit("wire-done",{method:e,isFolder:(0,h.isFolder)(t),success:!1}),r}}))}fetchDelta(...e){if(this._fetchDeltaPromise)return this._fetchDeltaPromise;const t=e=>o(this,void 0,void 0,(function*(){let r,o;"string"==typeof e?(r=y,o={cursor:e}):(r=g,o={path:"/remotestorage",recursive:!0,include_deleted:!0});try{const n=yield this._request("POST",r,{body:o});if(401===n.status)throw new c.default;if(200!==n.status&&409!==n.status)throw new Error("Invalid response status: "+n.status);let i;try{i=JSON.parse(n.responseText)}catch(e){throw new Error("Invalid response body: "+n.responseText)}if(409===n.status){if(!w(i,["path","not_found"]))throw new Error("API returned an error: "+i.error_summary);i={cursor:null,entries:[],has_more:!1}}if(e||this._revCache.deactivatePropagation(),i.entries.forEach(e=>{const t=e.path_display.slice("/remotestorage".length);"deleted"===e[".tag"]?(this._revCache.delete(t),this._revCache.delete(t+"/")):"file"===e[".tag"]&&this._revCache.set(t,e.rev)}),this._fetchDeltaCursor=i.cursor,i.has_more)return t(i.cursor);this._revCache.activatePropagation(),this._initialFetchDone=!0}catch(e){if("timeout"===e)return;throw e}}));return this._fetchDeltaPromise=t(this._fetchDeltaCursor).catch(e=>("object"==typeof e&&"message"in e?e.message="Dropbox: fetchDelta: "+e.message:e="Dropbox: fetchDelta: "+e,this.rs._emit("error",e),this._fetchDeltaPromise=null,Promise.reject(e))).then(()=>(this._fetchDeltaPromise=null,Promise.resolve(e))),this._fetchDeltaPromise}_getMetadata(e){const t={path:v(e)};return this._request("POST","https://api.dropboxapi.com/2/files/get_metadata",{body:t}).then(e=>{if(200!==e.status&&409!==e.status)return Promise.reject(new Error("Invalid response status:"+e.status));let t;try{t=JSON.parse(e.responseText)}catch(t){return Promise.reject(new Error("Invalid response body: "+e.responseText))}return 409===e.status?w(t,["path","not_found"])?Promise.resolve():Promise.reject(new Error("API error: "+t.error_summary)):Promise.resolve(t)}).then(void 0,t=>(t.message='Could not load metadata for file or folder ("'+e+'"): '+t.message,Promise.reject(t)))}_uploadSimple(e){const t={path:v(e.path),mode:{".tag":"overwrite",update:void 0},mute:!0};return e.ifMatch&&(t.mode={".tag":"update",update:e.ifMatch}),this._request("POST","https://content.dropboxapi.com/2/files/upload",{body:e.body,headers:{"Content-Type":"application/octet-stream","Dropbox-API-Arg":b(t)}}).then(t=>{if(200!==t.status&&409!==t.status)return Promise.resolve({statusCode:t.status});let r;try{r=JSON.parse(t.responseText)}catch(e){return Promise.reject(new Error("Invalid API result: "+t.responseText))}return 409===t.status?w(r,["path","conflict"])?this._getMetadata(e.path).then((function(e){return Promise.resolve({statusCode:412,revision:e.rev})})):(this.rs._emit("error",new Error(r.error_summary)),Promise.resolve({statusCode:t.status})):(this._revCache.set(e.path,r.rev),Promise.resolve({statusCode:t.status,revision:r.rev}))})}_deleteSimple(e){const t={path:v(e)};return this._request("POST","https://api.dropboxapi.com/2/files/delete",{body:t}).then(e=>{if(200!==e.status&&409!==e.status)return Promise.resolve({statusCode:e.status});let t;try{t=JSON.parse(e.responseText)}catch(t){return Promise.reject(new Error("Invalid response body: "+e.responseText))}if(409===e.status){if(w(t,["path_lookup","not_found"]))return Promise.resolve({statusCode:404});this.rs._emit("error",new Error(t.error_summary))}return Promise.resolve({statusCode:e.status})}).then(t=>(200!==t.statusCode&&404!==t.statusCode||(this._revCache.delete(e),delete this._itemRefs[e]),Promise.resolve(t)),t=>(t.message='Could not delete Dropbox file or folder ("'+e+'"): '+t.message,Promise.reject(t)))}_getSharedLink(e){return o(this,void 0,void 0,(function*(){const t={body:{path:v(e),direct_only:!0}};return this._request("POST","https://api.dropbox.com/2/sharing/list_shared_links",t).then(e=>{if(200!==e.status&&409!==e.status)return Promise.reject(new Error("Invalid response status: "+e.status));let t;try{t=JSON.parse(e.responseText)}catch(t){return Promise.reject(new Error("Invalid response body: "+e.responseText))}return 409===e.status?Promise.reject(new Error("API error: "+(null==t?void 0:t.error_summary)||!1)):t.links.length?Promise.resolve(t.links[0].url):Promise.reject(new Error("No links returned"))},t=>(t.message='Could not get link to a shared file or folder ("'+e+'"): '+t.message,Promise.reject(t)))}))}static _rs_init(e){p=(0,h.localStorageAvailable)(),e.apiKeys.dropbox&&(e.dropbox=new E(e)),"dropbox"===e.backend&&R(e)}static _rs_supported(){return!0}static _rs_cleanup(e){!function(e){(function(e){e._origRemote&&(e.remote=e._origRemote,delete e._origRemote)})(e),function(e){if(!e._dropboxOrigSync)return;e.sync.sync=e._dropboxOrigSync,delete e._dropboxOrigSync}(e),function(e){if(!e._origBaseClientGetItemURL)return;s.default.prototype.getItemURL=e._origBaseClientGetItemURL,delete e._origBaseClientGetItemURL}(e),A(e)}(e),p&&localStorage.removeItem(m),e.setBackend(void 0)}}function T(e,...t){e._dropboxOrigSync||(e._dropboxOrigSync=e.sync.sync.bind(e.sync),e.sync.sync=function(){return this.dropbox.fetchDelta(e,...t).then(e._dropboxOrigSync,(function(t){e._emit("error",new u.default(t)),e._emit("sync-done")}))}.bind(e))}function A(e){e._dropboxOrigSyncCycle&&(e.syncCycle=e._dropboxOrigSyncCycle,delete e._dropboxOrigSyncCycle)}function R(e){!function(e){e._origRemote||(e._origRemote=e.remote,e.remote=e.dropbox)}(e),e.sync?T(e):function(e,...t){e._dropboxOrigSyncCycle||(e._dropboxOrigSyncCycle=e.syncCycle,e.syncCycle=()=>{if(!e.sync)throw new Error("expected sync to be initialized by now");T(e),e._dropboxOrigSyncCycle(e,...t),A(e)})}(e),function(e){e._origBaseClientGetItemURL||(e._origBaseClientGetItemURL=s.default.prototype.getItemURL,s.default.prototype.getItemURL=function(){throw new Error("getItemURL is not implemented for Dropbox yet")})}(e)}(0,h.applyMixins)(E,[i.default]),e.exports=E},function(e,t,r){"use strict";var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const n=o(r(28)),i=o(r(1)),s=r(0);let a,u;let c={};const h=function(e){return new Promise((t,r)=>{if(e in c)return t(c[e]);return new n.default({tls_only:!1,uri_fallback:!0,request_timeout:5e3}).lookup(e,(function(o,n){if(o)return r(o);if("object"!=typeof n.idx.links.remotestorage||"number"!=typeof n.idx.links.remotestorage.length||n.idx.links.remotestorage.length<=0)return(0,i.default)("[Discover] WebFinger record for "+e+" does not have remotestorage defined in the links section ",JSON.stringify(n.json)),r("WebFinger record for "+e+" does not have remotestorage defined in the links section.");const s=n.idx.links.remotestorage[0],a=s.properties["http://tools.ietf.org/html/rfc6749#section-4.2"]||s.properties["auth-endpoint"],h=s.properties["http://remotestorage.io/spec/version"]||s.type;return c[e]={href:s.href,storageApi:h,authURL:a,properties:s.properties},u&&(localStorage["remotestorage:discover"]=JSON.stringify({cache:c})),t(c[e])}))})};(h.DiscoveryError=function(e){this.name="DiscoveryError",this.message=e,this.stack=(new Error).stack}).prototype=Object.create(Error.prototype),h.DiscoveryError.prototype.constructor=h.DiscoveryError,h._rs_init=function(){if(u=(0,s.localStorageAvailable)(),u)try{const e=JSON.parse(localStorage["remotestorage:discover"]);c=e.cache}catch(e){}},h._rs_supported=function(){return a=Object.prototype.hasOwnProperty.call(s.globalContext,"XMLHttpRequest"),a},h._rs_cleanup=function(){u&&delete localStorage["remotestorage:discover"]},e.exports=h},function(e,t,r){"use strict";const o=(this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}})(r(2)),n=r(0);class i{constructor(){this.addEvents(["background","foreground"]),this.mode="undefined"!=typeof window?"browser":"node","browser"===this.mode&&(this.setBrowserPrefixedNames(),document.addEventListener(this.visibilityChangeEvent,this.setVisibility.bind(this),!1),this.setVisibility())}setBrowserPrefixedNames(){"browser"===this.mode&&(void 0!==document.hidden?(this.hiddenProperty="hidden",this.visibilityChangeEvent="visibilitychange"):void 0!==document.mozHidden?(this.hiddenProperty="mozHidden",this.visibilityChangeEvent="mozvisibilitychange"):void 0!==document.msHidden?(this.hiddenProperty="msHidden",this.visibilityChangeEvent="msvisibilitychange"):void 0!==document.webkitHidden&&(this.hiddenProperty="webkitHidden",this.visibilityChangeEvent="webkitvisibilitychange"))}setVisibility(){document[this.hiddenProperty]?this.goBackground():this.goForeground()}isBrowser(){return"browser"===this.mode}isNode(){return"node"===this.mode}goBackground(){this._emit("background")}goForeground(){this._emit("foreground")}static _rs_init(){}static _rs_cleanup(){}}(0,n.applyMixins)(i,[o.default]),e.exports=i},function(e,t,r){e.exports=r(19)},function(e,t,r){"use strict";var o=this&&this.__createBinding||(Object.create?function(e,t,r,o){void 0===o&&(o=r);var n=Object.getOwnPropertyDescriptor(t,r);n&&!("get"in n?!t.__esModule:n.writable||n.configurable)||(n={enumerable:!0,get:function(){return t[r]}}),Object.defineProperty(e,o,n)}:function(e,t,r,o){void 0===o&&(o=r),e[o]=t[r]}),n=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),i=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var r in e)"default"!==r&&Object.prototype.hasOwnProperty.call(e,r)&&o(t,e,r);return n(t,e),t},s=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const a=s(r(3)),u=s(r(1)),c=r(0),h=s(r(12)),l=s(r(4)),d=s(r(8)),f=s(r(13)),p=s(r(2)),m=s(r(14)),g=s(r(15)),y=s(r(16)),v=s(r(10)),_=s(r(5)),b=s(r(30)),w=i(r(0)),P=(0,c.getGlobalContext)();let E;function T(e){return 403!==e.statusCode&&401!==e.statusCode||this._emit("error",new _.default),Promise.resolve(e)}function A(e){return"number"==typeof e&&e>=2e3&&e<=36e5}class R{constructor(e){this._pending=[],this._cleanups=[],this._pathHandlers={change:{}},this.apiKeys={},this._init=b.default.loadFeatures,this.features=b.default.features,this.loadFeature=b.default.loadFeature,this.featureSupported=b.default.featureSupported,this.featureDone=b.default.featureDone,this.featuresDone=b.default.featuresDone,this.featuresLoaded=b.default.featuresLoaded,this.featureInitialized=b.default.featureInitialized,this.featureFailed=b.default.featureFailed,this.hasFeature=b.default.hasFeature,this._setCachingModule=b.default._setCachingModule,this._collectCleanupFunctions=b.default._collectCleanupFunctions,this._fireReady=b.default._fireReady,this.initFeature=b.default.initFeature,"object"==typeof e&&(0,c.extend)(a.default,e),this.addEvents(["ready","authing","connecting","connected","disconnected","not-connected","conflict","error","features-loaded","sync-interval-change","sync-req-done","sync-done","wire-busy","wire-done","network-offline","network-online"]),this._setGPD({get:this._pendingGPD("get"),put:this._pendingGPD("put"),delete:this._pendingGPD("delete")}),E=(0,c.localStorageAvailable)(),E&&(this.apiKeys=(0,c.getJSONFromLocalStorage)("remotestorage:api-keys")||{},this.setBackend(localStorage.getItem("remotestorage:backend")||"remotestorage"));const t=this.on;this.on=function(e,r){if(this._allLoaded)switch(e){case"features-loaded":setTimeout(r,0);break;case"ready":this.remote&&setTimeout(r,0);break;case"connected":this.remote&&this.remote.connected&&setTimeout(r,0);break;case"not-connected":this.remote&&!this.remote.connected&&setTimeout(r,0)}return t.call(this,e,r)},this._init(),this.fireInitial=function(){this.local&&setTimeout(this.local.fireInitial.bind(this.local),0)}.bind(this),this.on("ready",this.fireInitial.bind(this)),this.loadModules()}get connected(){return this.remote.connected}loadModules(){a.default.modules.forEach(this.addModule.bind(this))}authorize(e){if(this.access.setStorageType(this.remote.storageApi),void 0===e.scope&&(e.scope=this.access.scopeParameter),P.cordova)e.redirectUri=a.default.cordovaRedirectUri;else{const t=l.default.getLocation();let r=t.origin;"/"!==t.pathname&&(r+=t.pathname),e.redirectUri=r}void 0===e.clientId&&(e.clientId=e.redirectUri.match(/^(https?:\/\/[^/]+)/)[0]),l.default.authorize(this,e)}impliedauth(e,t){e=e||this.remote.storageApi,t=t||String(document.location),(0,u.default)("ImpliedAuth proceeding due to absent authURL; storageApi = "+e+" redirectUri = "+t),this.remote.configure({token:l.default.IMPLIED_FAKE_TOKEN}),document.location.href=t}connect(e,t){if(this.setBackend("remotestorage"),e.indexOf("@")<0&&!e.match(/^(https?:\/\/)?[^\s\/$\.?#]+\.[^\s]*$/))return void this._emit("error",new R.DiscoveryError("Not a valid user address or URL."));if(e.indexOf("@")<0&&!e.match(/^https?:\/\//)&&(e="https://"+e),P.cordova){if("string"!=typeof a.default.cordovaRedirectUri)return void this._emit("error",new R.DiscoveryError("Please supply a custom HTTPS redirect URI for your Cordova app"));if(!P.cordova.InAppBrowser)return void this._emit("error",new R.DiscoveryError("Please include the InAppBrowser Cordova plugin to enable OAuth"))}this.remote.configure({userAddress:e}),this._emit("connecting");const r=setTimeout(()=>{this._emit("error",new R.DiscoveryError("No storage information found for this user address."))},a.default.discoveryTimeout);(0,y.default)(e).then(o=>{if(clearTimeout(r),this._emit("authing"),o.userAddress=e,this.remote.configure(o),!this.remote.connected)if(o.authURL)if(void 0===t)this.authorize({authURL:o.authURL});else{if("string"!=typeof t)throw new Error("Supplied bearer token must be a string");(0,u.default)("Skipping authorization sequence and connecting with known token"),this.remote.configure({token:t})}else this.impliedauth()},()=>{clearTimeout(r),this._emit("error",new R.DiscoveryError("No storage information found for this user address."))})}reconnect(){this.remote.configure({token:null}),"remotestorage"===this.backend?this.connect(this.remote.userAddress):this.remote.connect()}disconnect(){this.remote&&this.remote.configure({userAddress:null,href:null,storageApi:null,token:null,properties:null}),this._setGPD({get:this._pendingGPD("get"),put:this._pendingGPD("put"),delete:this._pendingGPD("delete")});const e=this._cleanups.length;let t=0;const r=()=>{t++,t>=e&&(this._init(),this._emit("disconnected"))};e>0?this._cleanups.forEach(e=>{const t=e(this);"object"==typeof t&&"function"==typeof t.then?t.then(r):r()}):r()}setBackend(e){this.backend=e,E&&(e?localStorage.setItem("remotestorage:backend",e):localStorage.removeItem("remotestorage:backend"))}onChange(e,t){this._pathHandlers.change[e]||(this._pathHandlers.change[e]=[]),this._pathHandlers.change[e].push(t)}enableLog(){a.default.logging=!0}disableLog(){a.default.logging=!1}log(...e){u.default.apply(R,e)}setApiKeys(e){const t=[S.GOOGLE,S.DROPBOX];if("object"!=typeof e||!Object.keys(e).every(e=>t.includes(e)))return console.error("setApiKeys() was called with invalid arguments"),!1;Object.keys(e).forEach(t=>{const r=e[t];if(r){switch(t){case S.DROPBOX:this.apiKeys[S.DROPBOX]={appKey:r},void 0!==this.dropbox&&this.dropbox.clientId===r||g.default._rs_init(this);break;case S.GOOGLE:this.apiKeys[S.GOOGLE]={clientId:r},void 0!==this.googledrive&&this.googledrive.clientId===r||m.default._rs_init(this)}return!0}delete this.apiKeys[t]}),E&&localStorage.setItem("remotestorage:api-keys",JSON.stringify(this.apiKeys))}setCordovaRedirectUri(e){if("string"!=typeof e||!e.match(/http(s)?:\/\//))throw new Error("Cordova redirect URI must be a URI string");a.default.cordovaRedirectUri=e}_setGPD(e,t){function r(e){return function(...r){return e.apply(t,r).then(T.bind(this))}}this.get=r(e.get),this.put=r(e.put),this.delete=r(e.delete)}_pendingGPD(e){return(...t)=>{const r=Array.prototype.slice.call(t);return new Promise((t,o)=>{this._pending.push({method:e,args:r,promise:{resolve:t,reject:o}})})}}_processPending(){this._pending.forEach(e=>{try{this[e.method](...e.args).then(e.promise.resolve,e.promise.reject)}catch(t){e.promise.reject(t)}}),this._pending=[]}_bindChange(e){e.on("change",this._dispatchEvent.bind(this,"change"))}_dispatchEvent(e,t){Object.keys(this._pathHandlers[e]).forEach(r=>{const o=r.length;t.path.substr(0,o)===r&&this._pathHandlers[e][r].forEach(e=>{const o={};for(const e in t)o[e]=t[e];o.relativePath=t.path.replace(new RegExp("^"+r),"");try{e(o)}catch(e){console.error("'change' handler failed: ",e,e.stack),this._emit("error",e)}})})}scope(e){if("string"!=typeof e)throw"Argument 'path' of baseClient.scope must be a string";return this.access.checkPathPermission(e,"r")||console.warn("WARNING: Please use remoteStorage.access.claim() to ask for access permissions first: https://remotestoragejs.readthedocs.io/en/latest/js-api/access.html#claim"),new d.default(this,e)}getSyncInterval(){return a.default.syncInterval}setSyncInterval(e){if(!A(e))throw e+" is not a valid sync interval";const t=a.default.syncInterval;a.default.syncInterval=e,this._emit("sync-interval-change",{oldValue:t,newValue:e})}getBackgroundSyncInterval(){return a.default.backgroundSyncInterval}setBackgroundSyncInterval(e){if(!A(e))throw e+" is not a valid sync interval";const t=a.default.backgroundSyncInterval;a.default.backgroundSyncInterval=e,this._emit("sync-interval-change",{oldValue:t,newValue:e})}getCurrentSyncInterval(){return a.default.isBackground?a.default.backgroundSyncInterval:a.default.syncInterval}getRequestTimeout(){return a.default.requestTimeout}setRequestTimeout(e){if("number"!=typeof e)throw e+" is not a valid request timeout";a.default.requestTimeout=e}syncCycle(){this.sync&&!this.sync.stopped&&(this.on("sync-done",()=>{this.sync&&!this.sync.stopped&&(this._syncTimer&&(clearTimeout(this._syncTimer),this._syncTimer=void 0),this._syncTimer=setTimeout(this.sync.sync.bind(this.sync),this.getCurrentSyncInterval()))}),this.sync.sync())}startSync(){return a.default.cache?(this.sync.stopped=!1,this.syncStopped=!1,this.sync.sync()):(console.warn("Nothing to sync, because caching is disabled."),Promise.resolve())}stopSync(){clearTimeout(this._syncTimer),this._syncTimer=void 0,this.sync?this.sync.stopped=!0:this.syncStopped=!0}addModule(e){const t=e.name,r=e.builder;if(Object.defineProperty(this,t,{configurable:!0,get:function(){const e=this._loadModule(t,r);return Object.defineProperty(this,t,{value:e}),e}}),-1!==t.indexOf("-")){const e=t.replace(/\-[a-z]/g,(function(e){return e[1].toUpperCase()}));Object.defineProperty(this,e,{get:function(){return this[t]}})}}_loadModule(e,t){if(t){return t(new d.default(this,"/"+e+"/"),new d.default(this,"/public/"+e+"/")).exports}throw"Unknown module: "+e}}var S;R.Authorize=l.default,R.SyncError=v.default,R.Unauthorized=_.default,R.DiscoveryError=y.default.DiscoveryError,R.util=w,Object.defineProperty(R.prototype,"access",{get:function(){const e=new h.default;return Object.defineProperty(this,"access",{value:e}),e},configurable:!0}),Object.defineProperty(R.prototype,"caching",{configurable:!0,get:function(){const e=new f.default;return Object.defineProperty(this,"caching",{value:e}),e}}),(0,c.applyMixins)(R,[p.default]),function(e){e.GOOGLE="googledrive",e.DROPBOX="dropbox"}(S||(S={})),e.exports=R},function(e,t,r){"use strict";(function(e){ /*! * The buffer module from node.js, for the browser. * * @author Feross Aboukhadijeh * @license MIT */ -var n=r(20),o=r(21),i=r(22);function s(){return u.TYPED_ARRAY_SUPPORT?2147483647:1073741823}function a(e,t){if(s()=s())throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+s().toString(16)+" bytes");return 0|e}function p(e,t){if(u.isBuffer(e))return e.length;if("undefined"!=typeof ArrayBuffer&&"function"==typeof ArrayBuffer.isView&&(ArrayBuffer.isView(e)||e instanceof ArrayBuffer))return e.byteLength;"string"!=typeof e&&(e=""+e);var r=e.length;if(0===r)return 0;for(var n=!1;;)switch(t){case"ascii":case"latin1":case"binary":return r;case"utf8":case"utf-8":case void 0:return B(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*r;case"hex":return r>>>1;case"base64":return q(e).length;default:if(n)return B(e).length;t=(""+t).toLowerCase(),n=!0}}function m(e,t,r){var n=!1;if((void 0===t||t<0)&&(t=0),t>this.length)return"";if((void 0===r||r>this.length)&&(r=this.length),r<=0)return"";if((r>>>=0)<=(t>>>=0))return"";for(e||(e="utf8");;)switch(e){case"hex":return k(this,t,r);case"utf8":case"utf-8":return R(this,t,r);case"ascii":return S(this,t,r);case"latin1":case"binary":return O(this,t,r);case"base64":return A(this,t,r);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return M(this,t,r);default:if(n)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),n=!0}}function g(e,t,r){var n=e[t];e[t]=e[r],e[r]=n}function y(e,t,r,n,o){if(0===e.length)return-1;if("string"==typeof r?(n=r,r=0):r>2147483647?r=2147483647:r<-2147483648&&(r=-2147483648),r=+r,isNaN(r)&&(r=o?0:e.length-1),r<0&&(r=e.length+r),r>=e.length){if(o)return-1;r=e.length-1}else if(r<0){if(!o)return-1;r=0}if("string"==typeof t&&(t=u.from(t,n)),u.isBuffer(t))return 0===t.length?-1:v(e,t,r,n,o);if("number"==typeof t)return t&=255,u.TYPED_ARRAY_SUPPORT&&"function"==typeof Uint8Array.prototype.indexOf?o?Uint8Array.prototype.indexOf.call(e,t,r):Uint8Array.prototype.lastIndexOf.call(e,t,r):v(e,[t],r,n,o);throw new TypeError("val must be string, number or Buffer")}function v(e,t,r,n,o){var i,s=1,a=e.length,u=t.length;if(void 0!==n&&("ucs2"===(n=String(n).toLowerCase())||"ucs-2"===n||"utf16le"===n||"utf-16le"===n)){if(e.length<2||t.length<2)return-1;s=2,a/=2,u/=2,r/=2}function c(e,t){return 1===s?e[t]:e.readUInt16BE(t*s)}if(o){var h=-1;for(i=r;ia&&(r=a-u),i=r;i>=0;i--){for(var l=!0,d=0;do&&(n=o):n=o;var i=t.length;if(i%2!=0)throw new TypeError("Invalid hex string");n>i/2&&(n=i/2);for(var s=0;s>8,o=r%256,i.push(o),i.push(n);return i}(t,e.length-r),e,r,n)}function A(e,t,r){return 0===t&&r===e.length?n.fromByteArray(e):n.fromByteArray(e.slice(t,r))}function R(e,t,r){r=Math.min(e.length,r);for(var n=[],o=t;o239?4:c>223?3:c>191?2:1;if(o+l<=r)switch(l){case 1:c<128&&(h=c);break;case 2:128==(192&(i=e[o+1]))&&(u=(31&c)<<6|63&i)>127&&(h=u);break;case 3:i=e[o+1],s=e[o+2],128==(192&i)&&128==(192&s)&&(u=(15&c)<<12|(63&i)<<6|63&s)>2047&&(u<55296||u>57343)&&(h=u);break;case 4:i=e[o+1],s=e[o+2],a=e[o+3],128==(192&i)&&128==(192&s)&&128==(192&a)&&(u=(15&c)<<18|(63&i)<<12|(63&s)<<6|63&a)>65535&&u<1114112&&(h=u)}null===h?(h=65533,l=1):h>65535&&(h-=65536,n.push(h>>>10&1023|55296),h=56320|1023&h),n.push(h),o+=l}return function(e){var t=e.length;if(t<=4096)return String.fromCharCode.apply(String,e);var r="",n=0;for(;n0&&(e=this.toString("hex",0,r).match(/.{2}/g).join(" "),this.length>r&&(e+=" ... ")),""},u.prototype.compare=function(e,t,r,n,o){if(!u.isBuffer(e))throw new TypeError("Argument must be a Buffer");if(void 0===t&&(t=0),void 0===r&&(r=e?e.length:0),void 0===n&&(n=0),void 0===o&&(o=this.length),t<0||r>e.length||n<0||o>this.length)throw new RangeError("out of range index");if(n>=o&&t>=r)return 0;if(n>=o)return-1;if(t>=r)return 1;if(this===e)return 0;for(var i=(o>>>=0)-(n>>>=0),s=(r>>>=0)-(t>>>=0),a=Math.min(i,s),c=this.slice(n,o),h=e.slice(t,r),l=0;lo)&&(r=o),e.length>0&&(r<0||t<0)||t>this.length)throw new RangeError("Attempt to write outside buffer bounds");n||(n="utf8");for(var i=!1;;)switch(n){case"hex":return _(this,e,t,r);case"utf8":case"utf-8":return b(this,e,t,r);case"ascii":return w(this,e,t,r);case"latin1":case"binary":return P(this,e,t,r);case"base64":return E(this,e,t,r);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return T(this,e,t,r);default:if(i)throw new TypeError("Unknown encoding: "+n);n=(""+n).toLowerCase(),i=!0}},u.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};function S(e,t,r){var n="";r=Math.min(e.length,r);for(var o=t;on)&&(r=n);for(var o="",i=t;ir)throw new RangeError("Trying to access beyond buffer length")}function I(e,t,r,n,o,i){if(!u.isBuffer(e))throw new TypeError('"buffer" argument must be a Buffer instance');if(t>o||te.length)throw new RangeError("Index out of range")}function x(e,t,r,n){t<0&&(t=65535+t+1);for(var o=0,i=Math.min(e.length-r,2);o>>8*(n?o:1-o)}function N(e,t,r,n){t<0&&(t=4294967295+t+1);for(var o=0,i=Math.min(e.length-r,4);o>>8*(n?o:3-o)&255}function j(e,t,r,n,o,i){if(r+n>e.length)throw new RangeError("Index out of range");if(r<0)throw new RangeError("Index out of range")}function U(e,t,r,n,i){return i||j(e,0,r,4),o.write(e,t,r,n,23,4),r+4}function F(e,t,r,n,i){return i||j(e,0,r,8),o.write(e,t,r,n,52,8),r+8}u.prototype.slice=function(e,t){var r,n=this.length;if((e=~~e)<0?(e+=n)<0&&(e=0):e>n&&(e=n),(t=void 0===t?n:~~t)<0?(t+=n)<0&&(t=0):t>n&&(t=n),t0&&(o*=256);)n+=this[e+--t]*o;return n},u.prototype.readUInt8=function(e,t){return t||C(e,1,this.length),this[e]},u.prototype.readUInt16LE=function(e,t){return t||C(e,2,this.length),this[e]|this[e+1]<<8},u.prototype.readUInt16BE=function(e,t){return t||C(e,2,this.length),this[e]<<8|this[e+1]},u.prototype.readUInt32LE=function(e,t){return t||C(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+16777216*this[e+3]},u.prototype.readUInt32BE=function(e,t){return t||C(e,4,this.length),16777216*this[e]+(this[e+1]<<16|this[e+2]<<8|this[e+3])},u.prototype.readIntLE=function(e,t,r){e|=0,t|=0,r||C(e,t,this.length);for(var n=this[e],o=1,i=0;++i=(o*=128)&&(n-=Math.pow(2,8*t)),n},u.prototype.readIntBE=function(e,t,r){e|=0,t|=0,r||C(e,t,this.length);for(var n=t,o=1,i=this[e+--n];n>0&&(o*=256);)i+=this[e+--n]*o;return i>=(o*=128)&&(i-=Math.pow(2,8*t)),i},u.prototype.readInt8=function(e,t){return t||C(e,1,this.length),128&this[e]?-1*(255-this[e]+1):this[e]},u.prototype.readInt16LE=function(e,t){t||C(e,2,this.length);var r=this[e]|this[e+1]<<8;return 32768&r?4294901760|r:r},u.prototype.readInt16BE=function(e,t){t||C(e,2,this.length);var r=this[e+1]|this[e]<<8;return 32768&r?4294901760|r:r},u.prototype.readInt32LE=function(e,t){return t||C(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},u.prototype.readInt32BE=function(e,t){return t||C(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},u.prototype.readFloatLE=function(e,t){return t||C(e,4,this.length),o.read(this,e,!0,23,4)},u.prototype.readFloatBE=function(e,t){return t||C(e,4,this.length),o.read(this,e,!1,23,4)},u.prototype.readDoubleLE=function(e,t){return t||C(e,8,this.length),o.read(this,e,!0,52,8)},u.prototype.readDoubleBE=function(e,t){return t||C(e,8,this.length),o.read(this,e,!1,52,8)},u.prototype.writeUIntLE=function(e,t,r,n){(e=+e,t|=0,r|=0,n)||I(this,e,t,r,Math.pow(2,8*r)-1,0);var o=1,i=0;for(this[t]=255&e;++i=0&&(i*=256);)this[t+o]=e/i&255;return t+r},u.prototype.writeUInt8=function(e,t,r){return e=+e,t|=0,r||I(this,e,t,1,255,0),u.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),this[t]=255&e,t+1},u.prototype.writeUInt16LE=function(e,t,r){return e=+e,t|=0,r||I(this,e,t,2,65535,0),u.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):x(this,e,t,!0),t+2},u.prototype.writeUInt16BE=function(e,t,r){return e=+e,t|=0,r||I(this,e,t,2,65535,0),u.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):x(this,e,t,!1),t+2},u.prototype.writeUInt32LE=function(e,t,r){return e=+e,t|=0,r||I(this,e,t,4,4294967295,0),u.TYPED_ARRAY_SUPPORT?(this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=255&e):N(this,e,t,!0),t+4},u.prototype.writeUInt32BE=function(e,t,r){return e=+e,t|=0,r||I(this,e,t,4,4294967295,0),u.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):N(this,e,t,!1),t+4},u.prototype.writeIntLE=function(e,t,r,n){if(e=+e,t|=0,!n){var o=Math.pow(2,8*r-1);I(this,e,t,r,o-1,-o)}var i=0,s=1,a=0;for(this[t]=255&e;++i>0)-a&255;return t+r},u.prototype.writeIntBE=function(e,t,r,n){if(e=+e,t|=0,!n){var o=Math.pow(2,8*r-1);I(this,e,t,r,o-1,-o)}var i=r-1,s=1,a=0;for(this[t+i]=255&e;--i>=0&&(s*=256);)e<0&&0===a&&0!==this[t+i+1]&&(a=1),this[t+i]=(e/s>>0)-a&255;return t+r},u.prototype.writeInt8=function(e,t,r){return e=+e,t|=0,r||I(this,e,t,1,127,-128),u.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),e<0&&(e=255+e+1),this[t]=255&e,t+1},u.prototype.writeInt16LE=function(e,t,r){return e=+e,t|=0,r||I(this,e,t,2,32767,-32768),u.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):x(this,e,t,!0),t+2},u.prototype.writeInt16BE=function(e,t,r){return e=+e,t|=0,r||I(this,e,t,2,32767,-32768),u.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):x(this,e,t,!1),t+2},u.prototype.writeInt32LE=function(e,t,r){return e=+e,t|=0,r||I(this,e,t,4,2147483647,-2147483648),u.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24):N(this,e,t,!0),t+4},u.prototype.writeInt32BE=function(e,t,r){return e=+e,t|=0,r||I(this,e,t,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),u.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):N(this,e,t,!1),t+4},u.prototype.writeFloatLE=function(e,t,r){return U(this,e,t,!0,r)},u.prototype.writeFloatBE=function(e,t,r){return U(this,e,t,!1,r)},u.prototype.writeDoubleLE=function(e,t,r){return F(this,e,t,!0,r)},u.prototype.writeDoubleBE=function(e,t,r){return F(this,e,t,!1,r)},u.prototype.copy=function(e,t,r,n){if(r||(r=0),n||0===n||(n=this.length),t>=e.length&&(t=e.length),t||(t=0),n>0&&n=this.length)throw new RangeError("sourceStart out of bounds");if(n<0)throw new RangeError("sourceEnd out of bounds");n>this.length&&(n=this.length),e.length-t=0;--o)e[o+t]=this[o+r];else if(i<1e3||!u.TYPED_ARRAY_SUPPORT)for(o=0;o>>=0,r=void 0===r?this.length:r>>>0,e||(e=0),"number"==typeof e)for(i=t;i55295&&r<57344){if(!o){if(r>56319){(t-=3)>-1&&i.push(239,191,189);continue}if(s+1===n){(t-=3)>-1&&i.push(239,191,189);continue}o=r;continue}if(r<56320){(t-=3)>-1&&i.push(239,191,189),o=r;continue}r=65536+(o-55296<<10|r-56320)}else o&&(t-=3)>-1&&i.push(239,191,189);if(o=null,r<128){if((t-=1)<0)break;i.push(r)}else if(r<2048){if((t-=2)<0)break;i.push(r>>6|192,63&r|128)}else if(r<65536){if((t-=3)<0)break;i.push(r>>12|224,r>>6&63|128,63&r|128)}else{if(!(r<1114112))throw new Error("Invalid code point");if((t-=4)<0)break;i.push(r>>18|240,r>>12&63|128,r>>6&63|128,63&r|128)}}return i}function q(e){return n.toByteArray(function(e){if((e=function(e){return e.trim?e.trim():e.replace(/^\s+|\s+$/g,"")}(e).replace(D,"")).length<2)return"";for(;e.length%4!=0;)e+="=";return e}(e))}function J(e,t,r,n){for(var o=0;o=t.length||o>=e.length);++o)t[o+r]=e[o];return o}}).call(this,r(5))},function(e,t,r){"use strict";t.byteLength=function(e){var t=c(e),r=t[0],n=t[1];return 3*(r+n)/4-n},t.toByteArray=function(e){var t,r,n=c(e),s=n[0],a=n[1],u=new i(function(e,t,r){return 3*(t+r)/4-r}(0,s,a)),h=0,l=a>0?s-4:s;for(r=0;r>16&255,u[h++]=t>>8&255,u[h++]=255&t;2===a&&(t=o[e.charCodeAt(r)]<<2|o[e.charCodeAt(r+1)]>>4,u[h++]=255&t);1===a&&(t=o[e.charCodeAt(r)]<<10|o[e.charCodeAt(r+1)]<<4|o[e.charCodeAt(r+2)]>>2,u[h++]=t>>8&255,u[h++]=255&t);return u},t.fromByteArray=function(e){for(var t,r=e.length,o=r%3,i=[],s=0,a=r-o;sa?a:s+16383));1===o?(t=e[r-1],i.push(n[t>>2]+n[t<<4&63]+"==")):2===o&&(t=(e[r-2]<<8)+e[r-1],i.push(n[t>>10]+n[t>>4&63]+n[t<<2&63]+"="));return i.join("")};for(var n=[],o=[],i="undefined"!=typeof Uint8Array?Uint8Array:Array,s="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",a=0,u=s.length;a0)throw new Error("Invalid string. Length must be a multiple of 4");var r=e.indexOf("=");return-1===r&&(r=t),[r,r===t?0:4-r%4]}function h(e,t,r){for(var o,i,s=[],a=t;a>18&63]+n[i>>12&63]+n[i>>6&63]+n[63&i]);return s.join("")}o["-".charCodeAt(0)]=62,o["_".charCodeAt(0)]=63},function(e,t){t.read=function(e,t,r,n,o){var i,s,a=8*o-n-1,u=(1<>1,h=-7,l=r?o-1:0,d=r?-1:1,f=e[t+l];for(l+=d,i=f&(1<<-h)-1,f>>=-h,h+=a;h>0;i=256*i+e[t+l],l+=d,h-=8);for(s=i&(1<<-h)-1,i>>=-h,h+=n;h>0;s=256*s+e[t+l],l+=d,h-=8);if(0===i)i=1-c;else{if(i===u)return s?NaN:1/0*(f?-1:1);s+=Math.pow(2,n),i-=c}return(f?-1:1)*s*Math.pow(2,i-n)},t.write=function(e,t,r,n,o,i){var s,a,u,c=8*i-o-1,h=(1<>1,d=23===o?Math.pow(2,-24)-Math.pow(2,-77):0,f=n?0:i-1,p=n?1:-1,m=t<0||0===t&&1/t<0?1:0;for(t=Math.abs(t),isNaN(t)||t===1/0?(a=isNaN(t)?1:0,s=h):(s=Math.floor(Math.log(t)/Math.LN2),t*(u=Math.pow(2,-s))<1&&(s--,u*=2),(t+=s+l>=1?d/u:d*Math.pow(2,1-l))*u>=2&&(s++,u/=2),s+l>=h?(a=0,s=h):s+l>=1?(a=(t*u-1)*Math.pow(2,o),s+=l):(a=t*Math.pow(2,l-1)*Math.pow(2,o),s=0));o>=8;e[r+f]=255&a,f+=p,a/=256,o-=8);for(s=s<0;e[r+f]=255&s,f+=p,s/=256,c-=8);e[r+f-p]|=128*m}},function(e,t){var r={}.toString;e.exports=Array.isArray||function(e){return"[object Array]"==r.call(e)}},function(e,t,r){var n,o,i;o=[],void 0===(i="function"==typeof(n=function(){var e,t,r,n;Object.keys||(Object.keys=(e=Object.prototype.hasOwnProperty,t=!{toString:null}.propertyIsEnumerable("toString"),n=(r=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"]).length,function(o){if("object"!=typeof o&&"function"!=typeof o||null===o)throw new TypeError("Object.keys called on non-object");var i=[];for(var s in o)e.call(o,s)&&i.push(s);if(t)for(var a=0;a>>0;if(0===r)return-1;var n=0;if(arguments.length>1&&((n=Number(arguments[1]))!=n?n=0:0!==n&&n!==1/0&&n!==-1/0&&(n=(n>0||-1)*Math.floor(Math.abs(n)))),n>=r)return-1;for(var o=n>=0?n:Math.max(r-Math.abs(n),0);o0&&(t+=h.suffices["*"]&&r||",",h.suffices["*"]&&u&&(t+=h.name+"=")),t+=a?encodeURIComponent(l[f]).replace(/!/g,"%21"):s(l[f])}else if("object"==typeof l){u&&!h.suffices["*"]&&(t+=h.name+"=");var p=!0;for(var m in l)p||(t+=h.suffices["*"]&&r||","),p=!1,t+=a?encodeURIComponent(m).replace(/!/g,"%21"):s(m),t+=h.suffices["*"]?"=":",",t+=a?encodeURIComponent(l[m]).replace(/!/g,"%21"):s(l[m])}else u&&(t+=h.name,c&&""===l||(t+="=")),null!=h.truncate&&(l=l.substring(0,h.truncate)),t+=a?encodeURIComponent(l).replace(/!/g,"%21"):s(l)}return t};return b.varNames=h,{prefix:n,substitution:b}}function u(e){if(!(this instanceof u))return new u(e);for(var t=e.split("{"),r=[t.shift()],n=[],o=[],i=[];t.length>0;){var s=t.shift(),c=s.split("}")[0],h=s.substring(c.length+1),l=a(c);o.push(l.substitution),n.push(l.prefix),r.push(h),i=i.concat(l.substitution.varNames)}this.fill=function(e){for(var t=r[0],n=0;n0&&"/"===t.charAt(e.length-1)||"#"===r.charAt(0)||"?"===r.charAt(0))return!0}return!1}(t,e.id)&&void 0===this.schemas[e.id]&&(this.schemas[e.id]=e),e)if("enum"!==n)if("object"==typeof e[n])this.searchSchemas(e[n],t);else if("$ref"===n){var o=m(e[n]);o&&void 0===this.schemas[o]&&void 0===this.missingMap[o]&&(this.missingMap[o]=o)}},c.prototype.addSchema=function(e,t){if("string"!=typeof e||void 0===t){if("object"!=typeof e||"string"!=typeof e.id)return;e=(t=e).id}e===m(e)+"#"&&(e=m(e)),this.schemas[e]=t,delete this.missingMap[e],g(t,e),this.searchSchemas(t,e)},c.prototype.getSchemaMap=function(){var e={};for(var t in this.schemas)e[t]=this.schemas[t];return e},c.prototype.getSchemaUris=function(e){var t=[];for(var r in this.schemas)e&&!e.test(r)||t.push(r);return t},c.prototype.getMissingUris=function(e){var t=[];for(var r in this.missingMap)e&&!e.test(r)||t.push(r);return t},c.prototype.dropSchemas=function(){this.schemas={},this.reset()},c.prototype.reset=function(){this.missing=[],this.missingMap={},this.errors=[]},c.prototype.validateAll=function(e,t,r,n,o){var i;if(!(t=this.resolveRefs(t)))return null;if(t instanceof P)return this.errors.push(t),t;var s,a=this.errors.length,u=null,c=null;if(this.checkRecursive&&e&&"object"==typeof e){if(i=!this.scanned.length,e[this.validatedSchemasKey]){var h=e[this.validatedSchemasKey].indexOf(t);if(-1!==h)return this.errors=this.errors.concat(e[this.validationErrorsKey][h]),null}if(Object.isFrozen(e)&&-1!==(s=this.scannedFrozen.indexOf(e))){var l=this.scannedFrozenSchemas[s].indexOf(t);if(-1!==l)return this.errors=this.errors.concat(this.scannedFrozenValidationErrors[s][l]),null}if(this.scanned.push(e),Object.isFrozen(e))-1===s&&(s=this.scannedFrozen.length,this.scannedFrozen.push(e),this.scannedFrozenSchemas.push([])),u=this.scannedFrozenSchemas[s].length,this.scannedFrozenSchemas[s][u]=t,this.scannedFrozenValidationErrors[s][u]=[];else{if(!e[this.validatedSchemasKey])try{Object.defineProperty(e,this.validatedSchemasKey,{value:[],configurable:!0}),Object.defineProperty(e,this.validationErrorsKey,{value:[],configurable:!0})}catch(t){e[this.validatedSchemasKey]=[],e[this.validationErrorsKey]=[]}c=e[this.validatedSchemasKey].length,e[this.validatedSchemasKey][c]=t,e[this.validationErrorsKey][c]=[]}}var d=this.errors.length,f=this.validateBasic(e,t,o)||this.validateNumeric(e,t,o)||this.validateString(e,t,o)||this.validateArray(e,t,o)||this.validateObject(e,t,o)||this.validateCombinations(e,t,o)||this.validateHypermedia(e,t,o)||this.validateFormat(e,t,o)||this.validateDefinedKeywords(e,t,o)||null;if(i){for(;this.scanned.length;)delete this.scanned.pop()[this.validatedSchemasKey];this.scannedFrozen=[],this.scannedFrozenSchemas=[]}if(f||d!==this.errors.length)for(;r&&r.length||n&&n.length;){var p=r&&r.length?""+r.pop():null,m=n&&n.length?""+n.pop():null;f&&(f=f.prefixWith(p,m)),this.prefixErrors(d,p,m)}return null!==u?this.scannedFrozenValidationErrors[s][u]=this.errors.slice(a):null!==c&&(e[this.validationErrorsKey][c]=this.errors.slice(a)),this.handleError(f)},c.prototype.validateFormat=function(e,t){if("string"!=typeof t.format||!this.formatValidators[t.format])return null;var r=this.formatValidators[t.format].call(null,e,t);return"string"==typeof r||"number"==typeof r?this.createError(v.FORMAT_CUSTOM,{message:r},"","/format",null,e,t):r&&"object"==typeof r?this.createError(v.FORMAT_CUSTOM,{message:r.message||"?"},r.dataPath||"",r.schemaPath||"/format",null,e,t):null},c.prototype.validateDefinedKeywords=function(e,t,r){for(var n in this.definedKeywords)if(void 0!==t[n])for(var o=this.definedKeywords[n],i=0;i=l&&nt.maximum)return this.createError(v.NUMBER_MAXIMUM,{value:e,maximum:t.maximum},"","/maximum",null,e,t);if(t.exclusiveMaximum&&e===t.maximum)return this.createError(v.NUMBER_MAXIMUM_EXCLUSIVE,{value:e,maximum:t.maximum},"","/exclusiveMaximum",null,e,t)}return null},c.prototype.validateNaN=function(e,t){return"number"!=typeof e?null:!0===isNaN(e)||e===1/0||e===-1/0?this.createError(v.NUMBER_NOT_A_NUMBER,{value:e},"","/type",null,e,t):null},c.prototype.validateString=function(e,t,r){return this.validateStringLength(e,t,r)||this.validateStringPattern(e,t,r)||null},c.prototype.validateStringLength=function(e,t){return"string"!=typeof e?null:void 0!==t.minLength&&e.lengtht.maxLength?this.createError(v.STRING_LENGTH_LONG,{length:e.length,maximum:t.maxLength},"","/maxLength",null,e,t):null},c.prototype.validateStringPattern=function(e,t){if("string"!=typeof e||"string"!=typeof t.pattern&&!(t.pattern instanceof RegExp))return null;var r;if(t.pattern instanceof RegExp)r=t.pattern;else{var n,o="",i=t.pattern.match(/^\/(.+)\/([img]*)$/);i?(n=i[1],o=i[2]):n=t.pattern,r=new RegExp(n,o)}return r.test(e)?null:this.createError(v.STRING_PATTERN,{pattern:t.pattern},"","/pattern",null,e,t)},c.prototype.validateArray=function(e,t,r){return Array.isArray(e)&&(this.validateArrayLength(e,t,r)||this.validateArrayUniqueItems(e,t,r)||this.validateArrayItems(e,t,r))||null},c.prototype.validateArrayLength=function(e,t){var r;return void 0!==t.minItems&&e.lengtht.maxItems&&(r=this.createError(v.ARRAY_LENGTH_LONG,{length:e.length,maximum:t.maxItems},"","/maxItems",null,e,t),this.handleError(r))?r:null},c.prototype.validateArrayUniqueItems=function(e,t){if(t.uniqueItems)for(var r=0;rt.maxProperties&&(r=this.createError(v.OBJECT_PROPERTIES_MAXIMUM,{propertyCount:n.length,maximum:t.maxProperties},"","/maxProperties",null,e,t),this.handleError(r))?r:null},c.prototype.validateObjectRequiredProperties=function(e,t){if(void 0!==t.required)for(var r=0;r 10000");if(void 0!==v[e])throw new Error("Error already defined: "+e+" as "+v[e]);if(void 0!==_[t])throw new Error("Error code already used: "+_[t]+" as "+t);for(var n in v[e]=t,_[t]=e,w[e]=w[t]=r,E){var o=E[n];o[e]&&(o[t]=o[t]||o[e])}},reset:function(){o.reset(),this.error=null,this.missing=[],this.valid=!0},missing:[],error:null,valid:!0,normSchema:g,resolveUrl:p,getDocumentUri:m,errorCodes:v};return i.language(t||"en"),i}();return T.addLanguage("en-gb",w),T.tv4=T,T})?n.apply(t,o):n)||(e.exports=i)},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.BaseClientTypes=void 0;class n{constructor(){this.uris={},this.schemas={},this.aliases={}}declare(e,t,r,n){const o=e+"/"+t;if(n.extends){const t=n.extends.split("/"),r=1===t.length?e+"/"+t.shift():t.join("/"),i=this.uris[r];if(!i)throw"Type '"+o+"' tries to extend unknown schema '"+r+"'";n.extends=this.schemas[i]}this.uris[o]=r,this.aliases[r]=o,this.schemas[r]=n}resolveAlias(e){return this.uris[e]}getSchema(e){return this.schemas[e]}inScope(e){const t=e.length,r={};for(const n in this.uris)if(n.substr(0,t+1)===e+"/"){const e=this.uris[n];r[e]=this.schemas[e]}return r}}t.BaseClientTypes=n;const o=new n;t.default=o},function(e,t,r){"use strict";class n extends Error{constructor(e){super();const t=new Error("Schema not found: "+e);return t.name="SchemaNotFound",t}}e.exports=n},function(e,t,r){"use strict";e.exports=class{constructor(e){this._itemsRev={},this._storage={},this._canPropagate=!1,this.defaultValue=e,this.activatePropagation()}get(e){e=e.toLowerCase();let t=this._storage[e];return void 0===t&&(t=this.defaultValue,this._storage[e]=t),t}set(e,t){return e=e.toLowerCase(),this._storage[e]===t?t:(this._storage[e]=t,t||delete this._itemsRev[e],this._updateParentFolderItemRev(e,t),this._canPropagate&&this._propagate(e),t)}delete(e){return this.set(e,null)}deactivatePropagation(){return this._canPropagate=!1,!0}activatePropagation(){return!!this._canPropagate||(this._generateFolderRev("/"),this._canPropagate=!0,!0)}_hashCode(e){let t=0;if(0===e.length)return t;for(let r=0;r0&&(r=this._generateHash(e))}return this.set(e,r),r}}},function(e,t,r){var n; +var o=r(21),n=r(22),i=r(23);function s(){return u.TYPED_ARRAY_SUPPORT?2147483647:1073741823}function a(e,t){if(s()=s())throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+s().toString(16)+" bytes");return 0|e}function p(e,t){if(u.isBuffer(e))return e.length;if("undefined"!=typeof ArrayBuffer&&"function"==typeof ArrayBuffer.isView&&(ArrayBuffer.isView(e)||e instanceof ArrayBuffer))return e.byteLength;"string"!=typeof e&&(e=""+e);var r=e.length;if(0===r)return 0;for(var o=!1;;)switch(t){case"ascii":case"latin1":case"binary":return r;case"utf8":case"utf-8":case void 0:return B(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*r;case"hex":return r>>>1;case"base64":return q(e).length;default:if(o)return B(e).length;t=(""+t).toLowerCase(),o=!0}}function m(e,t,r){var o=!1;if((void 0===t||t<0)&&(t=0),t>this.length)return"";if((void 0===r||r>this.length)&&(r=this.length),r<=0)return"";if((r>>>=0)<=(t>>>=0))return"";for(e||(e="utf8");;)switch(e){case"hex":return M(this,t,r);case"utf8":case"utf-8":return R(this,t,r);case"ascii":return S(this,t,r);case"latin1":case"binary":return k(this,t,r);case"base64":return A(this,t,r);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return O(this,t,r);default:if(o)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),o=!0}}function g(e,t,r){var o=e[t];e[t]=e[r],e[r]=o}function y(e,t,r,o,n){if(0===e.length)return-1;if("string"==typeof r?(o=r,r=0):r>2147483647?r=2147483647:r<-2147483648&&(r=-2147483648),r=+r,isNaN(r)&&(r=n?0:e.length-1),r<0&&(r=e.length+r),r>=e.length){if(n)return-1;r=e.length-1}else if(r<0){if(!n)return-1;r=0}if("string"==typeof t&&(t=u.from(t,o)),u.isBuffer(t))return 0===t.length?-1:v(e,t,r,o,n);if("number"==typeof t)return t&=255,u.TYPED_ARRAY_SUPPORT&&"function"==typeof Uint8Array.prototype.indexOf?n?Uint8Array.prototype.indexOf.call(e,t,r):Uint8Array.prototype.lastIndexOf.call(e,t,r):v(e,[t],r,o,n);throw new TypeError("val must be string, number or Buffer")}function v(e,t,r,o,n){var i,s=1,a=e.length,u=t.length;if(void 0!==o&&("ucs2"===(o=String(o).toLowerCase())||"ucs-2"===o||"utf16le"===o||"utf-16le"===o)){if(e.length<2||t.length<2)return-1;s=2,a/=2,u/=2,r/=2}function c(e,t){return 1===s?e[t]:e.readUInt16BE(t*s)}if(n){var h=-1;for(i=r;ia&&(r=a-u),i=r;i>=0;i--){for(var l=!0,d=0;dn&&(o=n):o=n;var i=t.length;if(i%2!=0)throw new TypeError("Invalid hex string");o>i/2&&(o=i/2);for(var s=0;s>8,n=r%256,i.push(n),i.push(o);return i}(t,e.length-r),e,r,o)}function A(e,t,r){return 0===t&&r===e.length?o.fromByteArray(e):o.fromByteArray(e.slice(t,r))}function R(e,t,r){r=Math.min(e.length,r);for(var o=[],n=t;n239?4:c>223?3:c>191?2:1;if(n+l<=r)switch(l){case 1:c<128&&(h=c);break;case 2:128==(192&(i=e[n+1]))&&(u=(31&c)<<6|63&i)>127&&(h=u);break;case 3:i=e[n+1],s=e[n+2],128==(192&i)&&128==(192&s)&&(u=(15&c)<<12|(63&i)<<6|63&s)>2047&&(u<55296||u>57343)&&(h=u);break;case 4:i=e[n+1],s=e[n+2],a=e[n+3],128==(192&i)&&128==(192&s)&&128==(192&a)&&(u=(15&c)<<18|(63&i)<<12|(63&s)<<6|63&a)>65535&&u<1114112&&(h=u)}null===h?(h=65533,l=1):h>65535&&(h-=65536,o.push(h>>>10&1023|55296),h=56320|1023&h),o.push(h),n+=l}return function(e){var t=e.length;if(t<=4096)return String.fromCharCode.apply(String,e);var r="",o=0;for(;o0&&(e=this.toString("hex",0,r).match(/.{2}/g).join(" "),this.length>r&&(e+=" ... ")),""},u.prototype.compare=function(e,t,r,o,n){if(!u.isBuffer(e))throw new TypeError("Argument must be a Buffer");if(void 0===t&&(t=0),void 0===r&&(r=e?e.length:0),void 0===o&&(o=0),void 0===n&&(n=this.length),t<0||r>e.length||o<0||n>this.length)throw new RangeError("out of range index");if(o>=n&&t>=r)return 0;if(o>=n)return-1;if(t>=r)return 1;if(this===e)return 0;for(var i=(n>>>=0)-(o>>>=0),s=(r>>>=0)-(t>>>=0),a=Math.min(i,s),c=this.slice(o,n),h=e.slice(t,r),l=0;ln)&&(r=n),e.length>0&&(r<0||t<0)||t>this.length)throw new RangeError("Attempt to write outside buffer bounds");o||(o="utf8");for(var i=!1;;)switch(o){case"hex":return _(this,e,t,r);case"utf8":case"utf-8":return b(this,e,t,r);case"ascii":return w(this,e,t,r);case"latin1":case"binary":return P(this,e,t,r);case"base64":return E(this,e,t,r);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return T(this,e,t,r);default:if(i)throw new TypeError("Unknown encoding: "+o);o=(""+o).toLowerCase(),i=!0}},u.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};function S(e,t,r){var o="";r=Math.min(e.length,r);for(var n=t;no)&&(r=o);for(var n="",i=t;ir)throw new RangeError("Trying to access beyond buffer length")}function x(e,t,r,o,n,i){if(!u.isBuffer(e))throw new TypeError('"buffer" argument must be a Buffer instance');if(t>n||te.length)throw new RangeError("Index out of range")}function I(e,t,r,o){t<0&&(t=65535+t+1);for(var n=0,i=Math.min(e.length-r,2);n>>8*(o?n:1-n)}function N(e,t,r,o){t<0&&(t=4294967295+t+1);for(var n=0,i=Math.min(e.length-r,4);n>>8*(o?n:3-n)&255}function U(e,t,r,o,n,i){if(r+o>e.length)throw new RangeError("Index out of range");if(r<0)throw new RangeError("Index out of range")}function j(e,t,r,o,i){return i||U(e,0,r,4),n.write(e,t,r,o,23,4),r+4}function F(e,t,r,o,i){return i||U(e,0,r,8),n.write(e,t,r,o,52,8),r+8}u.prototype.slice=function(e,t){var r,o=this.length;if((e=~~e)<0?(e+=o)<0&&(e=0):e>o&&(e=o),(t=void 0===t?o:~~t)<0?(t+=o)<0&&(t=0):t>o&&(t=o),t0&&(n*=256);)o+=this[e+--t]*n;return o},u.prototype.readUInt8=function(e,t){return t||C(e,1,this.length),this[e]},u.prototype.readUInt16LE=function(e,t){return t||C(e,2,this.length),this[e]|this[e+1]<<8},u.prototype.readUInt16BE=function(e,t){return t||C(e,2,this.length),this[e]<<8|this[e+1]},u.prototype.readUInt32LE=function(e,t){return t||C(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+16777216*this[e+3]},u.prototype.readUInt32BE=function(e,t){return t||C(e,4,this.length),16777216*this[e]+(this[e+1]<<16|this[e+2]<<8|this[e+3])},u.prototype.readIntLE=function(e,t,r){e|=0,t|=0,r||C(e,t,this.length);for(var o=this[e],n=1,i=0;++i=(n*=128)&&(o-=Math.pow(2,8*t)),o},u.prototype.readIntBE=function(e,t,r){e|=0,t|=0,r||C(e,t,this.length);for(var o=t,n=1,i=this[e+--o];o>0&&(n*=256);)i+=this[e+--o]*n;return i>=(n*=128)&&(i-=Math.pow(2,8*t)),i},u.prototype.readInt8=function(e,t){return t||C(e,1,this.length),128&this[e]?-1*(255-this[e]+1):this[e]},u.prototype.readInt16LE=function(e,t){t||C(e,2,this.length);var r=this[e]|this[e+1]<<8;return 32768&r?4294901760|r:r},u.prototype.readInt16BE=function(e,t){t||C(e,2,this.length);var r=this[e+1]|this[e]<<8;return 32768&r?4294901760|r:r},u.prototype.readInt32LE=function(e,t){return t||C(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},u.prototype.readInt32BE=function(e,t){return t||C(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},u.prototype.readFloatLE=function(e,t){return t||C(e,4,this.length),n.read(this,e,!0,23,4)},u.prototype.readFloatBE=function(e,t){return t||C(e,4,this.length),n.read(this,e,!1,23,4)},u.prototype.readDoubleLE=function(e,t){return t||C(e,8,this.length),n.read(this,e,!0,52,8)},u.prototype.readDoubleBE=function(e,t){return t||C(e,8,this.length),n.read(this,e,!1,52,8)},u.prototype.writeUIntLE=function(e,t,r,o){(e=+e,t|=0,r|=0,o)||x(this,e,t,r,Math.pow(2,8*r)-1,0);var n=1,i=0;for(this[t]=255&e;++i=0&&(i*=256);)this[t+n]=e/i&255;return t+r},u.prototype.writeUInt8=function(e,t,r){return e=+e,t|=0,r||x(this,e,t,1,255,0),u.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),this[t]=255&e,t+1},u.prototype.writeUInt16LE=function(e,t,r){return e=+e,t|=0,r||x(this,e,t,2,65535,0),u.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):I(this,e,t,!0),t+2},u.prototype.writeUInt16BE=function(e,t,r){return e=+e,t|=0,r||x(this,e,t,2,65535,0),u.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):I(this,e,t,!1),t+2},u.prototype.writeUInt32LE=function(e,t,r){return e=+e,t|=0,r||x(this,e,t,4,4294967295,0),u.TYPED_ARRAY_SUPPORT?(this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=255&e):N(this,e,t,!0),t+4},u.prototype.writeUInt32BE=function(e,t,r){return e=+e,t|=0,r||x(this,e,t,4,4294967295,0),u.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):N(this,e,t,!1),t+4},u.prototype.writeIntLE=function(e,t,r,o){if(e=+e,t|=0,!o){var n=Math.pow(2,8*r-1);x(this,e,t,r,n-1,-n)}var i=0,s=1,a=0;for(this[t]=255&e;++i>0)-a&255;return t+r},u.prototype.writeIntBE=function(e,t,r,o){if(e=+e,t|=0,!o){var n=Math.pow(2,8*r-1);x(this,e,t,r,n-1,-n)}var i=r-1,s=1,a=0;for(this[t+i]=255&e;--i>=0&&(s*=256);)e<0&&0===a&&0!==this[t+i+1]&&(a=1),this[t+i]=(e/s>>0)-a&255;return t+r},u.prototype.writeInt8=function(e,t,r){return e=+e,t|=0,r||x(this,e,t,1,127,-128),u.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),e<0&&(e=255+e+1),this[t]=255&e,t+1},u.prototype.writeInt16LE=function(e,t,r){return e=+e,t|=0,r||x(this,e,t,2,32767,-32768),u.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):I(this,e,t,!0),t+2},u.prototype.writeInt16BE=function(e,t,r){return e=+e,t|=0,r||x(this,e,t,2,32767,-32768),u.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):I(this,e,t,!1),t+2},u.prototype.writeInt32LE=function(e,t,r){return e=+e,t|=0,r||x(this,e,t,4,2147483647,-2147483648),u.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24):N(this,e,t,!0),t+4},u.prototype.writeInt32BE=function(e,t,r){return e=+e,t|=0,r||x(this,e,t,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),u.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):N(this,e,t,!1),t+4},u.prototype.writeFloatLE=function(e,t,r){return j(this,e,t,!0,r)},u.prototype.writeFloatBE=function(e,t,r){return j(this,e,t,!1,r)},u.prototype.writeDoubleLE=function(e,t,r){return F(this,e,t,!0,r)},u.prototype.writeDoubleBE=function(e,t,r){return F(this,e,t,!1,r)},u.prototype.copy=function(e,t,r,o){if(r||(r=0),o||0===o||(o=this.length),t>=e.length&&(t=e.length),t||(t=0),o>0&&o=this.length)throw new RangeError("sourceStart out of bounds");if(o<0)throw new RangeError("sourceEnd out of bounds");o>this.length&&(o=this.length),e.length-t=0;--n)e[n+t]=this[n+r];else if(i<1e3||!u.TYPED_ARRAY_SUPPORT)for(n=0;n>>=0,r=void 0===r?this.length:r>>>0,e||(e=0),"number"==typeof e)for(i=t;i55295&&r<57344){if(!n){if(r>56319){(t-=3)>-1&&i.push(239,191,189);continue}if(s+1===o){(t-=3)>-1&&i.push(239,191,189);continue}n=r;continue}if(r<56320){(t-=3)>-1&&i.push(239,191,189),n=r;continue}r=65536+(n-55296<<10|r-56320)}else n&&(t-=3)>-1&&i.push(239,191,189);if(n=null,r<128){if((t-=1)<0)break;i.push(r)}else if(r<2048){if((t-=2)<0)break;i.push(r>>6|192,63&r|128)}else if(r<65536){if((t-=3)<0)break;i.push(r>>12|224,r>>6&63|128,63&r|128)}else{if(!(r<1114112))throw new Error("Invalid code point");if((t-=4)<0)break;i.push(r>>18|240,r>>12&63|128,r>>6&63|128,63&r|128)}}return i}function q(e){return o.toByteArray(function(e){if((e=function(e){return e.trim?e.trim():e.replace(/^\s+|\s+$/g,"")}(e).replace(D,"")).length<2)return"";for(;e.length%4!=0;)e+="=";return e}(e))}function J(e,t,r,o){for(var n=0;n=t.length||n>=e.length);++n)t[n+r]=e[n];return n}}).call(this,r(6))},function(e,t,r){"use strict";t.byteLength=function(e){var t=c(e),r=t[0],o=t[1];return 3*(r+o)/4-o},t.toByteArray=function(e){var t,r,o=c(e),s=o[0],a=o[1],u=new i(function(e,t,r){return 3*(t+r)/4-r}(0,s,a)),h=0,l=a>0?s-4:s;for(r=0;r>16&255,u[h++]=t>>8&255,u[h++]=255&t;2===a&&(t=n[e.charCodeAt(r)]<<2|n[e.charCodeAt(r+1)]>>4,u[h++]=255&t);1===a&&(t=n[e.charCodeAt(r)]<<10|n[e.charCodeAt(r+1)]<<4|n[e.charCodeAt(r+2)]>>2,u[h++]=t>>8&255,u[h++]=255&t);return u},t.fromByteArray=function(e){for(var t,r=e.length,n=r%3,i=[],s=0,a=r-n;sa?a:s+16383));1===n?(t=e[r-1],i.push(o[t>>2]+o[t<<4&63]+"==")):2===n&&(t=(e[r-2]<<8)+e[r-1],i.push(o[t>>10]+o[t>>4&63]+o[t<<2&63]+"="));return i.join("")};for(var o=[],n=[],i="undefined"!=typeof Uint8Array?Uint8Array:Array,s="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",a=0,u=s.length;a0)throw new Error("Invalid string. Length must be a multiple of 4");var r=e.indexOf("=");return-1===r&&(r=t),[r,r===t?0:4-r%4]}function h(e,t,r){for(var n,i,s=[],a=t;a>18&63]+o[i>>12&63]+o[i>>6&63]+o[63&i]);return s.join("")}n["-".charCodeAt(0)]=62,n["_".charCodeAt(0)]=63},function(e,t){ +/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh */ +t.read=function(e,t,r,o,n){var i,s,a=8*n-o-1,u=(1<>1,h=-7,l=r?n-1:0,d=r?-1:1,f=e[t+l];for(l+=d,i=f&(1<<-h)-1,f>>=-h,h+=a;h>0;i=256*i+e[t+l],l+=d,h-=8);for(s=i&(1<<-h)-1,i>>=-h,h+=o;h>0;s=256*s+e[t+l],l+=d,h-=8);if(0===i)i=1-c;else{if(i===u)return s?NaN:1/0*(f?-1:1);s+=Math.pow(2,o),i-=c}return(f?-1:1)*s*Math.pow(2,i-o)},t.write=function(e,t,r,o,n,i){var s,a,u,c=8*i-n-1,h=(1<>1,d=23===n?Math.pow(2,-24)-Math.pow(2,-77):0,f=o?0:i-1,p=o?1:-1,m=t<0||0===t&&1/t<0?1:0;for(t=Math.abs(t),isNaN(t)||t===1/0?(a=isNaN(t)?1:0,s=h):(s=Math.floor(Math.log(t)/Math.LN2),t*(u=Math.pow(2,-s))<1&&(s--,u*=2),(t+=s+l>=1?d/u:d*Math.pow(2,1-l))*u>=2&&(s++,u/=2),s+l>=h?(a=0,s=h):s+l>=1?(a=(t*u-1)*Math.pow(2,n),s+=l):(a=t*Math.pow(2,l-1)*Math.pow(2,n),s=0));n>=8;e[r+f]=255&a,f+=p,a/=256,n-=8);for(s=s<0;e[r+f]=255&s,f+=p,s/=256,c-=8);e[r+f-p]|=128*m}},function(e,t){var r={}.toString;e.exports=Array.isArray||function(e){return"[object Array]"==r.call(e)}},function(e,t,r){var o,n,i;n=[],void 0===(i="function"==typeof(o=function(){var e,t,r,o;Object.keys||(Object.keys=(e=Object.prototype.hasOwnProperty,t=!{toString:null}.propertyIsEnumerable("toString"),o=(r=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"]).length,function(n){if("object"!=typeof n&&"function"!=typeof n||null===n)throw new TypeError("Object.keys called on non-object");var i=[];for(var s in n)e.call(n,s)&&i.push(s);if(t)for(var a=0;a>>0;if(0===r)return-1;var o=0;if(arguments.length>1&&((o=Number(arguments[1]))!=o?o=0:0!==o&&o!==1/0&&o!==-1/0&&(o=(o>0||-1)*Math.floor(Math.abs(o)))),o>=r)return-1;for(var n=o>=0?o:Math.max(r-Math.abs(o),0);n0&&(t+=h.suffices["*"]&&r||",",h.suffices["*"]&&u&&(t+=h.name+"=")),t+=a?encodeURIComponent(l[f]).replace(/!/g,"%21"):s(l[f])}else if("object"==typeof l){u&&!h.suffices["*"]&&(t+=h.name+"=");var p=!0;for(var m in l)p||(t+=h.suffices["*"]&&r||","),p=!1,t+=a?encodeURIComponent(m).replace(/!/g,"%21"):s(m),t+=h.suffices["*"]?"=":",",t+=a?encodeURIComponent(l[m]).replace(/!/g,"%21"):s(l[m])}else u&&(t+=h.name,c&&""===l||(t+="=")),null!=h.truncate&&(l=l.substring(0,h.truncate)),t+=a?encodeURIComponent(l).replace(/!/g,"%21"):s(l)}return t};return b.varNames=h,{prefix:o,substitution:b}}function u(e){if(!(this instanceof u))return new u(e);for(var t=e.split("{"),r=[t.shift()],o=[],n=[],i=[];t.length>0;){var s=t.shift(),c=s.split("}")[0],h=s.substring(c.length+1),l=a(c);n.push(l.substitution),o.push(l.prefix),r.push(h),i=i.concat(l.substitution.varNames)}this.fill=function(e){for(var t=r[0],o=0;o0&&"/"===t.charAt(e.length-1)||"#"===r.charAt(0)||"?"===r.charAt(0))return!0}return!1}(t,e.id)&&void 0===this.schemas[e.id]&&(this.schemas[e.id]=e),e)if("enum"!==o)if("object"==typeof e[o])this.searchSchemas(e[o],t);else if("$ref"===o){var n=m(e[o]);n&&void 0===this.schemas[n]&&void 0===this.missingMap[n]&&(this.missingMap[n]=n)}},c.prototype.addSchema=function(e,t){if("string"!=typeof e||void 0===t){if("object"!=typeof e||"string"!=typeof e.id)return;e=(t=e).id}e===m(e)+"#"&&(e=m(e)),this.schemas[e]=t,delete this.missingMap[e],g(t,e),this.searchSchemas(t,e)},c.prototype.getSchemaMap=function(){var e={};for(var t in this.schemas)e[t]=this.schemas[t];return e},c.prototype.getSchemaUris=function(e){var t=[];for(var r in this.schemas)e&&!e.test(r)||t.push(r);return t},c.prototype.getMissingUris=function(e){var t=[];for(var r in this.missingMap)e&&!e.test(r)||t.push(r);return t},c.prototype.dropSchemas=function(){this.schemas={},this.reset()},c.prototype.reset=function(){this.missing=[],this.missingMap={},this.errors=[]},c.prototype.validateAll=function(e,t,r,o,n){var i;if(!(t=this.resolveRefs(t)))return null;if(t instanceof P)return this.errors.push(t),t;var s,a=this.errors.length,u=null,c=null;if(this.checkRecursive&&e&&"object"==typeof e){if(i=!this.scanned.length,e[this.validatedSchemasKey]){var h=e[this.validatedSchemasKey].indexOf(t);if(-1!==h)return this.errors=this.errors.concat(e[this.validationErrorsKey][h]),null}if(Object.isFrozen(e)&&-1!==(s=this.scannedFrozen.indexOf(e))){var l=this.scannedFrozenSchemas[s].indexOf(t);if(-1!==l)return this.errors=this.errors.concat(this.scannedFrozenValidationErrors[s][l]),null}if(this.scanned.push(e),Object.isFrozen(e))-1===s&&(s=this.scannedFrozen.length,this.scannedFrozen.push(e),this.scannedFrozenSchemas.push([])),u=this.scannedFrozenSchemas[s].length,this.scannedFrozenSchemas[s][u]=t,this.scannedFrozenValidationErrors[s][u]=[];else{if(!e[this.validatedSchemasKey])try{Object.defineProperty(e,this.validatedSchemasKey,{value:[],configurable:!0}),Object.defineProperty(e,this.validationErrorsKey,{value:[],configurable:!0})}catch(t){e[this.validatedSchemasKey]=[],e[this.validationErrorsKey]=[]}c=e[this.validatedSchemasKey].length,e[this.validatedSchemasKey][c]=t,e[this.validationErrorsKey][c]=[]}}var d=this.errors.length,f=this.validateBasic(e,t,n)||this.validateNumeric(e,t,n)||this.validateString(e,t,n)||this.validateArray(e,t,n)||this.validateObject(e,t,n)||this.validateCombinations(e,t,n)||this.validateHypermedia(e,t,n)||this.validateFormat(e,t,n)||this.validateDefinedKeywords(e,t,n)||null;if(i){for(;this.scanned.length;)delete this.scanned.pop()[this.validatedSchemasKey];this.scannedFrozen=[],this.scannedFrozenSchemas=[]}if(f||d!==this.errors.length)for(;r&&r.length||o&&o.length;){var p=r&&r.length?""+r.pop():null,m=o&&o.length?""+o.pop():null;f&&(f=f.prefixWith(p,m)),this.prefixErrors(d,p,m)}return null!==u?this.scannedFrozenValidationErrors[s][u]=this.errors.slice(a):null!==c&&(e[this.validationErrorsKey][c]=this.errors.slice(a)),this.handleError(f)},c.prototype.validateFormat=function(e,t){if("string"!=typeof t.format||!this.formatValidators[t.format])return null;var r=this.formatValidators[t.format].call(null,e,t);return"string"==typeof r||"number"==typeof r?this.createError(v.FORMAT_CUSTOM,{message:r},"","/format",null,e,t):r&&"object"==typeof r?this.createError(v.FORMAT_CUSTOM,{message:r.message||"?"},r.dataPath||"",r.schemaPath||"/format",null,e,t):null},c.prototype.validateDefinedKeywords=function(e,t,r){for(var o in this.definedKeywords)if(void 0!==t[o])for(var n=this.definedKeywords[o],i=0;i=l&&ot.maximum)return this.createError(v.NUMBER_MAXIMUM,{value:e,maximum:t.maximum},"","/maximum",null,e,t);if(t.exclusiveMaximum&&e===t.maximum)return this.createError(v.NUMBER_MAXIMUM_EXCLUSIVE,{value:e,maximum:t.maximum},"","/exclusiveMaximum",null,e,t)}return null},c.prototype.validateNaN=function(e,t){return"number"!=typeof e?null:!0===isNaN(e)||e===1/0||e===-1/0?this.createError(v.NUMBER_NOT_A_NUMBER,{value:e},"","/type",null,e,t):null},c.prototype.validateString=function(e,t,r){return this.validateStringLength(e,t,r)||this.validateStringPattern(e,t,r)||null},c.prototype.validateStringLength=function(e,t){return"string"!=typeof e?null:void 0!==t.minLength&&e.lengtht.maxLength?this.createError(v.STRING_LENGTH_LONG,{length:e.length,maximum:t.maxLength},"","/maxLength",null,e,t):null},c.prototype.validateStringPattern=function(e,t){if("string"!=typeof e||"string"!=typeof t.pattern&&!(t.pattern instanceof RegExp))return null;var r;if(t.pattern instanceof RegExp)r=t.pattern;else{var o,n="",i=t.pattern.match(/^\/(.+)\/([img]*)$/);i?(o=i[1],n=i[2]):o=t.pattern,r=new RegExp(o,n)}return r.test(e)?null:this.createError(v.STRING_PATTERN,{pattern:t.pattern},"","/pattern",null,e,t)},c.prototype.validateArray=function(e,t,r){return Array.isArray(e)&&(this.validateArrayLength(e,t,r)||this.validateArrayUniqueItems(e,t,r)||this.validateArrayItems(e,t,r))||null},c.prototype.validateArrayLength=function(e,t){var r;return void 0!==t.minItems&&e.lengtht.maxItems&&(r=this.createError(v.ARRAY_LENGTH_LONG,{length:e.length,maximum:t.maxItems},"","/maxItems",null,e,t),this.handleError(r))?r:null},c.prototype.validateArrayUniqueItems=function(e,t){if(t.uniqueItems)for(var r=0;rt.maxProperties&&(r=this.createError(v.OBJECT_PROPERTIES_MAXIMUM,{propertyCount:o.length,maximum:t.maxProperties},"","/maxProperties",null,e,t),this.handleError(r))?r:null},c.prototype.validateObjectRequiredProperties=function(e,t){if(void 0!==t.required)for(var r=0;r 10000");if(void 0!==v[e])throw new Error("Error already defined: "+e+" as "+v[e]);if(void 0!==_[t])throw new Error("Error code already used: "+_[t]+" as "+t);for(var o in v[e]=t,_[t]=e,w[e]=w[t]=r,E){var n=E[o];n[e]&&(n[t]=n[t]||n[e])}},reset:function(){n.reset(),this.error=null,this.missing=[],this.valid=!0},missing:[],error:null,valid:!0,normSchema:g,resolveUrl:p,getDocumentUri:m,errorCodes:v};return i.language(t||"en"),i}();return T.addLanguage("en-gb",w),T.tv4=T,T})?o.apply(t,n):o)||(e.exports=i)},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.BaseClientTypes=void 0;class o{constructor(){this.uris={},this.schemas={},this.aliases={}}declare(e,t,r,o){const n=e+"/"+t;if(o.extends){const t=o.extends.split("/"),r=1===t.length?e+"/"+t.shift():t.join("/"),i=this.uris[r];if(!i)throw"Type '"+n+"' tries to extend unknown schema '"+r+"'";o.extends=this.schemas[i]}this.uris[n]=r,this.aliases[r]=n,this.schemas[r]=o}resolveAlias(e){return this.uris[e]}getSchema(e){return this.schemas[e]}inScope(e){const t=e.length,r={};for(const o in this.uris)if(o.substr(0,t+1)===e+"/"){const e=this.uris[o];r[e]=this.schemas[e]}return r}}t.BaseClientTypes=o;const n=new o;t.default=n},function(e,t,r){"use strict";class o extends Error{constructor(e){super();const t=new Error("Schema not found: "+e);return t.name="SchemaNotFound",t}}e.exports=o},function(e,t,r){"use strict";e.exports=class{constructor(e){this._itemsRev={},this._storage={},this._canPropagate=!1,this.defaultValue=e,this.activatePropagation()}get(e){e=e.toLowerCase();let t=this._storage[e];return void 0===t&&(t=this.defaultValue,this._storage[e]=t),t}set(e,t){return e=e.toLowerCase(),this._storage[e]===t||(this._storage[e]=t,t||delete this._itemsRev[e],this._updateParentFolderItemRev(e,t),this._canPropagate&&this._propagate(e)),t}delete(e){return this.set(e,null)}deactivatePropagation(){return this._canPropagate=!1,!0}activatePropagation(){return this._canPropagate||(this._generateFolderRev("/"),this._canPropagate=!0),!0}_hashCode(e){let t=0;if(0===e.length)return t;for(let r=0;r0&&(r=this._generateHash(e))}return this.set(e,r),r}}},function(e,t,r){var o; /*! * webfinger.js * http://github.com/silverbucket/webfinger.js @@ -22,5 +24,5 @@ var n=r(20),o=r(21),i=r(22);function s(){return u.TYPED_ARRAY_SUPPORT?2147483647 * You are free to use, modify and distribute this software, but all copyright * information must remain. * - */"function"!=typeof fetch&&"function"!=typeof XMLHttpRequest&&(XMLHttpRequest=r(28)),function(r){var o={"http://webfist.org/spec/rel":"webfist","http://webfinger.net/rel/avatar":"avatar",remotestorage:"remotestorage","http://tools.ietf.org/id/draft-dejong-remotestorage":"remotestorage",remoteStorage:"remotestorage","http://www.packetizer.com/rel/share":"share","http://webfinger.net/rel/profile-page":"profile",me:"profile",vcard:"vcard",blog:"blog","http://packetizer.com/rel/blog":"blog","http://schemas.google.com/g/2010#updates-from":"updates","https://camlistore.org/rel/server":"camilstore"},i={avatar:[],remotestorage:[],blog:[],vcard:[],updates:[],share:[],profile:[],webfist:[],camlistore:[]},s=["webfinger","host-meta","host-meta.json"];function a(e){return e.toString=function(){return this.message},e}function u(e){"object"!=typeof e&&(e={}),this.config={tls_only:void 0===e.tls_only||e.tls_only,webfist_fallback:void 0!==e.webfist_fallback&&e.webfist_fallback,uri_fallback:void 0!==e.uri_fallback&&e.uri_fallback,request_timeout:void 0!==e.request_timeout?e.request_timeout:1e4}}u.prototype.__fetchJRD=function(e,t,r){if("function"==typeof fetch)return this.__fetchJRD_fetch(e,t,r);if("function"==typeof XMLHttpRequest)return this.__fetchJRD_XHR(e,t,r);throw new Error("add a polyfill for fetch or XMLHttpRequest")},u.prototype.__fetchJRD_fetch=function(e,t,r){var n,o=this;"function"==typeof AbortController&&(n=new AbortController);var i=fetch(e,{headers:{Accept:"application/jrd+json, application/json"},signal:n?n.signal:void 0}).then((function(t){if(t.ok)return t.text();throw 404===t.status?a({message:"resource not found",url:e,status:t.status}):a({message:"error during request",url:e,status:t.status})}),(function(t){throw a({message:"error during request",url:e,status:void 0,err:t})})).then((function(t){if(o.__isValidJSON(t))return t;throw a({message:"invalid json",url:e,status:void 0})})),s=new Promise((function(t,r){setTimeout((function(){r(a({message:"request timed out",url:e,status:void 0})),n&&n.abort()}),o.config.request_timeout)}));Promise.race([i,s]).then((function(e){r(e)})).catch((function(e){t(e)}))},u.prototype.__fetchJRD_XHR=function(e,t,r){var n=this,o=!1,i=new XMLHttpRequest;function s(){if(!o){if(o=!0,200===i.status)return n.__isValidJSON(i.responseText)?r(i.responseText):t(a({message:"invalid json",url:e,status:i.status}));if(404===i.status)return t(a({message:"resource not found",url:e,status:i.status}));if(i.status>=301&&i.status<=302){var s=i.getResponseHeader("Location");return function(e){return"string"==typeof e&&"https"===e.split("://")[0]}(s)?u():t(a({message:"no redirect URL found",url:e,status:i.status}))}return t(a({message:"error during request",url:e,status:i.status}))}}function u(){i.onreadystatechange=function(){4===i.readyState&&s()},i.onload=function(){s()},i.ontimeout=function(){return t(a({message:"request timed out",url:e,status:i.status}))},i.open("GET",e,!0),i.timeout=n.config.request_timeout,i.setRequestHeader("Accept","application/jrd+json, application/json"),i.send()}return u()},u.prototype.__isValidJSON=function(e){try{JSON.parse(e)}catch(e){return!1}return!0},u.prototype.__isLocalhost=function(e){return/^localhost(\.localdomain)?(\:[0-9]+)?$/.test(e)},u.prototype.__processJRD=function(e,t,r,n){var s=JSON.parse(t);if("object"!=typeof s||"object"!=typeof s.links)return void 0!==s.error?r(a({message:s.error,request:e})):r(a({message:"unknown response from server",request:e}));var u=s.links;Array.isArray(u)||(u=[]);var c={object:s,json:t,idx:{}};c.idx.properties={name:void 0},c.idx.links=JSON.parse(JSON.stringify(i)),u.map((function(e,t){if(o.hasOwnProperty(e.rel)&&c.idx.links[o[e.rel]]){var r={};Object.keys(e).map((function(t,n){r[t]=e[t]})),c.idx.links[o[e.rel]].push(r)}}));var h=JSON.parse(t).properties;for(var l in h)h.hasOwnProperty(l)&&"http://packetizer.com/ns/name"===l&&(c.idx.properties.name=h[l]);return n(c)},u.prototype.lookup=function(e,t){if("string"!=typeof e)throw new Error("first parameter must be a user address");if("function"!=typeof t)throw new Error("second parameter must be a callback");var r=this,n="";n=e.indexOf("://")>-1?e.replace(/ /g,"").split("/")[2]:e.replace(/ /g,"").split("@")[1];var o=0,i="https";function a(){var t="";return e.split("://")[1]||(t="acct:"),i+"://"+n+"/.well-known/"+s[o]+"?resource="+t+e}function u(e){if(r.config.uri_fallback&&"webfist.org"!==n&&o!==s.length-1)return o+=1,c();if(!r.config.tls_only&&"https"===i)return o=0,i="http",c();if(!r.config.webfist_fallback||"webfist.org"===n)return t(e);o=0,i="http",n="webfist.org";var u=a();r.__fetchJRD(u,t,(function(e){r.__processJRD(u,e,t,(function(e){"object"==typeof e.idx.links.webfist&&"string"==typeof e.idx.links.webfist[0].href&&r.__fetchJRD(e.idx.links.webfist[0].href,t,(function(e){r.__processJRD(u,e,t,(function(e){return t(null,t)}))}))}))}))}function c(){var e=a();r.__fetchJRD(e,u,(function(n){r.__processJRD(e,n,t,(function(e){t(null,e)}))}))}return(r.__isLocalhost(n)&&(i="http"),setTimeout(c,0))},u.prototype.lookupLink=function(e,t,r){if(!i.hasOwnProperty(t))return r("unsupported rel "+t);this.lookup(e,(function(e,n){var o=n.idx.links[t];return e?r(e):0===o.length?r('no links found with rel="'+t+'"'):r(null,o[0])}))},void 0===(n=function(){return u}.apply(t,[]))||(e.exports=n)}()},function(e,t){e.exports=XMLHttpRequest},function(e,t,r){"use strict";var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const o=n(r(3)),i=n(r(16)),s=n(r(1)),a=r(0),u=n(r(30)),c=n(r(11)),h=n(r(6)),l=n(r(15)),d=n(r(7)),f=n(r(13)),p=n(r(14)),m=n(r(8)),g=n(r(31)),y=n(r(12)),v=n(r(32)),_=n(r(33)),b=n(r(34)),w={features:[],featuresDone:0,readyFired:!1,loadFeatures(){this.features=[],this.featuresDone=0,this.readyFired=!1,this.featureModules={WireClient:m.default,Dropbox:p.default,GoogleDrive:f.default,Access:c.default,Discover:l.default,Authorize:h.default,BaseClient:d.default,Env:i.default},o.default.cache&&a.extend(this.featureModules,{Caching:y.default,IndexedDB:v.default,LocalStorage:_.default,InMemoryStorage:b.default,Sync:g.default}),o.default.disableFeatures.forEach(e=>{this.featureModules[e]&&delete this.featureModules[e]}),this._allLoaded=!1;for(const e in this.featureModules)this.loadFeature(e)},hasFeature(e){for(let t=this.features.length-1;t>=0;t--)if(this.features[t].name===e)return this.features[t].supported;return!1},loadFeature(e){const t=this.featureModules[e],r=!t._rs_supported||t._rs_supported();s.default(`[RemoteStorage] [FEATURE ${e}] initializing ...`),"object"==typeof r?r.then(()=>{this.featureSupported(e,!0),this.initFeature(e)},()=>{this.featureSupported(e,!1)}):"boolean"==typeof r?(this.featureSupported(e,r),r&&this.initFeature(e)):this.featureSupported(e,!1)},initFeature(e){const t=this.featureModules[e];let r;try{r=t._rs_init(this)}catch(t){return void this.featureFailed(e,t)}"object"==typeof r&&"function"==typeof r.then?r.then(()=>{this.featureInitialized(e)},t=>{this.featureFailed(e,t)}):this.featureInitialized(e)},featureFailed(e,t){s.default(`[RemoteStorage] [FEATURE ${e}] initialization failed (${t})`),this.featureDone()},featureSupported(e,t){s.default(`[RemoteStorage] [FEATURE ${e}]${t?"":"not "} supported`),t||this.featureDone()},featureInitialized(e){s.default(`[RemoteStorage] [FEATURE ${e}] initialized`),this.features.push({name:e,init:this.featureModules[e]._rs_init,supported:!0,cleanup:this.featureModules[e]._rs_cleanup}),this.featureDone()},featureDone(){this.featuresDone++,this.featuresDone===Object.keys(this.featureModules).length&&setTimeout(this.featuresLoaded.bind(this),0)},_setCachingModule(){["IndexedDB","LocalStorage","InMemoryStorage"].some(e=>{if(this.features.some(t=>t.name===e))return this.features.local=this.featureModules[e],!0})},_fireReady(){try{this.readyFired||(this._emit("ready"),this.readyFired=!0)}catch(e){console.error("'ready' failed: ",e,e.stack),this._emit("error",e)}},featuresLoaded(){s.default("[RemoteStorage] All features loaded"),this._setCachingModule(),this.local=o.default.cache&&this.features.local&&new this.features.local,this.local&&this.remote?(this._setGPD(u.default,this),this._bindChange(this.local)):this.remote&&this._setGPD(this.remote,this.remote),this.remote&&(this.remote.on("connected",()=>{this._fireReady(),this._emit("connected")}),this.remote.on("not-connected",()=>{this._fireReady(),this._emit("not-connected")}),this.remote.connected&&(this._fireReady(),this._emit("connected")),this.hasFeature("Authorize")||this.remote.stopWaitingForToken()),this._collectCleanupFunctions();try{this._allLoaded=!0,this._emit("features-loaded")}catch(e){a.logError(e),this._emit("error",e)}this._processPending()},_collectCleanupFunctions(){this._cleanups=[];for(let e=0;e(this._emit("wire-done",{success:!0}),Promise.resolve(e)),e=>(this._emit("wire-done",{success:!1}),Promise.reject(e)))}))}};e.exports=s},function(e,t,r){"use strict";var n=this&&this.__awaiter||function(e,t,r,n){return new(r||(r=Promise))((function(o,i){function s(e){try{u(n.next(e))}catch(e){i(e)}}function a(e){try{u(n.throw(e))}catch(e){i(e)}}function u(e){var t;e.done?o(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(s,a)}u((n=n.apply(e,t||[])).next())}))},o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const i=o(r(3)),s=o(r(16)),a=o(r(2)),u=o(r(1)),c=o(r(6)),h=o(r(9)),l=o(r(4)),d=r(0);let f,p;function m(e,t,r){return{action:e,path:t,promise:r}}function g(e,t){return e.common.revision!==t&&(!e.remote||e.remote.revision!==t)}function y(e){return e.common&&e.common.revision}class v{constructor(e){this.rs=e,this._tasks={},this._running={},this._timeStarted={},this.numThreads=10,this.rs.local.onDiff(e=>{this.addTask(e),this.doTasks()}),this.rs.caching.onActivate(e=>{this.addTask(e),this.doTasks()}),this.addEvents(["done","req-done"])}now(){return(new Date).getTime()}queueGetRequest(e){return new Promise((t,r)=>{this.rs.remote.connected?this.rs.remote.online?(this.addTask(e,function(){this.rs.local.get(e).then(e=>t(e))}.bind(this)),this.doTasks()):r("cannot fulfill maxAge requirement - remote is not online"):r("cannot fulfill maxAge requirement - remote is not connected")})}corruptServerItemsMap(e,t){if("object"!=typeof e||Array.isArray(e))return!0;for(const r in e){const n=e[r];if("object"!=typeof n)return!0;if("string"!=typeof n.ETag)return!0;if(d.isFolder(r)){if(-1!==r.substring(0,r.length-1).indexOf("/"))return!0}else{if(-1!==r.indexOf("/"))return!0;if(t){if("string"!=typeof n["Content-Type"])return!0;if("number"!=typeof n["Content-Length"])return!0}}}return!1}corruptItemsMap(e){if("object"!=typeof e||Array.isArray(e))return!0;for(const t in e)if("boolean"!=typeof e[t])return!0;return!1}corruptRevision(e){return"object"!=typeof e||Array.isArray(e)||e.revision&&"string"!=typeof e.revision||e.body&&"string"!=typeof e.body&&"object"!=typeof e.body||e.contentType&&"string"!=typeof e.contentType||e.contentLength&&"number"!=typeof e.contentLength||e.timestamp&&"number"!=typeof e.timestamp||e.itemsMap&&this.corruptItemsMap(e.itemsMap)}isCorrupt(e){return"object"!=typeof e||Array.isArray(e)||"string"!=typeof e.path||this.corruptRevision(e.common)||e.local&&this.corruptRevision(e.local)||e.remote&&this.corruptRevision(e.remote)||e.push&&this.corruptRevision(e.push)}hasTasks(){return Object.getOwnPropertyNames(this._tasks).length>0}collectDiffTasks(){return n(this,void 0,void 0,(function*(){let e=0;return this.rs.local.forAllNodes(t=>{e>100||(this.isCorrupt(t)?(u.default("[Sync] WARNING: corrupt node in local cache",t),"object"==typeof t&&t.path&&(this.addTask(t.path),e++)):this.needsFetch(t)&&this.rs.access.checkPathPermission(t.path,"r")?(this.addTask(t.path),e++):d.isDocument(t.path)&&this.needsPush(t)&&this.rs.access.checkPathPermission(t.path,"rw")&&(this.addTask(t.path),e++))}).then(()=>e).catch(e=>{throw e})}))}inConflict(e){return e.local&&e.remote&&(void 0!==e.remote.body||e.remote.itemsMap)}needsRefresh(e){return!!e.common&&(!e.common.timestamp||this.now()-e.common.timestamp>i.default.syncInterval)}needsFetch(e){return!!this.inConflict(e)||(!(!e.common||void 0!==e.common.itemsMap||void 0!==e.common.body)||!(!e.remote||void 0!==e.remote.itemsMap||void 0!==e.remote.body))}needsPush(e){return!this.inConflict(e)&&(!(!e.local||e.push)||void 0)}needsRemotePut(e){return e.local&&e.local.body}needsRemoteDelete(e){return e.local&&!1===e.local.body}getParentPath(e){const t=e.match(/^(.*\/)([^\/]+\/?)$/);if(t)return t[1];throw new Error('Not a valid path: "'+e+'"')}deleteChildPathsFromTasks(){for(const e in this._tasks){const t=d.pathsFromRoot(e);for(let r=1;r{let t;if(this.needsRefresh(e)){try{t=this.getParentPath(e.path)}catch(e){}t&&this.rs.access.checkPathPermission(t,"r")?this.addTask(t):this.rs.access.checkPathPermission(e.path,"r")&&this.addTask(e.path)}}).then(()=>this.deleteChildPathsFromTasks()).catch(e=>{throw e})}))}flush(e){for(const t in e)"FLUSH"===this.rs.caching.checkPath(t)&&e[t]&&!e[t].local&&(u.default("[Sync] Flushing",t),e[t]=void 0);return e}doTask(e){return this.rs.local.getNodes([e]).then(t=>{const r=t[e];return void 0===r?m("get",e,this.rs.remote.get(e)):function(e){return e.remote&&e.remote.revision&&!e.remote.itemsMap&&!e.remote.body}(r)?m("get",e,this.rs.remote.get(e)):this.needsRemotePut(r)?(r.push=d.deepClone(r.local),r.push.timestamp=this.now(),this.rs.local.setNodes(this.flush(t)).then(()=>{let t;return t=y(r)?{ifMatch:r.common.revision}:{ifNoneMatch:"*"},m("put",e,this.rs.remote.put(e,r.push.body,r.push.contentType,t))})):this.needsRemoteDelete(r)?(r.push={body:!1,timestamp:this.now()},this.rs.local.setNodes(this.flush(t)).then(()=>y(r)?m("delete",e,this.rs.remote.delete(e,{ifMatch:r.common.revision})):m("get",e,this.rs.remote.get(e)))):y(r)?m("get",e,this.rs.remote.get(e,{ifNoneMatch:r.common.revision})):m("get",e,this.rs.remote.get(e))})}autoMergeFolder(e){if(e.remote.itemsMap&&(e.common=e.remote,delete e.remote,e.common.itemsMap)){for(const t in e.common.itemsMap)e.local.itemsMap[t]||(e.local.itemsMap[t]=!1);d.equal(e.local.itemsMap,e.common.itemsMap)&&delete e.local}return e}autoMergeDocument(e){return!function(e){return(!e.remote||!e.remote.revision||e.remote.revision===e.common.revision)&&(void 0===e.common.body&&!1===e.remote.body||e.remote.body===e.common.body&&e.remote.contentType===e.common.contentType)}(e)?void 0!==e.remote.body&&(u.default("[Sync] Emitting keep/revert"),this.rs.local._emitChange({origin:"conflict",path:e.path,oldValue:e.local.body,newValue:e.remote.body,lastCommonValue:e.common.body,oldContentType:e.local.contentType,newContentType:e.remote.contentType,lastCommonContentType:e.common.contentType}),e.remote.body?e.common=e.remote:e.common={},delete e.remote,delete e.local):delete(e=function(e){return e.remote&&!1===e.remote.body&&e.local&&!1===e.local.body&&delete e.local,e}(e)).remote,e}autoMerge(e){if(e.remote){if(e.local)return d.isFolder(e.path)?this.autoMergeFolder(e):this.autoMergeDocument(e);if(d.isFolder(e.path))void 0!==e.remote.itemsMap&&(e.common=e.remote,delete e.remote);else if(void 0!==e.remote.body){const t={origin:"remote",path:e.path,oldValue:!1===e.common.body?void 0:e.common.body,newValue:!1===e.remote.body?void 0:e.remote.body,oldContentType:e.common.contentType,newContentType:e.remote.contentType};if((t.oldValue||t.newValue)&&this.rs.local._emitChange(t),!e.remote.body)return;e.common=e.remote,delete e.remote}return e}e.common.body&&this.rs.local._emitChange({origin:"remote",path:e.path,oldValue:e.common.body,newValue:void 0,oldContentType:e.common.contentType,newContentType:void 0})}updateCommonTimestamp(e,t){return n(this,void 0,void 0,(function*(){return this.rs.local.getNodes([e]).then(r=>(r[e]&&r[e].common&&r[e].common.revision===t&&(r[e].common.timestamp=this.now()),this.rs.local.setNodes(this.flush(r))))}))}markChildren(e,t,r,o){return n(this,void 0,void 0,(function*(){const n=[],i={},s={};for(const r in t)n.push(e+r),i[e+r]=t[r];for(const t in o)n.push(e+t);return this.rs.local.getNodes(n).then(t=>{let n,a;for(const u in t)if(a=t[u],i[u])a&&a.common?g(a,i[u].ETag)&&(r[u]=d.deepClone(a),r[u].remote={revision:i[u].ETag,timestamp:this.now()},r[u]=this.autoMerge(r[u])):(n=this.rs.caching.checkPath(u),"ALL"===n&&(r[u]={path:u,common:{timestamp:this.now()},remote:{revision:i[u].ETag,timestamp:this.now()}})),r[u]&&i[u]["Content-Type"]&&(r[u].remote.contentType=i[u]["Content-Type"]),r[u]&&i[u]["Content-Length"]&&(r[u].remote.contentLength=i[u]["Content-Length"]);else if(o[u.substring(e.length)]&&a&&a.common){if(a.common.itemsMap)for(const e in a.common.itemsMap)s[u+e]=!0;if(a.local&&a.local.itemsMap)for(const e in a.local.itemsMap)s[u+e]=!0;if(a.remote||d.isFolder(u))r[u]=void 0;else if(r[u]=this.autoMerge(a),void 0===r[u]){const t=this.getParentPath(u),n=r[t],o=u.substring(e.length);n&&n.local&&(delete n.local.itemsMap[o],d.equal(n.local.itemsMap,n.common.itemsMap)&&delete n.local)}}return this.deleteRemoteTrees(Object.keys(s),r).then(e=>this.rs.local.setNodes(this.flush(e)))})}))}deleteRemoteTrees(e,t){return n(this,void 0,void 0,(function*(){return 0===e.length?Promise.resolve(t):this.rs.local.getNodes(e).then(e=>n(this,void 0,void 0,(function*(){const r={};function n(e,t){if(e&&e.itemsMap)for(const n in e.itemsMap)r[t+n]=!0}for(const r in e){const o=e[r];o&&(d.isFolder(r)?(n(o.common,r),n(o.local,r)):o.common&&void 0!==typeof o.common.body&&(t[r]=d.deepClone(o),t[r].remote={body:!1,timestamp:this.now()},t[r]=this.autoMerge(t[r])))}return this.deleteRemoteTrees(Object.keys(r),t).then(e=>this.rs.local.setNodes(this.flush(e)))})))}))}completeFetch(e,t,r,o){return n(this,void 0,void 0,(function*(){let n,i;const s=d.pathsFromRoot(e);return d.isFolder(e)?n=[e]:(i=s[1],n=[e,i]),this.rs.local.getNodes(n).then(n=>{let s,a,u=n[e];const c={};function h(e){if(e&&e.itemsMap)for(s in e.itemsMap)t[s]||(c[s]=!0)}if("object"==typeof u&&u.path===e&&"object"==typeof u.common||(u={path:e,common:{}},n[e]=u),u.remote={revision:o,timestamp:this.now()},d.isFolder(e))for(s in h(u.common),h(u.remote),u.remote.itemsMap={},t)u.remote.itemsMap[s]=!0;else u.remote.body=t,u.remote.contentType=r,a=n[i],a&&a.local&&a.local.itemsMap&&(s=e.substring(i.length),a.local.itemsMap[s]=!0,d.equal(a.local.itemsMap,a.common.itemsMap)&&delete a.local);return n[e]=this.autoMerge(u),{toBeSaved:n,missingChildren:c}})}))}completePush(e,t,r,o){return n(this,void 0,void 0,(function*(){return this.rs.local.getNodes([e]).then(n=>{const i=n[e];if(!i.push)throw this.stopped=!0,new Error("completePush called but no push version!");return r?(u.default("[Sync] We have a conflict"),i.remote&&i.remote.revision===o||(i.remote={revision:o||"conflict",timestamp:this.now()},delete i.push),n[e]=this.autoMerge(i)):(i.common={revision:o,timestamp:this.now()},"put"===t?(i.common.body=i.push.body,i.common.contentType=i.push.contentType,d.equal(i.local.body,i.push.body)&&i.local.contentType===i.push.contentType&&delete i.local,delete i.push):"delete"===t&&(!1===i.local.body?n[e]=void 0:delete i.push)),this.rs.local.setNodes(this.flush(n))})}))}dealWithFailure(e){return n(this,void 0,void 0,(function*(){return this.rs.local.getNodes([e]).then(t=>{if(t[e])return delete t[e].push,this.rs.local.setNodes(this.flush(t))})}))}interpretStatus(e){const t={statusCode:e,successful:void 0,conflict:void 0,unAuth:void 0,notFound:void 0,changed:void 0,networkProblems:void 0};if("string"==typeof e&&("offline"===e||"timeout"===e))return t.successful=!1,t.networkProblems=!0,t;if("number"==typeof e){const r=Math.floor(e/100);return t.successful=2===r||304===e||412===e||404===e,t.conflict=412===e,t.unAuth=401===e&&this.rs.remote.token!==c.default.IMPLIED_FAKE_TOKEN||402===e||403===e,t.notFound=404===e,t.changed=304!==e,t}}handleGetResponse(e,t,r,o,i){return n(this,void 0,void 0,(function*(){return t.notFound&&(r=!!d.isFolder(e)&&{}),t.changed?this.completeFetch(e,r,o,i).then(t=>d.isFolder(e)?this.corruptServerItemsMap(r)?(u.default("[Sync] WARNING: Discarding corrupt folder description from server for "+e),!1):this.markChildren(e,r,t.toBeSaved,t.missingChildren).then(()=>!0):this.rs.local.setNodes(this.flush(t.toBeSaved)).then(()=>!0)):this.updateCommonTimestamp(e,i).then(()=>!0)}))}handleResponse(e,t,r){const n=this.interpretStatus(r.statusCode);if(n.successful){if("get"===t)return this.handleGetResponse(e,n,r.body,r.contentType,r.revision);if("put"===t||"delete"===t)return this.completePush(e,t,n.conflict,r.revision).then((function(){return!0}));throw new Error(`cannot handle response for unknown action ${t}`)}{let t;return t=n.unAuth?new l.default:n.networkProblems?new h.default("Network request failed."):new Error("HTTP response code "+n.statusCode+" received."),this.dealWithFailure(e).then(()=>{throw this.rs._emit("error",t),t})}}finishTask(e){if(void 0!==e.action)return e.promise.then(t=>this.handleResponse(e.path,e.action,t),t=>(u.default("[Sync] wireclient rejects its promise!",e.path,e.action,t),this.handleResponse(e.path,e.action,{statusCode:"offline"}))).then(t=>{if(delete this._timeStarted[e.path],delete this._running[e.path],t&&this._tasks[e.path]){for(let t=0;t{!this.hasTasks()||this.stopped?(u.default("[Sync] Sync is done! Reschedule?",Object.getOwnPropertyNames(this._tasks).length,this.stopped),this.done||(this.done=!0,this.rs._emit("sync-done"))):setTimeout(()=>{this.doTasks()},10)})},t=>{u.default("[Sync] Error",t),delete this._timeStarted[e.path],delete this._running[e.path],this.rs._emit("sync-req-done"),this.done||(this.done=!0,this.rs._emit("sync-done"))});delete this._running[e.path]}doTasks(){let e,t,r=0;e=this.rs.remote.connected?this.rs.remote.online?this.numThreads:1:0;const n=e-Object.getOwnPropertyNames(this._running).length;if(n<=0)return!0;for(t in this._tasks)if(!this._running[t]&&(this._timeStarted[t]=this.now(),this._running[t]=this.doTask(t),this._running[t].then(this.finishTask.bind(this)),r++,r>=n))return!0;return r>=n}collectTasks(e){return n(this,void 0,void 0,(function*(){return this.hasTasks()||this.stopped?Promise.resolve():this.collectDiffTasks().then(t=>t||!1===e?Promise.resolve():this.collectRefreshTasks(),(function(e){throw e}))}))}addTask(e,t){this._tasks[e]||(this._tasks[e]=[]),"function"==typeof t&&this._tasks[e].push(t)}sync(){return this.done=!1,this.doTasks()?Promise.resolve():this.collectTasks().then(()=>{try{this.doTasks()}catch(e){u.default("[Sync] doTasks error",e)}},(function(e){throw u.default("[Sync] Sync error",e),new Error("Local cache unavailable")}))}static _rs_init(e){f=function(){u.default("[Sync] syncCycleCb calling syncCycle");const t=new s.default;t.isBrowser()&&function(e,t){function r(e){const r=t.getCurrentSyncInterval();i.default.isBackground=!e;const n=t.getCurrentSyncInterval();t._emit("sync-interval-change",{oldValue:r,newValue:n})}e.on("background",()=>r(!1)),e.on("foreground",()=>r(!0))}(t,e),e.sync||(e.sync=new v(e),e.syncStopped&&(u.default("[Sync] Instantiating sync stopped"),e.sync.stopped=!0,delete e.syncStopped)),u.default("[Sync] syncCycleCb calling syncCycle"),e.syncCycle()},p=function(){e.removeEventListener("connected",p),e.startSync()},e.on("ready",f),e.on("connected",p)}static _rs_cleanup(e){e.stopSync(),e.removeEventListener("ready",f),e.removeEventListener("connected",p),e.sync=void 0,delete e.sync}}d.applyMixins(v,[a.default]),e.exports=v},function(e,t,r){"use strict";(function(t){var n=this&&this.__awaiter||function(e,t,r,n){return new(r||(r=Promise))((function(o,i){function s(e){try{u(n.next(e))}catch(e){i(e)}}function a(e){try{u(n.throw(e))}catch(e){i(e)}}function u(e){var t;e.done?o(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(s,a)}u((n=n.apply(e,t||[])).next())}))},o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const i=o(r(2)),s=o(r(10)),a=o(r(1)),u=r(0);let c;class h extends s.default{constructor(e){super(),this.addEvents(["change","local-events-done"]),this.db=e||c,this.db?(this.getsRunning=0,this.putsRunning=0,this.changesQueued={},this.changesRunning={},this.commitSlownessWarning=null):a.default("[IndexedDB] Failed to open DB")}getNodes(e){return n(this,void 0,void 0,(function*(){const t=[],r={};for(let n=0,o=e.length;n0?this.getNodesFromDb(t).then((function(e){for(const t in r)e[t]=r[t];return e})):Promise.resolve(r)}))}setNodes(e){return n(this,void 0,void 0,(function*(){for(const t in e)this.changesQueued[t]=e[t]||!1;return this.maybeFlush(),Promise.resolve()}))}maybeFlush(){0===this.putsRunning?this.flushChangesQueued():this.commitSlownessWarning||(this.commitSlownessWarning=t.setInterval((function(){console.warn("WARNING: waited more than 10 seconds for previous commit to finish")}),1e4))}flushChangesQueued(){this.commitSlownessWarning&&(clearInterval(this.commitSlownessWarning),this.commitSlownessWarning=null),Object.keys(this.changesQueued).length>0&&(this.changesRunning=this.changesQueued,this.changesQueued={},this.setNodesInDb(this.changesRunning).then(this.flushChangesQueued.bind(this)))}getNodesFromDb(e){return new Promise((t,r)=>{const n=this.db.transaction(["nodes"],"readonly"),o=n.objectStore("nodes"),i={};this.getsRunning++,e.map(e=>{o.get(e).onsuccess=t=>{i[e]=t.target.result}}),n.oncomplete=()=>{t(i),this.getsRunning--},n.onerror=n.onabort=()=>{r("get transaction error/abort"),this.getsRunning--}})}setNodesInDb(e){return n(this,void 0,void 0,(function*(){return new Promise((t,r)=>{const n=this.db.transaction(["nodes"],"readwrite"),o=n.objectStore("nodes"),i=(new Date).getTime();this.putsRunning++,a.default("[IndexedDB] Starting put",e,this.putsRunning);for(const t in e){const r=e[t];if("object"==typeof r)try{o.put(r)}catch(e){throw a.default("[IndexedDB] Error while putting",r,e),e}else try{o.delete(t)}catch(e){throw a.default("[IndexedDB] Error while removing",o,r,e),e}}n.oncomplete=()=>{this.putsRunning--,a.default("[IndexedDB] Finished put",e,this.putsRunning,(new Date).getTime()-i+"ms"),t()},n.onerror=()=>{this.putsRunning--,r("transaction error")},n.onabort=()=>{r("transaction abort"),this.putsRunning--}})}))}reset(e){const t=this.db.name;this.db.close(),h.clean(this.db.name,()=>{h.open(t,(t,r)=>{t?a.default("[IndexedDB] Error while resetting local storage",t):this.db=r,"function"==typeof e&&e(self)})})}forAllNodes(e){return n(this,void 0,void 0,(function*(){return new Promise(t=>{this.db.transaction(["nodes"],"readonly").objectStore("nodes").openCursor().onsuccess=r=>{const n=r.target.result;n?(e(this.migrate(n.value)),n.continue()):t()}})}))}closeDB(){0===this.putsRunning?this.db.close():setTimeout(this.closeDB.bind(this),100)}static open(e,t){const r=setTimeout((function(){t("timeout trying to open db")}),1e4);try{const n=indexedDB.open(e,2);n.onerror=function(){a.default("[IndexedDB] Opening DB failed",n),clearTimeout(r),t(n.error)},n.onupgradeneeded=function(e){const t=n.result;a.default("[IndexedDB] Upgrade: from ",e.oldVersion," to ",e.newVersion),1!==e.oldVersion&&(a.default("[IndexedDB] Creating object store: nodes"),t.createObjectStore("nodes",{keyPath:"path"})),a.default("[IndexedDB] Creating object store: changes"),t.createObjectStore("changes",{keyPath:"path"})},n.onsuccess=function(){clearTimeout(r);const o=n.result;if(!o.objectStoreNames.contains("nodes")||!o.objectStoreNames.contains("changes"))return a.default("[IndexedDB] Missing object store. Resetting the database."),void h.clean(e,(function(){h.open(e,t)}));t(null,n.result)}}catch(n){a.default("[IndexedDB] Failed to open database: "+n),a.default("[IndexedDB] Resetting database and trying again."),clearTimeout(r),h.clean(e,(function(){h.open(e,t)}))}}static clean(e,t){const r=indexedDB.deleteDatabase(e);r.onsuccess=function(){a.default("[IndexedDB] Done removing DB"),t()},r.onerror=r.onabort=function(t){console.error('Failed to remove database "'+e+'"',t)}}static _rs_init(e){return new Promise((t,r)=>{h.open("remotestorage",(function(n,o){n?r(n):(c=o,o.onerror=()=>{e._emit("error",n)},t())}))})}static _rs_supported(){return new Promise((e,t)=>{const r=u.getGlobalContext();let n=!1;if("undefined"!=typeof navigator&&navigator.userAgent.match(/Android (2|3|4\.[0-3])/)&&(navigator.userAgent.match(/Chrome|Firefox/)||(n=!0)),"indexedDB"in r&&!n)try{const r=indexedDB.open("rs-check");r.onerror=function(){t()},r.onsuccess=function(){r.result.close(),indexedDB.deleteDatabase("rs-check"),e()}}catch(e){t()}else t()})}static _rs_cleanup(e){return new Promise(t=>{e.local&&e.local.closeDB(),h.clean("remotestorage",t)})}diffHandler(){}}u.applyMixins(h,[i.default]),e.exports=h}).call(this,r(5))},function(e,t,r){"use strict";var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const o=n(r(10)),i=n(r(2)),s=n(r(1)),a=r(0),u="remotestorage:cache:nodes:";function c(e){return e.substr(0,u.length)===u||"remotestorage:cache:changes:"===e.substr(0,"remotestorage:cache:changes:".length)}class h extends o.default{constructor(){super(),this.addEvents(["change","local-events-done"])}diffHandler(...e){}getNodes(e){const t={};for(let r=0,n=e.length;r{s.default("[LocalStorage] Removing",e),delete localStorage[e]})}}a.applyMixins(h,[i.default]),e.exports=h},function(e,t,r){"use strict";var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const o=n(r(2)),i=n(r(10));class s extends i.default{constructor(){super(),this._storage={},this.addEvents(["change","local-events-done"])}getNodes(e){const t={};for(let r=0,n=e.length;r=301&&i.status<=302){var s=i.getResponseHeader("Location");return function(e){return"string"==typeof e&&"https"===e.split("://")[0]}(s)?u():t(a({message:"no redirect URL found",url:e,status:i.status}))}return t(a({message:"error during request",url:e,status:i.status}))}}function u(){i.onreadystatechange=function(){4===i.readyState&&s()},i.onload=function(){s()},i.ontimeout=function(){return t(a({message:"request timed out",url:e,status:i.status}))},i.open("GET",e,!0),i.timeout=o.config.request_timeout,i.setRequestHeader("Accept","application/jrd+json, application/json"),i.send()}return u()},u.prototype.__isValidJSON=function(e){try{JSON.parse(e)}catch(e){return!1}return!0},u.prototype.__isLocalhost=function(e){return/^localhost(\.localdomain)?(\:[0-9]+)?$/.test(e)},u.prototype.__processJRD=function(e,t,r,o){var s=JSON.parse(t);if("object"!=typeof s||"object"!=typeof s.links)return void 0!==s.error?r(a({message:s.error,request:e})):r(a({message:"unknown response from server",request:e}));var u=s.links;Array.isArray(u)||(u=[]);var c={object:s,json:t,idx:{}};c.idx.properties={name:void 0},c.idx.links=JSON.parse(JSON.stringify(i)),u.map((function(e,t){if(n.hasOwnProperty(e.rel)&&c.idx.links[n[e.rel]]){var r={};Object.keys(e).map((function(t,o){r[t]=e[t]})),c.idx.links[n[e.rel]].push(r)}}));var h=JSON.parse(t).properties;for(var l in h)h.hasOwnProperty(l)&&"http://packetizer.com/ns/name"===l&&(c.idx.properties.name=h[l]);return o(c)},u.prototype.lookup=function(e,t){if("string"!=typeof e)throw new Error("first parameter must be a user address");if("function"!=typeof t)throw new Error("second parameter must be a callback");var r=this,o="";o=e.indexOf("://")>-1?e.replace(/ /g,"").split("/")[2]:e.replace(/ /g,"").split("@")[1];var n=0,i="https";function a(){var t="";return e.split("://")[1]||(t="acct:"),i+"://"+o+"/.well-known/"+s[n]+"?resource="+t+e}function u(e){if(r.config.uri_fallback&&"webfist.org"!==o&&n!==s.length-1)return n+=1,c();if(!r.config.tls_only&&"https"===i)return n=0,i="http",c();if(!r.config.webfist_fallback||"webfist.org"===o)return t(e);n=0,i="http",o="webfist.org";var u=a();r.__fetchJRD(u,t,(function(e){r.__processJRD(u,e,t,(function(e){"object"==typeof e.idx.links.webfist&&"string"==typeof e.idx.links.webfist[0].href&&r.__fetchJRD(e.idx.links.webfist[0].href,t,(function(e){r.__processJRD(u,e,t,(function(e){return t(null,t)}))}))}))}))}function c(){var e=a();r.__fetchJRD(e,u,(function(o){r.__processJRD(e,o,t,(function(e){t(null,e)}))}))}return r.__isLocalhost(o)&&(i="http"),setTimeout(c,0)},u.prototype.lookupLink=function(e,t,r){if(!i.hasOwnProperty(t))return r("unsupported rel "+t);this.lookup(e,(function(e,o){var n=o.idx.links[t];return e?r(e):0===n.length?r('no links found with rel="'+t+'"'):r(null,n[0])}))},void 0===(o=function(){return u}.apply(t,[]))||(e.exports=o)}()},function(e,t){e.exports=XMLHttpRequest},function(e,t,r){"use strict";var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const n=o(r(3)),i=o(r(17)),s=o(r(1)),a=r(0),u=o(r(31)),c=o(r(12)),h=o(r(4)),l=o(r(16)),d=o(r(8)),f=o(r(14)),p=o(r(15)),m=o(r(32)),g=o(r(33)),y=o(r(13)),v=o(r(34)),_=o(r(35)),b=o(r(36)),w={features:[],featuresDone:0,readyFired:!1,loadFeatures(){this.features=[],this.featuresDone=0,this.readyFired=!1,this.featureModules={WireClient:m.default,Dropbox:p.default,GoogleDrive:f.default,Access:c.default,Discover:l.default,Authorize:h.default,BaseClient:d.default,Env:i.default},n.default.cache&&(0,a.extend)(this.featureModules,{Caching:y.default,IndexedDB:v.default,LocalStorage:_.default,InMemoryStorage:b.default,Sync:g.default}),n.default.disableFeatures.forEach(e=>{this.featureModules[e]&&delete this.featureModules[e]}),this._allLoaded=!1;for(const e in this.featureModules)this.loadFeature(e)},hasFeature(e){for(let t=this.features.length-1;t>=0;t--)if(this.features[t].name===e)return this.features[t].supported;return!1},loadFeature(e){const t=this.featureModules[e],r=!t._rs_supported||t._rs_supported();(0,s.default)(`[RemoteStorage] [FEATURE ${e}] initializing ...`),"object"==typeof r?r.then(()=>{this.featureSupported(e,!0),this.initFeature(e)},()=>{this.featureSupported(e,!1)}):"boolean"==typeof r?(this.featureSupported(e,r),r&&this.initFeature(e)):this.featureSupported(e,!1)},initFeature(e){const t=this.featureModules[e];let r;try{r=t._rs_init(this)}catch(t){return void this.featureFailed(e,t)}"object"==typeof r&&"function"==typeof r.then?r.then(()=>{this.featureInitialized(e)},t=>{this.featureFailed(e,t)}):this.featureInitialized(e)},featureFailed(e,t){(0,s.default)(`[RemoteStorage] [FEATURE ${e}] initialization failed (${t})`),this.featureDone()},featureSupported(e,t){(0,s.default)(`[RemoteStorage] [FEATURE ${e}]${t?"":"not "} supported`),t||this.featureDone()},featureInitialized(e){(0,s.default)(`[RemoteStorage] [FEATURE ${e}] initialized`),this.features.push({name:e,init:this.featureModules[e]._rs_init,supported:!0,cleanup:this.featureModules[e]._rs_cleanup}),this.featureDone()},featureDone(){this.featuresDone++,this.featuresDone===Object.keys(this.featureModules).length&&setTimeout(this.featuresLoaded.bind(this),0)},_setCachingModule(){["IndexedDB","LocalStorage","InMemoryStorage"].some(e=>{if(this.features.some(t=>t.name===e))return this.features.local=this.featureModules[e],!0})},_fireReady(){try{this.readyFired||(this._emit("ready"),this.readyFired=!0)}catch(e){console.error("'ready' failed: ",e,e.stack),this._emit("error",e)}},featuresLoaded(){(0,s.default)("[RemoteStorage] All features loaded"),this._setCachingModule(),this.local=n.default.cache&&this.features.local&&new this.features.local,this.local&&this.remote?(this._setGPD(u.default,this),this._bindChange(this.local)):this.remote&&this._setGPD(this.remote,this.remote),this.remote&&(this.remote.on("connected",()=>{this._fireReady(),this._emit("connected")}),this.remote.on("not-connected",()=>{this._fireReady(),this._emit("not-connected")}),this.remote.connected&&(this._fireReady(),this._emit("connected")),this.hasFeature("Authorize")||this.remote.stopWaitingForToken()),this._collectCleanupFunctions();try{this._allLoaded=!0,this._emit("features-loaded")}catch(e){(0,a.logError)(e),this._emit("error",e)}this._processPending()},_collectCleanupFunctions(){this._cleanups=[];for(let e=0;e(this._emit("wire-done",{success:!0}),Promise.resolve(e)),e=>(this._emit("wire-done",{success:!1}),Promise.reject(e)))}))}};e.exports=s},function(e,t,r){"use strict";var o=this&&this.__awaiter||function(e,t,r,o){return new(r||(r=Promise))((function(n,i){function s(e){try{u(o.next(e))}catch(e){i(e)}}function a(e){try{u(o.throw(e))}catch(e){i(e)}}function u(e){var t;e.done?n(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(s,a)}u((o=o.apply(e,t||[])).next())}))},n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const i=n(r(4)),s=n(r(2)),a=n(r(5)),u=n(r(1)),c=r(0),h=r(7),l=r(9);let d;const f="remotestorage:wireclient",p={"draft-dejong-remotestorage-00":2,"draft-dejong-remotestorage-01":3,"draft-dejong-remotestorage-02":4,"https://www.w3.org/community/rww/wiki/read-write-web-00#simple":1};class m extends l.RemoteBase{constructor(e){if(super(e),this._revisionCache={},d=(0,c.localStorageAvailable)(),this.addEvents(["connected","not-connected"]),d){const e=function(){const e=(0,c.getJSONFromLocalStorage)(f)||{},{userAddress:t,href:r,storageApi:o,token:n,properties:i}=e;return{userAddress:t,href:r,storageApi:o,token:n,properties:i}}();e&&setTimeout(()=>{this.configure(e)},0)}this.connected&&setTimeout(this._emit.bind(this),0,"connected")}get storageType(){if(this.storageApi){const e=this.storageApi.match(/draft-dejong-(remotestorage-\d\d)/);return e?e[1]:"2012.04"}}_request(e,t,r,n,s,l,d){return o(this,void 0,void 0,(function*(){if(this.isForbiddenRequestMethod(e,t))return Promise.reject(`Don't use ${e} on directories!`);let o;return r!==i.default.IMPLIED_FAKE_TOKEN&&(n.Authorization="Bearer "+r),this.rs._emit("wire-busy",{method:e,isFolder:(0,c.isFolder)(t)}),(0,h.requestWithTimeout)(e,t,{body:s,headers:n,responseType:"arraybuffer"}).then(r=>{if(this.online||(this.online=!0,this.rs._emit("network-online")),this.rs._emit("wire-done",{method:e,isFolder:(0,c.isFolder)(t),success:!0}),n=r.status,[401,403,404,412].indexOf(n)>=0)return(0,u.default)("[WireClient] Error response status",r.status),o=l?this.stripQuotes(r.getResponseHeader("ETag")):void 0,401===r.status&&this.rs._emit("error",new a.default),Promise.resolve({statusCode:r.status,revision:o});if(function(e){return[201,204,304].indexOf(e)>=0}(r.status)||200===r.status&&"GET"!==e)return o=this.stripQuotes(r.getResponseHeader("ETag")),(0,u.default)("[WireClient] Successful request",o),Promise.resolve({statusCode:r.status,revision:o});{const e=r.getResponseHeader("Content-Type");o=l?this.stripQuotes(r.getResponseHeader("ETag")):200===r.status?d:void 0;const t=function(e){let t,r="utf-8";return e&&(t=e.match(/charset=(.+)$/),t&&(r=t[1])),r}(e);return(0,c.shouldBeTreatedAsBinary)(r.response,e)?((0,u.default)("[WireClient] Successful request with unknown or binary mime-type",o),Promise.resolve({statusCode:r.status,body:r.response,contentType:e,revision:o})):(0,c.getTextFromArrayBuffer)(r.response,t).then(t=>((0,u.default)("[WireClient] Successful request",o),Promise.resolve({statusCode:r.status,body:t,contentType:e,revision:o})))}var n},r=>(this.online&&(this.online=!1,this.rs._emit("network-offline")),this.rs._emit("wire-done",{method:e,isFolder:(0,c.isFolder)(t),success:!1}),Promise.reject(r)))}))}configure(e){if("object"!=typeof e)throw new Error("WireClient configure settings parameter should be an object");if(void 0!==e.userAddress&&(this.userAddress=e.userAddress),void 0!==e.href&&(this.href=e.href),void 0!==e.storageApi&&(this.storageApi=e.storageApi),void 0!==e.token&&(this.token=e.token),void 0!==e.properties&&(this.properties=e.properties),"string"==typeof this.storageApi){const e=p[this.storageApi]||5;this.supportsRevs=e>=2}this.href&&this.token?(this.connected=!0,this.online=!0,this._emit("connected")):this.connected=!1,d&&(localStorage[f]=JSON.stringify({userAddress:this.userAddress,href:this.href,storageApi:this.storageApi,token:this.token,properties:this.properties}))}get(e,t={}){if(!this.connected)return Promise.reject("not connected (path: "+e+")");const r={};return this.supportsRevs&&t.ifNoneMatch&&(r["If-None-Match"]=this.addQuotes(t.ifNoneMatch)),this._request("GET",this.href+(0,c.cleanPath)(e),this.token,r,void 0,this.supportsRevs,this._revisionCache[e]).then(t=>{if(!(0,c.isFolder)(e))return Promise.resolve(t);let r={};if(void 0!==t.body)try{t.body=JSON.parse(t.body)}catch(t){return Promise.reject("Folder description at "+this.href+(0,c.cleanPath)(e)+" is not JSON")}if(200===t.statusCode&&"object"==typeof t.body){if(0===Object.keys(t.body).length)t.statusCode=404;else if("http://remotestorage.io/spec/folder-description"===(o=t.body)["@context"]&&"object"==typeof o.items){for(const r in t.body.items)this._revisionCache[e+r]=t.body.items[r].ETag;r=t.body.items}else Object.keys(t.body).forEach(o=>{this._revisionCache[e+o]=t.body[o],r[o]={ETag:t.body[o]}});return t.body=r,Promise.resolve(t)}return Promise.resolve(t);var o})}put(e,t,r,o={}){if(!this.connected)return Promise.reject("not connected (path: "+e+")");!r.match(/charset=/)&&(t instanceof ArrayBuffer||(0,h.isArrayBufferView)(t))&&(r+="; charset=binary");const n={"Content-Type":r};return this.supportsRevs&&(o.ifMatch&&(n["If-Match"]=this.addQuotes(o.ifMatch)),o.ifNoneMatch&&(n["If-None-Match"]=this.addQuotes(o.ifNoneMatch))),this._request("PUT",this.href+(0,c.cleanPath)(e),this.token,n,t,this.supportsRevs)}delete(e,t={}){if(!this.connected)throw new Error("not connected (path: "+e+")");t||(t={});const r={};return this.supportsRevs&&t.ifMatch&&(r["If-Match"]=this.addQuotes(t.ifMatch)),this._request("DELETE",this.href+(0,c.cleanPath)(e),this.token,r,void 0,this.supportsRevs)}static _rs_init(e){e.remote=new m(e),e.remote.online=!0}static _rs_supported(){return"function"==typeof fetch||"function"==typeof XMLHttpRequest}static _rs_cleanup(){d&&delete localStorage[f]}}(0,c.applyMixins)(m,[s.default]),e.exports=m},function(e,t,r){"use strict";var o=this&&this.__awaiter||function(e,t,r,o){return new(r||(r=Promise))((function(n,i){function s(e){try{u(o.next(e))}catch(e){i(e)}}function a(e){try{u(o.throw(e))}catch(e){i(e)}}function u(e){var t;e.done?n(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(s,a)}u((o=o.apply(e,t||[])).next())}))},n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const i=n(r(3)),s=n(r(17)),a=n(r(2)),u=n(r(1)),c=n(r(4)),h=n(r(10)),l=n(r(5)),d=r(0);let f,p;function m(e,t,r){return{action:e,path:t,promise:r}}function g(e,t){return e.common.revision!==t&&(!e.remote||e.remote.revision!==t)}function y(e){return e.common&&e.common.revision}class v{constructor(e){this.rs=e,this._tasks={},this._running={},this._timeStarted={},this.numThreads=10,this.rs.local.onDiff(e=>{this.addTask(e),this.doTasks()}),this.rs.caching.onActivate(e=>{this.addTask(e),this.doTasks()}),this.addEvents(["done","req-done"])}now(){return(new Date).getTime()}queueGetRequest(e){return new Promise((t,r)=>{this.rs.remote.connected?this.rs.remote.online?(this.addTask(e,function(){this.rs.local.get(e).then(e=>t(e))}.bind(this)),this.doTasks()):r("cannot fulfill maxAge requirement - remote is not online"):r("cannot fulfill maxAge requirement - remote is not connected")})}corruptServerItemsMap(e,t){if("object"!=typeof e||Array.isArray(e))return!0;for(const r in e){const o=e[r];if("object"!=typeof o)return!0;if("string"!=typeof o.ETag)return!0;if((0,d.isFolder)(r)){if(-1!==r.substring(0,r.length-1).indexOf("/"))return!0}else{if(-1!==r.indexOf("/"))return!0;if(t){if("string"!=typeof o["Content-Type"])return!0;if("number"!=typeof o["Content-Length"])return!0}}}return!1}corruptItemsMap(e){if("object"!=typeof e||Array.isArray(e))return!0;for(const t in e)if("boolean"!=typeof e[t])return!0;return!1}corruptRevision(e){return"object"!=typeof e||Array.isArray(e)||e.revision&&"string"!=typeof e.revision||e.body&&"string"!=typeof e.body&&"object"!=typeof e.body||e.contentType&&"string"!=typeof e.contentType||e.contentLength&&"number"!=typeof e.contentLength||e.timestamp&&"number"!=typeof e.timestamp||e.itemsMap&&this.corruptItemsMap(e.itemsMap)}isCorrupt(e){return"object"!=typeof e||Array.isArray(e)||"string"!=typeof e.path||this.corruptRevision(e.common)||e.local&&this.corruptRevision(e.local)||e.remote&&this.corruptRevision(e.remote)||e.push&&this.corruptRevision(e.push)}hasTasks(){return Object.getOwnPropertyNames(this._tasks).length>0}collectDiffTasks(){return o(this,void 0,void 0,(function*(){let e=0;return this.rs.local.forAllNodes(t=>{e>100||(this.isCorrupt(t)?((0,u.default)("[Sync] WARNING: corrupt node in local cache",t),"object"==typeof t&&t.path&&(this.addTask(t.path),e++)):(this.needsFetch(t)&&this.rs.access.checkPathPermission(t.path,"r")||(0,d.isDocument)(t.path)&&this.needsPush(t)&&this.rs.access.checkPathPermission(t.path,"rw"))&&(this.addTask(t.path),e++))}).then(()=>e).catch(e=>{throw e})}))}inConflict(e){return e.local&&e.remote&&(void 0!==e.remote.body||e.remote.itemsMap)}needsRefresh(e){return!!e.common&&(!e.common.timestamp||this.now()-e.common.timestamp>i.default.syncInterval)}needsFetch(e){return!!this.inConflict(e)||(!(!e.common||void 0!==e.common.itemsMap||void 0!==e.common.body)||!(!e.remote||void 0!==e.remote.itemsMap||void 0!==e.remote.body))}needsPush(e){return!this.inConflict(e)&&(!(!e.local||e.push)||void 0)}needsRemotePut(e){return e.local&&e.local.body}needsRemoteDelete(e){return e.local&&!1===e.local.body}getParentPath(e){const t=e.match(/^(.*\/)([^\/]+\/?)$/);if(t)return t[1];throw new Error('Not a valid path: "'+e+'"')}deleteChildPathsFromTasks(){for(const e in this._tasks){const t=(0,d.pathsFromRoot)(e);for(let r=1;r{let t;if(this.needsRefresh(e)){try{t=this.getParentPath(e.path)}catch(e){}t&&this.rs.access.checkPathPermission(t,"r")?this.addTask(t):this.rs.access.checkPathPermission(e.path,"r")&&this.addTask(e.path)}}).then(()=>this.deleteChildPathsFromTasks()).catch(e=>{throw e})}))}flush(e){for(const t in e)"FLUSH"===this.rs.caching.checkPath(t)&&e[t]&&!e[t].local&&((0,u.default)("[Sync] Flushing",t),e[t]=void 0);return e}doTask(e){return this.rs.local.getNodes([e]).then(t=>{const r=t[e];return void 0===r||function(e){return e.remote&&e.remote.revision&&!e.remote.itemsMap&&!e.remote.body}(r)?m("get",e,this.rs.remote.get(e)):this.needsRemotePut(r)?(r.push=(0,d.deepClone)(r.local),r.push.timestamp=this.now(),this.rs.local.setNodes(this.flush(t)).then(()=>{let t;return t=y(r)?{ifMatch:r.common.revision}:{ifNoneMatch:"*"},m("put",e,this.rs.remote.put(e,r.push.body,r.push.contentType,t))})):this.needsRemoteDelete(r)?(r.push={body:!1,timestamp:this.now()},this.rs.local.setNodes(this.flush(t)).then(()=>y(r)?m("delete",e,this.rs.remote.delete(e,{ifMatch:r.common.revision})):m("get",e,this.rs.remote.get(e)))):y(r)?m("get",e,this.rs.remote.get(e,{ifNoneMatch:r.common.revision})):m("get",e,this.rs.remote.get(e))})}autoMergeFolder(e){if(e.remote.itemsMap&&(e.common=e.remote,delete e.remote,e.common.itemsMap)){for(const t in e.common.itemsMap)e.local.itemsMap[t]||(e.local.itemsMap[t]=!1);(0,d.equal)(e.local.itemsMap,e.common.itemsMap)&&delete e.local}return e}autoMergeDocument(e){return!function(e){return(!e.remote||!e.remote.revision||e.remote.revision===e.common.revision)&&(void 0===e.common.body&&!1===e.remote.body||e.remote.body===e.common.body&&e.remote.contentType===e.common.contentType)}(e)?void 0!==e.remote.body&&((0,u.default)("[Sync] Emitting keep/revert"),this.rs.local._emitChange({origin:"conflict",path:e.path,oldValue:e.local.body,newValue:e.remote.body,lastCommonValue:e.common.body,oldContentType:e.local.contentType,newContentType:e.remote.contentType,lastCommonContentType:e.common.contentType}),e.remote.body?e.common=e.remote:e.common={},delete e.remote,delete e.local):delete(e=function(e){return e.remote&&!1===e.remote.body&&e.local&&!1===e.local.body&&delete e.local,e}(e)).remote,e}autoMerge(e){if(e.remote){if(e.local)return(0,d.isFolder)(e.path)?this.autoMergeFolder(e):this.autoMergeDocument(e);if((0,d.isFolder)(e.path))void 0!==e.remote.itemsMap&&(e.common=e.remote,delete e.remote);else if(void 0!==e.remote.body){const t={origin:"remote",path:e.path,oldValue:!1===e.common.body?void 0:e.common.body,newValue:!1===e.remote.body?void 0:e.remote.body,oldContentType:e.common.contentType,newContentType:e.remote.contentType};if((t.oldValue||t.newValue)&&this.rs.local._emitChange(t),!e.remote.body)return;e.common=e.remote,delete e.remote}return e}e.common.body&&this.rs.local._emitChange({origin:"remote",path:e.path,oldValue:e.common.body,newValue:void 0,oldContentType:e.common.contentType,newContentType:void 0})}updateCommonTimestamp(e,t){return o(this,void 0,void 0,(function*(){return this.rs.local.getNodes([e]).then(r=>(r[e]&&r[e].common&&r[e].common.revision===t&&(r[e].common.timestamp=this.now()),this.rs.local.setNodes(this.flush(r))))}))}markChildren(e,t,r,n){return o(this,void 0,void 0,(function*(){const o=[],i={},s={};for(const r in t)o.push(e+r),i[e+r]=t[r];for(const t in n)o.push(e+t);return this.rs.local.getNodes(o).then(t=>{let o,a;for(const u in t)if(a=t[u],i[u])a&&a.common?g(a,i[u].ETag)&&(r[u]=(0,d.deepClone)(a),r[u].remote={revision:i[u].ETag,timestamp:this.now()},r[u]=this.autoMerge(r[u])):(o=this.rs.caching.checkPath(u),"ALL"===o&&(r[u]={path:u,common:{timestamp:this.now()},remote:{revision:i[u].ETag,timestamp:this.now()}})),r[u]&&i[u]["Content-Type"]&&(r[u].remote.contentType=i[u]["Content-Type"]),r[u]&&i[u]["Content-Length"]&&(r[u].remote.contentLength=i[u]["Content-Length"]);else if(n[u.substring(e.length)]&&a&&a.common){if(a.common.itemsMap)for(const e in a.common.itemsMap)s[u+e]=!0;if(a.local&&a.local.itemsMap)for(const e in a.local.itemsMap)s[u+e]=!0;if(a.remote||(0,d.isFolder)(u))r[u]=void 0;else if(r[u]=this.autoMerge(a),void 0===r[u]){const t=this.getParentPath(u),o=r[t],n=u.substring(e.length);o&&o.local&&(delete o.local.itemsMap[n],(0,d.equal)(o.local.itemsMap,o.common.itemsMap)&&delete o.local)}}return this.deleteRemoteTrees(Object.keys(s),r).then(e=>this.rs.local.setNodes(this.flush(e)))})}))}deleteRemoteTrees(e,t){return o(this,void 0,void 0,(function*(){return 0===e.length?Promise.resolve(t):this.rs.local.getNodes(e).then(e=>o(this,void 0,void 0,(function*(){const r={};function o(e,t){if(e&&e.itemsMap)for(const o in e.itemsMap)r[t+o]=!0}for(const r in e){const n=e[r];n&&((0,d.isFolder)(r)?(o(n.common,r),o(n.local,r)):n.common&&void 0!==typeof n.common.body&&(t[r]=(0,d.deepClone)(n),t[r].remote={body:!1,timestamp:this.now()},t[r]=this.autoMerge(t[r])))}return this.deleteRemoteTrees(Object.keys(r),t).then(e=>this.rs.local.setNodes(this.flush(e)))})))}))}completeFetch(e,t,r,n){return o(this,void 0,void 0,(function*(){let o,i;const s=(0,d.pathsFromRoot)(e);return(0,d.isFolder)(e)?o=[e]:(i=s[1],o=[e,i]),this.rs.local.getNodes(o).then(o=>{let s,a,u=o[e];const c={};function h(e){if(e&&e.itemsMap)for(s in e.itemsMap)t[s]||(c[s]=!0)}if("object"==typeof u&&u.path===e&&"object"==typeof u.common||(u={path:e,common:{}},o[e]=u),u.remote={revision:n,timestamp:this.now()},(0,d.isFolder)(e))for(s in h(u.common),h(u.remote),u.remote.itemsMap={},t)u.remote.itemsMap[s]=!0;else u.remote.body=t,u.remote.contentType=r,a=o[i],a&&a.local&&a.local.itemsMap&&(s=e.substring(i.length),a.local.itemsMap[s]=!0,(0,d.equal)(a.local.itemsMap,a.common.itemsMap)&&delete a.local);return o[e]=this.autoMerge(u),{toBeSaved:o,missingChildren:c}})}))}completePush(e,t,r,n){return o(this,void 0,void 0,(function*(){return this.rs.local.getNodes([e]).then(o=>{const i=o[e];if(!i.push)throw this.stopped=!0,new Error("completePush called but no push version!");return r?((0,u.default)("[Sync] We have a conflict"),i.remote&&i.remote.revision===n||(i.remote={revision:n||"conflict",timestamp:this.now()},delete i.push),o[e]=this.autoMerge(i)):(i.common={revision:n,timestamp:this.now()},"put"===t?(i.common.body=i.push.body,i.common.contentType=i.push.contentType,(0,d.equal)(i.local.body,i.push.body)&&i.local.contentType===i.push.contentType&&delete i.local,delete i.push):"delete"===t&&(!1===i.local.body?o[e]=void 0:delete i.push)),this.rs.local.setNodes(this.flush(o))})}))}dealWithFailure(e){return o(this,void 0,void 0,(function*(){return this.rs.local.getNodes([e]).then(t=>{if(t[e])return delete t[e].push,this.rs.local.setNodes(this.flush(t))})}))}interpretStatus(e){const t={statusCode:e,successful:void 0,conflict:void 0,unAuth:void 0,notFound:void 0,changed:void 0,networkProblems:void 0};if("string"==typeof e&&("offline"===e||"timeout"===e))return t.successful=!1,t.networkProblems=!0,t;if("number"==typeof e){const r=Math.floor(e/100);return t.successful=2===r||304===e||412===e||404===e,t.conflict=412===e,t.unAuth=401===e&&this.rs.remote.token!==c.default.IMPLIED_FAKE_TOKEN||402===e||403===e,t.notFound=404===e,t.changed=304!==e,t}}handleGetResponse(e,t,r,n,i){return o(this,void 0,void 0,(function*(){return t.notFound&&(r=!!(0,d.isFolder)(e)&&{}),t.changed?this.completeFetch(e,r,n,i).then(t=>(0,d.isFolder)(e)?this.corruptServerItemsMap(r)?((0,u.default)("[Sync] WARNING: Discarding corrupt folder description from server for "+e),!1):this.markChildren(e,r,t.toBeSaved,t.missingChildren).then(()=>!0):this.rs.local.setNodes(this.flush(t.toBeSaved)).then(()=>!0)):this.updateCommonTimestamp(e,i).then(()=>!0)}))}handleResponse(e,t,r){const o=this.interpretStatus(r.statusCode);if(o.successful){if("get"===t)return this.handleGetResponse(e,o,r.body,r.contentType,r.revision);if("put"===t||"delete"===t)return this.completePush(e,t,o.conflict,r.revision).then((function(){return!0}));throw new Error("cannot handle response for unknown action "+t)}{let t;return t=o.unAuth?new l.default:o.networkProblems?new h.default("Network request failed."):new Error("HTTP response code "+o.statusCode+" received."),this.dealWithFailure(e).then(()=>{throw this.rs._emit("error",t),t})}}finishTask(e){if(void 0!==e.action)return e.promise.then(t=>this.handleResponse(e.path,e.action,t),t=>((0,u.default)("[Sync] wireclient rejects its promise!",e.path,e.action,t),this.handleResponse(e.path,e.action,{statusCode:"offline"}))).then(t=>{if(delete this._timeStarted[e.path],delete this._running[e.path],t&&this._tasks[e.path]){for(let t=0;t{!this.hasTasks()||this.stopped?((0,u.default)("[Sync] Sync is done! Reschedule?",Object.getOwnPropertyNames(this._tasks).length,this.stopped),this.done||(this.done=!0,this.rs._emit("sync-done"))):setTimeout(()=>{this.doTasks()},10)})},t=>{(0,u.default)("[Sync] Error",t),delete this._timeStarted[e.path],delete this._running[e.path],this.rs._emit("sync-req-done"),this.done||(this.done=!0,this.rs._emit("sync-done"))});delete this._running[e.path]}doTasks(){let e,t,r=0;e=this.rs.remote.connected?this.rs.remote.online?this.numThreads:1:0;const o=e-Object.getOwnPropertyNames(this._running).length;if(o<=0)return!0;for(t in this._tasks)if(!this._running[t]&&(this._timeStarted[t]=this.now(),this._running[t]=this.doTask(t),this._running[t].then(this.finishTask.bind(this)),r++,r>=o))return!0;return r>=o}collectTasks(e){return o(this,void 0,void 0,(function*(){return this.hasTasks()||this.stopped?Promise.resolve():this.collectDiffTasks().then(t=>t||!1===e?Promise.resolve():this.collectRefreshTasks(),(function(e){throw e}))}))}addTask(e,t){this._tasks[e]||(this._tasks[e]=[]),"function"==typeof t&&this._tasks[e].push(t)}sync(){return this.done=!1,this.doTasks()?Promise.resolve():this.collectTasks().then(()=>{try{this.doTasks()}catch(e){(0,u.default)("[Sync] doTasks error",e)}},(function(e){throw(0,u.default)("[Sync] Sync error",e),new Error("Local cache unavailable")}))}static _rs_init(e){f=function(){(0,u.default)("[Sync] syncCycleCb calling syncCycle");const t=new s.default;t.isBrowser()&&function(e,t){function r(e){const r=t.getCurrentSyncInterval();i.default.isBackground=!e;const o=t.getCurrentSyncInterval();t._emit("sync-interval-change",{oldValue:r,newValue:o})}e.on("background",()=>r(!1)),e.on("foreground",()=>r(!0))}(t,e),e.sync||(e.sync=new v(e),e.syncStopped&&((0,u.default)("[Sync] Instantiating sync stopped"),e.sync.stopped=!0,delete e.syncStopped)),(0,u.default)("[Sync] syncCycleCb calling syncCycle"),e.syncCycle()},p=function(){e.removeEventListener("connected",p),e.startSync()},e.on("ready",f),e.on("connected",p)}static _rs_cleanup(e){e.stopSync(),e.removeEventListener("ready",f),e.removeEventListener("connected",p),e.sync=void 0,delete e.sync}}(0,d.applyMixins)(v,[a.default]),e.exports=v},function(e,t,r){"use strict";(function(t){var o=this&&this.__awaiter||function(e,t,r,o){return new(r||(r=Promise))((function(n,i){function s(e){try{u(o.next(e))}catch(e){i(e)}}function a(e){try{u(o.throw(e))}catch(e){i(e)}}function u(e){var t;e.done?n(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(s,a)}u((o=o.apply(e,t||[])).next())}))},n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const i=n(r(2)),s=n(r(11)),a=n(r(1)),u=r(0);let c;class h extends s.default{constructor(e){super(),this.addEvents(["change","local-events-done"]),this.db=e||c,this.db?(this.getsRunning=0,this.putsRunning=0,this.changesQueued={},this.changesRunning={},this.commitSlownessWarning=null):(0,a.default)("[IndexedDB] Failed to open DB")}getNodes(e){return o(this,void 0,void 0,(function*(){const t=[],r={};for(let o=0,n=e.length;o0?this.getNodesFromDb(t).then((function(e){for(const t in r)e[t]=r[t];return e})):Promise.resolve(r)}))}setNodes(e){return o(this,void 0,void 0,(function*(){for(const t in e)this.changesQueued[t]=e[t]||!1;return this.maybeFlush(),Promise.resolve()}))}maybeFlush(){0===this.putsRunning?this.flushChangesQueued():this.commitSlownessWarning||(this.commitSlownessWarning=t.setInterval((function(){console.warn("WARNING: waited more than 10 seconds for previous commit to finish")}),1e4))}flushChangesQueued(){this.commitSlownessWarning&&(clearInterval(this.commitSlownessWarning),this.commitSlownessWarning=null),Object.keys(this.changesQueued).length>0&&(this.changesRunning=this.changesQueued,this.changesQueued={},this.setNodesInDb(this.changesRunning).then(this.flushChangesQueued.bind(this)))}getNodesFromDb(e){return new Promise((t,r)=>{const o=this.db.transaction(["nodes"],"readonly"),n=o.objectStore("nodes"),i={};this.getsRunning++,e.map(e=>{n.get(e).onsuccess=t=>{i[e]=t.target.result}}),o.oncomplete=()=>{t(i),this.getsRunning--},o.onerror=o.onabort=()=>{r("get transaction error/abort"),this.getsRunning--}})}setNodesInDb(e){return o(this,void 0,void 0,(function*(){return new Promise((t,r)=>{const o=this.db.transaction(["nodes"],"readwrite"),n=o.objectStore("nodes"),i=(new Date).getTime();this.putsRunning++,(0,a.default)("[IndexedDB] Starting put",e,this.putsRunning);for(const t in e){const r=e[t];if("object"==typeof r)try{n.put(r)}catch(e){throw(0,a.default)("[IndexedDB] Error while putting",r,e),e}else try{n.delete(t)}catch(e){throw(0,a.default)("[IndexedDB] Error while removing",n,r,e),e}}o.oncomplete=()=>{this.putsRunning--,(0,a.default)("[IndexedDB] Finished put",e,this.putsRunning,(new Date).getTime()-i+"ms"),t()},o.onerror=()=>{this.putsRunning--,r("transaction error")},o.onabort=()=>{r("transaction abort"),this.putsRunning--}})}))}reset(e){const t=this.db.name;this.db.close(),h.clean(this.db.name,()=>{h.open(t,(t,r)=>{t?(0,a.default)("[IndexedDB] Error while resetting local storage",t):this.db=r,"function"==typeof e&&e(self)})})}forAllNodes(e){return o(this,void 0,void 0,(function*(){return new Promise(t=>{this.db.transaction(["nodes"],"readonly").objectStore("nodes").openCursor().onsuccess=r=>{const o=r.target.result;o?(e(this.migrate(o.value)),o.continue()):t()}})}))}closeDB(){0===this.putsRunning?this.db.close():setTimeout(this.closeDB.bind(this),100)}static open(e,t){const r=setTimeout((function(){t("timeout trying to open db")}),1e4);try{const o=indexedDB.open(e,2);o.onerror=function(){(0,a.default)("[IndexedDB] Opening DB failed",o),clearTimeout(r),t(o.error)},o.onupgradeneeded=function(e){const t=o.result;(0,a.default)("[IndexedDB] Upgrade: from ",e.oldVersion," to ",e.newVersion),1!==e.oldVersion&&((0,a.default)("[IndexedDB] Creating object store: nodes"),t.createObjectStore("nodes",{keyPath:"path"})),(0,a.default)("[IndexedDB] Creating object store: changes"),t.createObjectStore("changes",{keyPath:"path"})},o.onsuccess=function(){clearTimeout(r);const n=o.result;if(!n.objectStoreNames.contains("nodes")||!n.objectStoreNames.contains("changes"))return(0,a.default)("[IndexedDB] Missing object store. Resetting the database."),void h.clean(e,(function(){h.open(e,t)}));t(null,o.result)}}catch(o){(0,a.default)("[IndexedDB] Failed to open database: "+o),(0,a.default)("[IndexedDB] Resetting database and trying again."),clearTimeout(r),h.clean(e,(function(){h.open(e,t)}))}}static clean(e,t){const r=indexedDB.deleteDatabase(e);r.onsuccess=function(){(0,a.default)("[IndexedDB] Done removing DB"),t()},r.onerror=r.onabort=function(t){console.error('Failed to remove database "'+e+'"',t)}}static _rs_init(e){return new Promise((t,r)=>{h.open("remotestorage",(function(o,n){o?r(o):(c=n,n.onerror=()=>{e._emit("error",o)},t())}))})}static _rs_supported(){return new Promise((e,t)=>{const r=(0,u.getGlobalContext)();let o=!1;if("undefined"!=typeof navigator&&navigator.userAgent.match(/Android (2|3|4\.[0-3])/)&&(navigator.userAgent.match(/Chrome|Firefox/)||(o=!0)),"indexedDB"in r&&!o)try{const r=indexedDB.open("rs-check");r.onerror=function(){t()},r.onsuccess=function(){r.result.close(),indexedDB.deleteDatabase("rs-check"),e()}}catch(e){t()}else t()})}static _rs_cleanup(e){return new Promise(t=>{e.local&&e.local.closeDB(),h.clean("remotestorage",t)})}diffHandler(){}}(0,u.applyMixins)(h,[i.default]),e.exports=h}).call(this,r(6))},function(e,t,r){"use strict";var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const n=o(r(11)),i=o(r(2)),s=o(r(1)),a=r(0),u="remotestorage:cache:nodes:";function c(e){return e.substr(0,u.length)===u||"remotestorage:cache:changes:"===e.substr(0,"remotestorage:cache:changes:".length)}class h extends n.default{constructor(){super(),this.addEvents(["change","local-events-done"])}diffHandler(...e){}getNodes(e){const t={};for(let r=0,o=e.length;r{(0,s.default)("[LocalStorage] Removing",e),delete localStorage[e]})}}(0,a.applyMixins)(h,[i.default]),e.exports=h},function(e,t,r){"use strict";var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const n=o(r(2)),i=o(r(11)),s=r(0);class a extends i.default{constructor(){super(),this._storage={},this.addEvents(["change","local-events-done"])}getNodes(e){const t={};for(let r=0,o=e.length;r {\n if (typeof (error) === 'string') {\n console.error(error);\n } else {\n console.error(error.message, error.stack);\n }\n};\n\nexport const globalContext = (typeof (window) !== 'undefined' ? window : (typeof self === 'object' ? self : global));\n\nexport const getGlobalContext = (): any => {\n return (typeof (window) !== 'undefined' ? window : (typeof self === 'object' ? self : global));\n};\n\n// TODO Remove in favor of modern JS:\n// `const mergedObject = { ...obj1, ..obj2 }`\nexport const extend = (...args): unknown => {\n const target = args[0];\n const sources = Array.prototype.slice.call(args, 1);\n sources.forEach(function (source) {\n for (const key in source) {\n target[key] = source[key];\n }\n });\n return target;\n};\n\nexport const containingFolder = (path: string): string => {\n if (path === '') {\n return '/';\n }\n if (!path) {\n throw \"Path not given!\";\n }\n\n return path.replace(/\\/+/g, '/')\n .replace(/[^\\/]+\\/?$/, '');\n};\n\nexport const isFolder = (path: string): boolean => {\n return path.slice(-1) === '/';\n};\n\nexport const isDocument = (path: string): boolean => {\n return !isFolder(path);\n};\n\nexport const baseName = (path: string): string => {\n const parts = path.split('/');\n if (isFolder(path)) {\n return parts[parts.length - 2] + '/';\n } else {\n return parts[parts.length - 1];\n }\n};\n\nexport const cleanPath = (path: string): string => {\n return path.replace(/\\/+/g, '/')\n .split('/').map(encodeURIComponent).join('/')\n .replace(/'/g, '%27');\n};\n\nexport const bindAll = (object: object) => {\n for (const key in this) {\n if (typeof (object[key]) === 'function') {\n object[key] = object[key].bind(object);\n }\n }\n};\n\nexport const equal = (a: any, b: any, seen = []): boolean => {\n let key;\n\n if (typeof (a) !== typeof (b)) {\n return false;\n }\n\n if (typeof (a) === 'number' || typeof (a) === 'boolean' || typeof (a) === 'string') {\n return a === b;\n }\n\n if (typeof (a) === 'function') {\n return a.toString() === b.toString();\n }\n\n if (a instanceof ArrayBuffer && b instanceof ArrayBuffer) {\n // Without the following conversion the browsers wouldn't be able to\n // tell the ArrayBuffer instances apart.\n a = new Uint8Array(a);\n b = new Uint8Array(b);\n }\n\n // If this point has been reached, a and b are either arrays or objects.\n\n if (a instanceof Array) {\n if (a.length !== b.length) {\n return false;\n }\n\n for (let i = 0, c = a.length; i < c; i++) {\n if (!equal(a[i], b[i], seen)) {\n return false;\n }\n }\n } else {\n // Check that keys from a exist in b\n for (key in a) {\n if (a.hasOwnProperty(key) && !(key in b)) {\n return false;\n }\n }\n\n // Check that keys from b exist in a, and compare the values\n for (key in b) {\n if (!b.hasOwnProperty(key)) {\n continue;\n }\n\n if (!(key in a)) {\n return false;\n }\n\n let seenArg;\n\n if (typeof (b[key]) === 'object') {\n if (seen.indexOf(b[key]) >= 0) {\n // Circular reference, don't attempt to compare this object.\n // If nothing else returns false, the objects match.\n continue;\n }\n\n seenArg = seen.slice();\n seenArg.push(b[key]);\n }\n\n if (!equal(a[key], b[key], seenArg)) {\n return false;\n }\n }\n }\n\n return true;\n};\n\nexport const deepClone = (obj: any): any => {\n if (obj === undefined) {\n return undefined;\n } else {\n const clone = JSON.parse(JSON.stringify(obj));\n _fixArrayBuffers(obj, clone);\n return clone;\n }\n};\n\nexport const pathsFromRoot = (path: string): string[] => {\n const paths = [path];\n const parts = path.replace(/\\/$/, '').split('/');\n\n while (parts.length > 1) {\n parts.pop();\n paths.push(parts.join('/') + '/');\n }\n return paths;\n};\n\nexport const localStorageAvailable = (): boolean => {\n const context = getGlobalContext();\n\n if (!('localStorage' in context)) {\n return false;\n }\n\n try {\n context.localStorage.setItem('rs-check', '1');\n context.localStorage.removeItem('rs-check');\n return true;\n } catch (error) {\n return false;\n }\n};\n\n/**\n * Extract and parse JSON data from localStorage.\n *\n * @param {string} key - localStorage key\n *\n * @returns {object} parsed object or undefined\n */\nexport const getJSONFromLocalStorage = (key: string): { [key: string]: any } => {\n const context = getGlobalContext() as Window;\n\n try {\n return JSON.parse(context.localStorage.getItem(key));\n } catch (e) {\n // no JSON stored\n }\n};\n\n/**\n * Decide if data should be treated as binary based on the content (presence of non-printable characters\n * or replacement character) and content-type.\n *\n * @param {string} content - The data\n * @param {string} mimeType - The data's content-type\n *\n * @returns {boolean}\n */\nexport const shouldBeTreatedAsBinary = (content: string | ArrayBuffer, mimeType: string): boolean => {\n // eslint-disable-next-line no-control-regex\n return !!((mimeType && mimeType.match(/charset=binary/)) || /[\\x00-\\x08\\x0E-\\x1F\\uFFFD]/.test(content as string));\n};\n\n/**\n * Read data from an ArrayBuffer and return it as a string\n * @param {ArrayBuffer} arrayBuffer\n * @param {string} encoding\n * @returns {Promise} Resolves with a string containing the data\n */\nexport const getTextFromArrayBuffer = (arrayBuffer: ArrayBuffer, encoding): Promise => {\n return new Promise((resolve/*, reject*/) => {\n if (typeof Blob === 'undefined') {\n const buffer = new Buffer(new Uint8Array(arrayBuffer));\n resolve(buffer.toString(encoding));\n } else {\n let blob;\n const gc = globalContext as any;\n // TODO fix as BlobBuilder is not available in all browsers\n // @see https://developer.mozilla.org/en-US/docs/Web/API/BlobBuilder\n gc.BlobBuilder = gc.BlobBuilder || gc.WebKitBlobBuilder;\n if (typeof gc.BlobBuilder !== 'undefined') {\n const bb = new gc.BlobBuilder();\n bb.append(arrayBuffer);\n blob = bb.getBlob();\n } else {\n blob = new Blob([arrayBuffer]);\n }\n\n const fileReader = new FileReader();\n if (typeof fileReader.addEventListener === 'function') {\n fileReader.addEventListener('loadend', function (evt) {\n resolve(evt.target.result);\n });\n } else {\n fileReader.onloadend = function (evt) {\n resolve(evt.target.result);\n };\n }\n fileReader.readAsText(blob, encoding);\n }\n });\n};\n\n/**\n * Encode string in base64\n * @param {String} str\n * @returns {String} base64-encoded string\n */\nexport const toBase64 = (str: string): string => {\n const context = getGlobalContext();\n if ('btoa' in context) {\n return context['btoa'](str);\n } else {\n return Buffer.from(str).toString('base64');\n }\n};\n\n/*\n * Apply mixins to an object\n *\n * https://www.typescriptlang.org/docs/handbook/mixins.html\n *\n * @param {object} Parent object\n * @param {Array} Mixins to apply methods from\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function applyMixins(derivedCtor: any, baseCtors: any[]): void {\n baseCtors.forEach(baseCtor => {\n Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {\n Object.defineProperty(derivedCtor.prototype, name, Object.getOwnPropertyDescriptor(baseCtor.prototype, name));\n });\n });\n}\n","import config from './config';\n\n/**\n * Log using console.log, when remoteStorage logging is enabled.\n *\n * You can enable logging with ``RemoteStorage#enableLog``.\n *\n * (You can also enable logging during remoteStorage object creation. See:\n * {@link RemoteStorage}).\n */\nfunction log(...args): void {\n if (config.logging) {\n // eslint-disable-next-line no-console\n console.log(...args);\n }\n}\n\nexport = log;\n","import log from './log';\nimport { EventHandler } from './interfaces/event_handling';\n\nclass EventHandling {\n _handlers: { [key: string]: EventHandler[] };\n\n /**\n * Register event names\n *\n * TODO see if necessary, or can be done on the fly in addEventListener\n */\n addEvents(additionalEvents: string[]): void {\n additionalEvents.forEach(evName => this._addEvent(evName));\n }\n\n /**\n * Install an event handler for the given event name\n */\n addEventListener (eventName: string, handler: EventHandler): void {\n // Check type for public consumption of API\n if (typeof (eventName) !== 'string') {\n throw new Error('Argument eventName should be a string');\n }\n if (typeof (handler) !== 'function') {\n throw new Error('Argument handler should be a function');\n }\n log('[EventHandling] Adding event listener', eventName);\n this._validateEvent(eventName);\n this._handlers[eventName].push(handler);\n }\n\n /*\n * Alias for addEventListener\n */\n on (eventName: string, handler: EventHandler): void {\n return this.addEventListener(eventName, handler);\n }\n\n /**\n * Remove a previously installed event handler\n */\n removeEventListener (eventName: string, handler: EventHandler): void {\n this._validateEvent(eventName);\n const hl = this._handlers[eventName].length;\n for (let i = 0; i < hl; i++) {\n if (this._handlers[eventName][i] === handler) {\n this._handlers[eventName].splice(i, 1);\n return;\n }\n }\n }\n\n _emit (eventName: string, ...args: unknown[]): void {\n this._validateEvent(eventName);\n this._handlers[eventName].slice().forEach((handler) => {\n handler.apply(this, args);\n });\n }\n\n _validateEvent (eventName: string): void {\n if (!(eventName in this._handlers)) {\n throw new Error(\"Unknown event: \" + eventName);\n }\n }\n\n _delegateEvent (eventName: string, target): void {\n target.on(eventName, (event) => {\n this._emit(eventName, event);\n });\n }\n\n _addEvent (eventName: string): void {\n if (typeof this._handlers === 'undefined') {\n this._handlers = {};\n }\n this._handlers[eventName] = [];\n }\n}\n\nexport = EventHandling;\n","/**\n * The default config, merged with the object passed to the constructor of the\n * RemoteStorage object\n */\nconst config = {\n cache: true,\n changeEvents: {\n local: true,\n window: false,\n remote: true,\n conflict: true\n },\n cordovaRedirectUri: undefined,\n logging: false,\n modules: [],\n // the following are not public and will probably be moved away from the\n // default config\n backgroundSyncInterval: 60000,\n disableFeatures: [],\n discoveryTimeout: 10000,\n isBackground: false,\n requestTimeout: 30000,\n syncInterval: 10000\n};\n\nexport = config;\n","class UnauthorizedError extends Error {\n code: string;\n\n constructor (message?: string, options: {code?: string} = {}) {\n super();\n this.name = 'Unauthorized';\n\n if (typeof message === 'undefined') {\n this.message = 'App authorization expired or revoked.';\n } else {\n this.message = message;\n }\n\n if (typeof options.code !== 'undefined') {\n this.code = options.code;\n }\n\n this.stack = (new Error()).stack;\n }\n}\n\nexport = UnauthorizedError;\n","var g;\n\n// This works in non-strict mode\ng = (function() {\n\treturn this;\n})();\n\ntry {\n\t// This works if eval is allowed (see CSP)\n\tg = g || new Function(\"return this\")();\n} catch (e) {\n\t// This works if the window reference is available\n\tif (typeof window === \"object\") g = window;\n}\n\n// g can still be undefined, but nothing to do about it...\n// We return undefined, instead of nothing here, so it's\n// easier to handle this case. if(!global) { ...}\n\nmodule.exports = g;\n","import log from './log';\nimport RemoteStorage from './remotestorage';\nimport { localStorageAvailable, globalContext, toBase64 } from './util';\nimport UnauthorizedError from './unauthorized-error';\nimport { EventHandler } from './interfaces/event_handling';\n\ninterface AuthOptions {\n authURL: string;\n scope?: string;\n clientId?: string;\n redirectUri?: string;\n}\n\ninterface AuthResult {\n access_token?: string;\n rsDiscovery?: object;\n error?: string;\n remotestorage?: string;\n state?: string;\n}\n\ninterface InAppBrowserEvent extends Event {\n type: 'loadstart'|'loadstop'|'loaderror'|'message'|'exit';\n url: string;\n code?: number;\n message?: string;\n data?: string;\n}\n\n// This is set in _rs_init and needed for removal in _rs_cleanup\nlet onFeaturesLoaded: EventHandler;\n\nfunction extractParams (url?: string): AuthResult {\n // FF already decodes the URL fragment in document.location.hash, so use this instead:\n // eslint-disable-next-line\n const location = url || Authorize.getLocation().href;\n const hashPos = location.indexOf('#');\n if (hashPos === -1) { return; }\n const urlFragment = location.substring(hashPos+1);\n // if hash is not of the form #key=val&key=val, it's probably not for us\n if (!urlFragment.includes('=')) { return; }\n\n return urlFragment.split('&').reduce(function(params, kvs) {\n const kv = kvs.split('=');\n\n if (kv[0] === 'state' && kv[1].match(/rsDiscovery/)) {\n // extract rsDiscovery data from the state param\n let stateValue = decodeURIComponent(kv[1]);\n const encodedData = stateValue.substr(stateValue.indexOf('rsDiscovery='))\n .split('&')[0]\n .split('=')[1];\n\n params['rsDiscovery'] = JSON.parse(atob(encodedData));\n\n // remove rsDiscovery param\n stateValue = stateValue.replace(new RegExp('&?rsDiscovery=' + encodedData), '');\n\n if (stateValue.length > 0) {\n params['state'] = stateValue;\n }\n } else {\n params[decodeURIComponent(kv[0])] = decodeURIComponent(kv[1]);\n }\n\n return params;\n }, {});\n}\n\nfunction buildOAuthURL (authURL: string, redirectUri: string, scope: string, clientId: string): string {\n const hashPos = redirectUri.indexOf('#');\n let url = authURL;\n\n url += authURL.indexOf('?') > 0 ? '&' : '?';\n url += 'redirect_uri=' + encodeURIComponent(redirectUri.replace(/#.*$/, ''));\n url += '&scope=' + encodeURIComponent(scope);\n url += '&client_id=' + encodeURIComponent(clientId);\n\n if (hashPos !== - 1 && hashPos+1 !== redirectUri.length) {\n url += '&state=' + encodeURIComponent(redirectUri.substring(hashPos+1));\n }\n url += '&response_type=token';\n\n return url;\n}\n\nclass Authorize {\n static IMPLIED_FAKE_TOKEN = false;\n\n static authorize (remoteStorage: RemoteStorage, { authURL, scope, redirectUri, clientId }: AuthOptions): void {\n log('[Authorize] authURL = ', authURL, 'scope = ', scope, 'redirectUri = ', redirectUri, 'clientId = ', clientId);\n\n if (!scope) {\n throw new Error(\"Cannot authorize due to undefined or empty scope; did you forget to access.claim()?\");\n }\n\n if (!scope) {\n throw new Error(\"Cannot authorize due to undefined or empty scope; did you forget to access.claim()?\");\n }\n\n // TODO add a test for this\n // keep track of the discovery data during redirect if we can't save it in localStorage\n if (!localStorageAvailable() && remoteStorage.backend === 'remotestorage') {\n redirectUri += redirectUri.indexOf('#') > 0 ? '&' : '#';\n\n const discoveryData = {\n userAddress: remoteStorage.remote.userAddress,\n href: remoteStorage.remote.href,\n storageApi: remoteStorage.remote.storageApi,\n properties: remoteStorage.remote.properties\n };\n\n redirectUri += 'rsDiscovery=' + toBase64(JSON.stringify(discoveryData));\n }\n\n const url = buildOAuthURL(authURL, redirectUri, scope, clientId);\n\n // FIXME declare potential `cordonva` property on global somehow, so we don't have to\n // use a string accessor here.\n if (globalContext['cordova']) {\n Authorize\n .openWindow(url, redirectUri, 'location=yes,clearsessioncache=yes,clearcache=yes')\n .then((authResult: AuthResult) => {\n remoteStorage.remote.configure({ token: authResult.access_token });\n });\n return;\n }\n\n Authorize.setLocation(url);\n }\n\n /**\n * Get current document location\n *\n * Override this method if access to document.location is forbidden\n */\n static getLocation = function (): Location {\n return document.location;\n };\n\n /**\n * Open new InAppBrowser window for OAuth in Cordova\n */\n static openWindow = function (url: string, redirectUri: string, options: string): Promise {\n return new Promise((resolve, reject) => {\n\n const newWindow = open(url, '_blank', options);\n\n if (!newWindow || newWindow.closed) {\n reject('Authorization popup was blocked'); return;\n }\n\n function handleExit (): void {\n reject('Authorization was canceled');\n }\n\n function handleLoadstart (event: InAppBrowserEvent): void {\n if (event.url.indexOf(redirectUri) !== 0) { return; }\n\n newWindow.removeEventListener('exit', handleExit);\n newWindow.close();\n\n const authResult: AuthResult = extractParams(event.url);\n\n if (!authResult) {\n reject('Authorization error'); return;\n }\n\n resolve(authResult);\n }\n\n newWindow.addEventListener('loadstart', handleLoadstart);\n newWindow.addEventListener('exit', handleExit);\n });\n };\n\n /**\n * Set current document location\n *\n * Override this method if access to document.location is forbidden\n */\n static setLocation (location: string | Location): void {\n if (typeof location === 'string') {\n document.location.href = location;\n } else if (typeof location === 'object') {\n document.location = location;\n } else {\n throw \"Invalid location \" + location;\n }\n }\n\n static _rs_supported (): boolean {\n return typeof(document) !== 'undefined';\n }\n\n static _rs_init = function (remoteStorage: RemoteStorage): void {\n const params = extractParams();\n let location: Location;\n\n if (params) {\n location = Authorize.getLocation();\n location.hash = '';\n }\n\n // eslint-disable-next-line\n onFeaturesLoaded = function(): void {\n let authParamsUsed = false;\n\n if (!params) {\n remoteStorage.remote.stopWaitingForToken();\n return;\n }\n\n if (params.error) {\n if (params.error === 'access_denied') {\n throw new UnauthorizedError('Authorization failed: access denied', { code: 'access_denied' });\n } else {\n throw new UnauthorizedError(`Authorization failed: ${params.error}`);\n }\n }\n\n // rsDiscovery came with the redirect, because it couldn't be\n // saved in localStorage\n if (params.rsDiscovery) {\n remoteStorage.remote.configure(params.rsDiscovery);\n }\n\n if (params.access_token) {\n remoteStorage.remote.configure({ token: params.access_token });\n authParamsUsed = true;\n }\n\n if (params.remotestorage) {\n remoteStorage.connect(params.remotestorage);\n authParamsUsed = true;\n }\n\n if (params.state) {\n location = Authorize.getLocation();\n Authorize.setLocation(location.href.split('#')[0]+'#'+params.state);\n }\n\n if (!authParamsUsed) {\n remoteStorage.remote.stopWaitingForToken();\n }\n };\n\n remoteStorage.on('features-loaded', onFeaturesLoaded);\n };\n\n static _rs_cleanup (remoteStorage: RemoteStorage): void {\n remoteStorage.removeEventListener('features-loaded', onFeaturesLoaded);\n }\n}\n\nexport = Authorize;\n","import tv4 from 'tv4';\nimport type { JsonSchemas } from './interfaces/json_schema';\nimport type { ChangeObj } from './interfaces/change_obj';\nimport type { QueuedRequestResponse } from './interfaces/queued_request_response';\nimport Types from './types';\nimport SchemaNotFound from './schema-not-found-error';\nimport EventHandling from './eventhandling';\nimport config from './config';\nimport { applyMixins, cleanPath, isFolder } from './util';\nimport RemoteStorage from './remotestorage';\n\nfunction getModuleNameFromBase(path: string): string {\n const parts = path.split('/');\n return path.length > 2 ? parts[1] : 'root';\n}\n\n/**\n * Provides a high-level interface to access data below a given root path.\n */\nclass BaseClient {\n /**\n * The instance this operates on.\n */\n storage: RemoteStorage;\n\n /**\n * Base path, which this operates on.\n *\n * For the module's privateClient this would be //, for the\n * corresponding publicClient /public//.\n */\n base: string;\n\n moduleName: string;\n\n constructor(storage: RemoteStorage, base: string) {\n if (base[base.length - 1] !== '/') {\n throw \"Not a folder: \" + base;\n }\n\n if (base === '/') {\n // allow absolute and relative paths for the root scope.\n this.makePath = (path: string): string => {\n return (path[0] === '/' ? '' : '/') + path;\n };\n }\n\n this.storage = storage;\n this.base = base;\n this.moduleName = getModuleNameFromBase(this.base);\n\n this.addEvents(['change']);\n this.on = this.on.bind(this);\n storage.onChange(this.base, this._fireChange.bind(this));\n }\n\n /**\n * Instantiate a new client, scoped to a subpath of the current client's\n * path.\n *\n * @param path - The path to scope the new client to\n *\n * @returns A new client operating on a subpath of the current base path\n */\n scope (path: string): BaseClient {\n return new BaseClient(this.storage, this.makePath(path));\n }\n\n /**\n * Get a list of child nodes below a given path.\n *\n * @param {string} path - The path to query. It MUST end with a forward slash.\n * @param {number} maxAge - (optional) Either ``false`` or the maximum age of\n * cached listing in milliseconds. See :ref:`max-age`.\n *\n * @returns {Promise} A promise for an object representing child nodes\n */\n // TODO add real return type\n async getListing (path?: string, maxAge?: false | number): Promise {\n if (typeof path !== 'string') { path = ''; }\n else if (path.length > 0 && !isFolder(path)) {\n return Promise.reject(\"Not a folder: \" + path);\n }\n\n return this.storage.get(this.makePath(path), maxAge).then((r: QueuedRequestResponse) => {\n return r.statusCode === 404 ? {} : r.body;\n });\n }\n\n /**\n * Get all objects directly below a given path.\n *\n * @param {string} path - Path to the folder. Must end in a forward slash.\n * @param {number} maxAge - (optional) Either ``false`` or the maximum age of\n * cached objects in milliseconds. See :ref:`max-age`.\n *\n * @returns {Promise} A promise for an object\n */\n // TODO add real return type\n async getAll (path: string, maxAge?: false | number): Promise {\n if (typeof path !== 'string') { path = ''; }\n else if (path.length > 0 && !isFolder(path)) {\n return Promise.reject(\"Not a folder: \" + path);\n }\n\n return this.storage.get(this.makePath(path), maxAge).then((r: QueuedRequestResponse) => {\n if (r.statusCode === 404) { return {}; }\n if (typeof r.body === 'object') {\n const keys = Object.keys(r.body);\n // treat this like 404. it probably means a folder listing that\n // has changes that haven't been pushed out yet.\n if (keys.length === 0) { return {}; }\n\n const calls = keys.map((key: string) => {\n return this.storage.get(this.makePath(path + key), maxAge)\n .then((o: QueuedRequestResponse) => {\n if (typeof o.body === 'string') {\n try { o.body = JSON.parse(o.body); }\n catch (e) { /* empty */ }\n }\n if (typeof o.body === 'object') {\n r.body[key] = o.body;\n }\n });\n });\n\n return Promise.all(calls).then(() => { return r.body; });\n }\n });\n }\n\n /**\n * Get the file at the given path. A file is raw data, as opposed to\n * a JSON object (use :func:`getObject` for that).\n *\n * @param {string} path - Relative path from the module root (without leading\n * slash).\n * @param {number} maxAge - (optional) Either ``false`` or the maximum age of\n * the cached file in milliseconds. See :ref:`max-age`.\n *\n * @returns {Promise} A promise for an object\n */\n // TODO add real return type\n async getFile (path: string, maxAge?: false | number): Promise {\n if (typeof path !== 'string') {\n return Promise.reject('Argument \\'path\\' of baseClient.getFile must be a string');\n }\n\n return this.storage.get(this.makePath(path), maxAge).then((r: QueuedRequestResponse) => {\n return {\n data: r.body,\n contentType: r.contentType,\n revision: r.revision // (this is new)\n };\n });\n }\n\n /**\n * Store raw data at a given path.\n *\n * @param {string} mimeType - MIME media type of the data being stored\n * @param {string} path - Path relative to the module root\n * @param {string|ArrayBuffer|ArrayBufferView} body - Raw data to store\n *\n * @returns {Promise} A promise for the created/updated revision (ETag)\n */\n async storeFile (mimeType: string, path: string, body: string | ArrayBuffer | ArrayBufferView): Promise {\n if (typeof mimeType !== 'string') {\n return Promise.reject('Argument \\'mimeType\\' of baseClient.storeFile must be a string');\n }\n if (typeof path !== 'string') {\n return Promise.reject('Argument \\'path\\' of baseClient.storeFile must be a string');\n }\n if ((typeof body !== 'string') && (typeof body !== 'object')) {\n return Promise.reject('Argument \\'body\\' of baseClient.storeFile must be a string, ArrayBuffer, or ArrayBufferView');\n }\n if (!this.storage.access.checkPathPermission(this.makePath(path), 'rw')) {\n console.warn('WARNING: Editing a document to which only read access (\\'r\\') was claimed');\n }\n\n return this.storage.put(this.makePath(path), body, mimeType).then((r: QueuedRequestResponse) => {\n if (r.statusCode === 200 || r.statusCode === 201) {\n return r.revision;\n } else {\n return Promise.reject(\"Request (PUT \" + this.makePath(path) + \") failed with status: \" + r.statusCode);\n }\n });\n }\n\n /**\n * Get a JSON object from the given path.\n *\n * @param {string} path - Relative path from the module root (without leading\n * slash).\n * @param {number} maxAge - (optional) Either ``false`` or the maximum age of\n * cached object in milliseconds. See :ref:`max-age`.\n *\n * @returns {Promise} A promise, which resolves with the requested object (or ``null``\n * if non-existent)\n */\n\n // TODO add real return type\n async getObject (path: string, maxAge?: false | number): Promise {\n if (typeof path !== 'string') {\n return Promise.reject('Argument \\'path\\' of baseClient.getObject must be a string');\n }\n\n return this.storage.get(this.makePath(path), maxAge).then((r: QueuedRequestResponse) => {\n if (typeof r.body === 'object') { // will be the case for documents stored with rs.js <= 0.10.0-beta2\n return r.body;\n } else if (typeof r.body === 'string') {\n try {\n return JSON.parse(r.body);\n } catch (e) {\n throw new Error(\"Not valid JSON: \" + this.makePath(path));\n }\n } else if (typeof r.body !== 'undefined' && r.statusCode === 200) {\n return Promise.reject(\"Not an object: \" + this.makePath(path));\n }\n });\n }\n\n /**\n * Store object at given path. Triggers synchronization.\n *\n * See ``declareType()`` and :doc:`data types `\n * for an explanation of types\n *\n * For any given `path`, must not be called more frequently than once per second.\n *\n * @param {string} typeAlias - Unique type of this object within this module.\n * @param {string} path - Path relative to the module root.\n * @param {object} object - A JavaScript object to be stored at the given\n * path. Must be serializable as JSON.\n *\n * @returns {Promise} Resolves with revision on success. Rejects with\n * a ValidationError, if validations fail.\n */\n // TODO add real return type\n async storeObject (typeAlias: string, path: string, object: object): Promise {\n if (typeof typeAlias !== 'string') {\n return Promise.reject('Argument \\'typeAlias\\' of baseClient.storeObject must be a string');\n }\n if (typeof path !== 'string') {\n return Promise.reject('Argument \\'path\\' of baseClient.storeObject must be a string');\n }\n if (typeof object !== 'object') {\n return Promise.reject('Argument \\'object\\' of baseClient.storeObject must be an object');\n }\n\n this._attachType(object, typeAlias);\n\n try {\n const validationResult = this.validate(object);\n if (!validationResult.valid) {\n return Promise.reject(validationResult);\n }\n } catch (exc) {\n return Promise.reject(exc);\n }\n\n return this.storage.put(this.makePath(path), JSON.stringify(object), 'application/json; charset=UTF-8').then((r: QueuedRequestResponse) => {\n if (r.statusCode === 200 || r.statusCode === 201) {\n return r.revision;\n } else {\n return Promise.reject(\"Request (PUT \" + this.makePath(path) + \") failed with status: \" + r.statusCode);\n }\n });\n }\n\n /**\n * Remove node at given path from storage. Triggers synchronization.\n *\n * @param {string} path - Path relative to the module root.\n * @returns {Promise}\n */\n // TODO add real return type\n remove (path: string): Promise {\n if (typeof path !== 'string') {\n return Promise.reject('Argument \\'path\\' of baseClient.remove must be a string');\n }\n if (!this.storage.access.checkPathPermission(this.makePath(path), 'rw')) {\n console.warn('WARNING: Removing a document to which only read access (\\'r\\') was claimed');\n }\n\n return this.storage.delete(this.makePath(path));\n }\n\n /**\n * Retrieve full URL of a document. Useful for example for sharing the public\n * URL of an item in the ``/public`` folder.\n *\n * @param {string} path - Path relative to the module root.\n * @returns {string} The full URL of the item, including the storage origin\n */\n getItemURL (path: string): string {\n if (typeof path !== 'string') {\n throw 'Argument \\'path\\' of baseClient.getItemURL must be a string';\n }\n if (this.storage.connected) {\n path = cleanPath(this.makePath(path));\n return this.storage.remote.href + path;\n } else {\n return undefined;\n }\n }\n\n /**\n * Set caching strategy for a given path and its children.\n *\n * See :ref:`caching-strategies` for a detailed description of the available\n * strategies.\n *\n * @param {string} path - Path to cache\n * @param {string} strategy - Caching strategy. One of 'ALL', 'SEEN', or\n * 'FLUSH'. Defaults to 'ALL'.\n *\n * @returns {BaseClient} The same instance this is called on to allow for method chaining\n */\n cache (path: string, strategy: 'ALL' | 'SEEN' | 'FLUSH' = 'ALL'): BaseClient {\n if (typeof path !== 'string') {\n throw 'Argument \\'path\\' of baseClient.cache must be a string';\n }\n if (typeof strategy !== 'string') {\n throw 'Argument \\'strategy\\' of baseClient.cache must be a string or undefined';\n }\n if (strategy !== 'FLUSH' &&\n strategy !== 'SEEN' &&\n strategy !== 'ALL') {\n throw 'Argument \\'strategy\\' of baseclient.cache must be one of '\n + '[\"FLUSH\", \"SEEN\", \"ALL\"]';\n }\n\n this.storage.caching.set(this.makePath(path), strategy);\n return this;\n }\n\n /**\n * TODO: document\n *\n * @param {string} path\n */\n // TODO add return type once known\n flush (path: string): unknown {\n return this.storage.local.flush(path);\n }\n\n /**\n * Declare a remoteStorage object type using a JSON schema.\n *\n * See :doc:`Defining data types ` for more info.\n *\n * @param {string} alias - A type alias/shortname\n * @param {uri} uri - (optional) JSON-LD URI of the schema. Automatically generated if none given\n * @param {object} schema - A JSON Schema object describing the object type\n **/\n declareType (alias: string, uriOrSchema: string|tv4.JsonSchema, schema?: tv4.JsonSchema): void {\n let uri: string;\n\n if (schema && typeof uriOrSchema === 'string') {\n uri = uriOrSchema;\n } else if (!schema && typeof uriOrSchema !== 'string') {\n schema = uriOrSchema;\n uri = this._defaultTypeURI(alias);\n } else if (!schema && typeof uriOrSchema === 'string') {\n throw new Error('declareType() requires a JSON Schema object to be passed, in order to validate object types/formats');\n }\n\n BaseClient.Types.declare(this.moduleName, alias, uri, schema);\n }\n\n /**\n * Validate an object against the associated schema.\n *\n * @param {Object} object - JS object to validate. Must have a ``@context`` property.\n *\n * @returns {Object} An object containing information about validation errors\n **/\n validate (object: {[key: string]: any}): {[key: string]: any} {\n const schema = BaseClient.Types.getSchema(object['@context']);\n if (schema) {\n return tv4.validateResult(object, schema);\n } else {\n throw new SchemaNotFound(object['@context']);\n }\n }\n\n /**\n * TODO document\n *\n * @private\n */\n schemas = {\n configurable: true,\n\n get (): JsonSchemas {\n return BaseClient.Types.inScope(this.moduleName);\n }\n };\n\n /**\n * The default JSON-LD @context URL for RS types/objects/documents\n *\n * @private\n */\n _defaultTypeURI (alias: string): string {\n return 'http://remotestorage.io/spec/modules/' + encodeURIComponent(this.moduleName) + '/' + encodeURIComponent(alias);\n }\n\n /**\n * Attaches the JSON-LD @content to an object\n *\n * @private\n */\n _attachType (object: object, alias: string): void {\n object['@context'] = BaseClient.Types.resolveAlias(this.moduleName + '/' + alias) || this._defaultTypeURI(alias);\n }\n\n /**\n * TODO: document\n *\n * @private\n */\n makePath (path: string): string {\n return this.base + (path || '');\n }\n\n /**\n * TODO: document\n *\n * @private\n */\n _fireChange (event: ChangeObj): void {\n if (config.changeEvents[event.origin]) {\n ['new', 'old', 'lastCommon'].forEach(function (fieldNamePrefix) {\n if ((!event[fieldNamePrefix + 'ContentType'])\n || (/^application\\/(.*)json(.*)/.exec(event[fieldNamePrefix + 'ContentType']))) {\n if (typeof event[fieldNamePrefix + 'Value'] === 'string') {\n try {\n event[fieldNamePrefix + 'Value'] = JSON.parse(event[fieldNamePrefix + 'Value']);\n } catch (e) {\n // empty\n }\n }\n }\n });\n this._emit('change', event);\n }\n }\n\n static Types = Types;\n\n static _rs_init (): void {\n return;\n }\n}\n\ninterface BaseClient extends EventHandling {}\napplyMixins(BaseClient, [EventHandling]);\n\nexport = BaseClient;\n","/**\n * This file exposes a get/put/delete interface on top of fetch() or XMLHttpRequest.\n * It requires to be configured with parameters about the remotestorage server to\n * connect to.\n * Each instance of WireClient is always associated with a single remotestorage\n * server and access token.\n *\n * Usually the WireClient instance can be accessed via `remoteStorage.remote`.\n *\n * This is the get/put/delete interface:\n *\n * - #get() takes a path and optionally a ifNoneMatch option carrying a version\n * string to check. It returns a promise that will be fulfilled with the HTTP\n * response status, the response body, the MIME type as returned in the\n * 'Content-Type' header and the current revision, as returned in the 'ETag'\n * header.\n * - #put() takes a path, the request body and a content type string. It also\n * accepts the ifMatch and ifNoneMatch options, that map to the If-Match and\n * If-None-Match headers respectively. See the remotestorage-01 specification\n * for details on handling these headers. It returns a promise, fulfilled with\n * the same values as the one for #get().\n * - #delete() takes a path and the ifMatch option as well. It returns a promise\n * fulfilled with the same values as the one for #get().\n *\n * In addition to this, the WireClient has some compatibility features to work with\n * remotestorage 2012.04 compatible storages. For example it will cache revisions\n * from folder listings in-memory and return them accordingly as the \"revision\"\n * parameter in response to #get() requests. Similarly it will return 404 when it\n * receives an empty folder listing, to mimic remotestorage-01 behavior. Note\n * that it is not always possible to know the revision beforehand, hence it may\n * be undefined at times (especially for caching-roots).\n */\nimport RemoteStorage from './remotestorage';\nimport Authorize from './authorize';\nimport EventHandling from './eventhandling';\nimport UnauthorizedError from './unauthorized-error';\nimport config from './config';\nimport log from './log';\nimport {\n applyMixins,\n cleanPath,\n getJSONFromLocalStorage,\n getTextFromArrayBuffer,\n isFolder,\n localStorageAvailable,\n shouldBeTreatedAsBinary\n} from './util';\n\nlet hasLocalStorage;\nconst SETTINGS_KEY = 'remotestorage:wireclient';\n\nconst API_2012 = 1;\nconst API_00 = 2;\nconst API_01 = 3;\nconst API_02 = 4;\nconst API_HEAD = 5;\n\nconst STORAGE_APIS = {\n 'draft-dejong-remotestorage-00': API_00,\n 'draft-dejong-remotestorage-01': API_01,\n 'draft-dejong-remotestorage-02': API_02,\n 'https://www.w3.org/community/rww/wiki/read-write-web-00#simple': API_2012\n};\n\nfunction readSettings () {\n const settings = getJSONFromLocalStorage(SETTINGS_KEY) || {};\n const { userAddress, href, storageApi, token, properties } = settings;\n\n return { userAddress, href, storageApi, token, properties };\n}\n\nlet isArrayBufferView;\n\nif (typeof ((global || window as any).ArrayBufferView) === 'function') {\n isArrayBufferView = function (object) {\n return object && (object instanceof (global || window as any).ArrayBufferView);\n };\n} else {\n const arrayBufferViews = [\n Int8Array, Uint8Array, Int16Array, Uint16Array,\n Int32Array, Uint32Array, Float32Array, Float64Array\n ];\n isArrayBufferView = function (object): boolean {\n for (let i = 0; i < 8; i++) {\n if (object instanceof arrayBufferViews[i]) {\n return true;\n }\n }\n return false;\n };\n}\n\n// TODO double check\ninterface WireClientSettings {\n userAddress: string;\n href: string;\n storageApi: string;\n token: string;\n properties: unknown;\n}\n\ninterface WireRequestResponse {\n statusCode: number;\n revision: string | undefined;\n body?: any;\n}\n\nfunction addQuotes (str: string): string {\n if (typeof (str) !== 'string') {\n return str;\n }\n if (str === '*') {\n return '*';\n }\n\n return '\"' + str + '\"';\n}\n\nfunction stripQuotes (str: string): string {\n if (typeof (str) !== 'string') {\n return str;\n }\n\n return str.replace(/^[\"']|[\"']$/g, '');\n}\n\nfunction determineCharset (mimeType: string): string {\n let charset = 'utf-8';\n let charsetMatch;\n\n if (mimeType) {\n charsetMatch = mimeType.match(/charset=(.+)$/);\n if (charsetMatch) {\n charset = charsetMatch[1];\n }\n }\n return charset;\n}\n\nfunction isFolderDescription (body: object): boolean {\n return ((body['@context'] === 'http://remotestorage.io/spec/folder-description')\n && (typeof (body['items']) === 'object'));\n}\n\nfunction isSuccessStatus (status: number): boolean {\n return [201, 204, 304].indexOf(status) >= 0;\n}\n\nfunction isErrorStatus (status: number): boolean {\n return [401, 403, 404, 412].indexOf(status) >= 0;\n}\n\nfunction isForbiddenRequestMethod(method: string, uri: string): boolean {\n if (method === 'PUT' || method === 'DELETE') {\n return isFolder(uri);\n } else {\n return false;\n }\n}\n\nclass WireClient {\n rs: RemoteStorage;\n connected: boolean;\n online: boolean;\n userAddress: string;\n\n /**\n * Holds the bearer token of this WireClient, as obtained in the OAuth dance\n *\n * Example:\n * (start code)\n *\n * remoteStorage.remote.token\n * // -> 'DEADBEEF01=='\n */\n token: string;\n\n /**\n * Holds the server's base URL, as obtained in the Webfinger discovery\n *\n * Example:\n * (start code)\n *\n * remoteStorage.remote.href\n * // -> 'https://storage.example.com/users/jblogg/'\n */\n href: string;\n\n /**\n * Holds the spec version the server claims to be compatible with\n *\n * Example:\n * (start code)\n *\n * remoteStorage.remote.storageApi\n * // -> 'draft-dejong-remotestorage-01'\n */\n storageApi: string;\n // TODO implement TS validation for incoming type\n\n supportsRevs: boolean;\n\n _revisionCache: { [key: string]: any } = {};\n\n properties: any;\n\n constructor (rs: RemoteStorage) {\n hasLocalStorage = localStorageAvailable();\n\n this.rs = rs;\n this.connected = false;\n\n /**\n * Event: connected\n * Fired when the wireclient connect method realizes that it is in\n * possession of a token and href\n **/\n this.addEvents(['connected', 'not-connected']);\n\n if (hasLocalStorage) {\n const settings = readSettings();\n if (settings) {\n setTimeout(() => {\n this.configure(settings);\n }, 0);\n }\n }\n\n if (this.connected) {\n setTimeout(this._emit.bind(this), 0, 'connected');\n }\n }\n\n get storageType () {\n if (this.storageApi) {\n const spec = this.storageApi.match(/draft-dejong-(remotestorage-\\d\\d)/);\n return spec ? spec[1] : '2012.04';\n } else {\n return undefined;\n }\n }\n\n async _request (method: string, uri: string, token: string | false, headers: object, body: unknown, getEtag: boolean, fakeRevision?: string): Promise {\n if (isForbiddenRequestMethod(method, uri)) {\n return Promise.reject(`Don't use ${method} on directories!`);\n }\n\n let revision: string | undefined;\n\n if (token !== Authorize.IMPLIED_FAKE_TOKEN) {\n headers['Authorization'] = 'Bearer ' + token;\n }\n\n this.rs._emit('wire-busy', {\n method: method,\n isFolder: isFolder(uri)\n });\n\n return WireClient.request(method, uri, {\n body: body,\n headers: headers,\n responseType: 'arraybuffer'\n }).then((response: XMLHttpRequest): Promise => {\n if (!this.online) {\n this.online = true;\n this.rs._emit('network-online');\n }\n this.rs._emit('wire-done', {\n method: method,\n isFolder: isFolder(uri),\n success: true\n });\n\n if (isErrorStatus(response.status)) {\n log('[WireClient] Error response status', response.status);\n if (getEtag) {\n revision = stripQuotes(response.getResponseHeader('ETag'));\n } else {\n revision = undefined;\n }\n\n if (response.status === 401) {\n this.rs._emit('error', new UnauthorizedError());\n }\n\n return Promise.resolve({statusCode: response.status, revision: revision});\n } else if (isSuccessStatus(response.status) ||\n (response.status === 200 && method !== 'GET')) {\n revision = stripQuotes(response.getResponseHeader('ETag'));\n log('[WireClient] Successful request', revision);\n return Promise.resolve({statusCode: response.status, revision: revision});\n } else {\n const mimeType = response.getResponseHeader('Content-Type');\n if (getEtag) {\n revision = stripQuotes(response.getResponseHeader('ETag'));\n } else {\n revision = (response.status === 200) ? fakeRevision : undefined;\n }\n\n const charset = determineCharset(mimeType);\n\n if (shouldBeTreatedAsBinary(response.response, mimeType)) {\n log('[WireClient] Successful request with unknown or binary mime-type', revision);\n return Promise.resolve({\n statusCode: response.status,\n body: response.response,\n contentType: mimeType,\n revision: revision\n });\n } else {\n return getTextFromArrayBuffer(response.response, charset)\n .then((textContent) => {\n log('[WireClient] Successful request', revision);\n return Promise.resolve({\n statusCode: response.status,\n body: textContent,\n contentType: mimeType,\n revision: revision\n });\n });\n }\n }\n }, error => {\n if (this.online) {\n this.online = false;\n this.rs._emit('network-offline');\n }\n this.rs._emit('wire-done', {\n method: method,\n isFolder: isFolder(uri),\n success: false\n });\n\n return Promise.reject(error);\n });\n }\n\n /**\n * Sets the userAddress, href, storageApi, token, and properties of a\n * remote store. Also sets connected and online to true and emits the\n * 'connected' event, if both token and href are present.\n *\n * Parameters:\n * settings - An object that may contain userAddress (string or null),\n * href (string or null), storageApi (string or null), token (string\n * or null), and/or properties (the JSON-parsed properties object\n * from the user's WebFinger record, see section 10 of\n * http://tools.ietf.org/html/draft-dejong-remotestorage-03\n * or null).\n * Fields that are not included (i.e. `undefined`), stay at\n * their current value. To set a field, include that field\n * with a `string` value. To reset a field, for instance when\n * the user disconnected their storage, or you found that the\n * token you have has expired, simply set that field to `null`.\n */\n configure (settings: WireClientSettings): void {\n if (typeof settings !== 'object') {\n throw new Error('WireClient configure settings parameter should be an object');\n }\n if (typeof settings.userAddress !== 'undefined') {\n this.userAddress = settings.userAddress;\n }\n if (typeof settings.href !== 'undefined') {\n this.href = settings.href;\n }\n if (typeof settings.storageApi !== 'undefined') {\n this.storageApi = settings.storageApi;\n }\n if (typeof settings.token !== 'undefined') {\n this.token = settings.token;\n }\n if (typeof settings.properties !== 'undefined') {\n this.properties = settings.properties;\n }\n\n if (typeof this.storageApi === 'string') {\n const _storageApi = STORAGE_APIS[this.storageApi] || API_HEAD;\n this.supportsRevs = _storageApi >= API_00;\n }\n if (this.href && this.token) {\n this.connected = true;\n this.online = true;\n this._emit('connected');\n } else {\n this.connected = false;\n }\n if (hasLocalStorage) {\n localStorage[SETTINGS_KEY] = JSON.stringify({\n userAddress: this.userAddress,\n href: this.href,\n storageApi: this.storageApi,\n token: this.token,\n properties: this.properties\n });\n }\n }\n\n stopWaitingForToken (): void {\n if (!this.connected) {\n this._emit('not-connected');\n }\n }\n\n get (path: string, options: { ifNoneMatch?: string } = {}): Promise {\n if (!this.connected) {\n return Promise.reject('not connected (path: ' + path + ')');\n }\n\n const headers = {};\n if (this.supportsRevs) {\n if (options.ifNoneMatch) {\n headers['If-None-Match'] = addQuotes(options.ifNoneMatch);\n }\n }\n // commenting it out as this is doing nothing and jshint is complaining -les\n // else if (options.ifNoneMatch) {\n // let oldRev = this._revisionCache[path];\n // }\n\n return this._request('GET', this.href + cleanPath(path), this.token, headers,\n undefined, this.supportsRevs, this._revisionCache[path])\n .then((r) => {\n if (!isFolder(path)) {\n return Promise.resolve(r);\n }\n let itemsMap = {};\n if (typeof (r.body) !== 'undefined') {\n try {\n r.body = JSON.parse(r.body);\n } catch (e) {\n return Promise.reject('Folder description at ' + this.href + cleanPath(path) + ' is not JSON');\n }\n }\n\n if (r.statusCode === 200 && typeof (r.body) === 'object') {\n // New folder listing received\n if (Object.keys(r.body).length === 0) {\n // Empty folder listing of any spec\n r.statusCode = 404;\n } else if (isFolderDescription(r.body)) {\n // >= 02 spec\n for (const item in r.body.items) {\n this._revisionCache[path + item] = r.body.items[item].ETag;\n }\n itemsMap = r.body.items;\n } else {\n // < 02 spec\n Object.keys(r.body).forEach((key) => {\n this._revisionCache[path + key] = r.body[key];\n itemsMap[key] = {'ETag': r.body[key]};\n });\n }\n r.body = itemsMap;\n return Promise.resolve(r);\n } else {\n return Promise.resolve(r);\n }\n });\n }\n\n put (path: string, body: unknown, contentType: string, options: { ifMatch?: string; ifNoneMatch?: string } = {}) {\n if (!this.connected) {\n return Promise.reject('not connected (path: ' + path + ')');\n }\n if ((!contentType.match(/charset=/)) && (body instanceof ArrayBuffer || isArrayBufferView(body))) {\n contentType += '; charset=binary';\n }\n const headers = {'Content-Type': contentType};\n if (this.supportsRevs) {\n if (options.ifMatch) {\n headers['If-Match'] = addQuotes(options.ifMatch);\n }\n if (options.ifNoneMatch) {\n headers['If-None-Match'] = addQuotes(options.ifNoneMatch);\n }\n }\n return this._request('PUT', this.href + cleanPath(path), this.token,\n headers, body, this.supportsRevs);\n }\n\n delete (path: string, options: { ifMatch?: string } = {}) {\n if (!this.connected) {\n throw new Error('not connected (path: ' + path + ')');\n }\n if (!options) {\n options = {};\n }\n const headers = {};\n if (this.supportsRevs) {\n if (options.ifMatch) {\n headers['If-Match'] = addQuotes(options.ifMatch);\n }\n }\n return this._request('DELETE', this.href + cleanPath(path), this.token,\n headers,\n undefined, this.supportsRevs);\n }\n\n // Shared isArrayBufferView used by WireClient and Dropbox\n static isArrayBufferView = isArrayBufferView;\n\n // TODO add proper definition for options\n // Shared request function used by WireClient, GoogleDrive and Dropbox.\n static async request (method: string, url: string, options: unknown): Promise {\n if (typeof fetch === 'function') {\n return WireClient._fetchRequest(method, url, options);\n } else if (typeof XMLHttpRequest === 'function') {\n return WireClient._xhrRequest(method, url, options);\n } else {\n log('[WireClient] You need to add a polyfill for fetch or XMLHttpRequest');\n return Promise.reject('[WireClient] You need to add a polyfill for fetch or XMLHttpRequest');\n }\n }\n\n /** options includes body, headers and responseType */\n static _fetchRequest (method: string, url: string, options): Promise {\n let syntheticXhr;\n const responseHeaders = {};\n let abortController;\n if (typeof AbortController === 'function') {\n abortController = new AbortController();\n }\n const networkPromise: Promise = fetch(url, {\n method: method,\n headers: options.headers,\n body: options.body,\n signal: abortController ? abortController.signal : undefined\n }).then((response) => {\n log('[WireClient fetch]', response);\n\n response.headers.forEach((value: string, headerName: string) => {\n responseHeaders[headerName.toUpperCase()] = value;\n });\n\n syntheticXhr = {\n readyState: 4,\n status: response.status,\n statusText: response.statusText,\n response: undefined,\n getResponseHeader: (headerName: string): unknown => {\n return responseHeaders[headerName.toUpperCase()] || null;\n },\n // responseText: 'foo',\n responseType: options.responseType,\n responseURL: url,\n };\n switch (options.responseType) {\n case 'arraybuffer':\n return response.arrayBuffer();\n case 'blob':\n return response.blob();\n case 'json':\n return response.json();\n case undefined:\n case '':\n case 'text':\n return response.text();\n default: // document\n throw new Error(\"responseType 'document' is not currently supported using fetch\");\n }\n }).then((processedBody) => {\n syntheticXhr.response = processedBody;\n if (!options.responseType || options.responseType === 'text') {\n syntheticXhr.responseText = processedBody;\n }\n return syntheticXhr;\n });\n\n const timeoutPromise: Promise = new Promise((resolve, reject) => {\n setTimeout(() => {\n reject('timeout');\n if (abortController) {\n abortController.abort();\n }\n }, config.requestTimeout);\n });\n\n return Promise.race([networkPromise, timeoutPromise]);\n }\n\n static _xhrRequest (method, url, options): Promise {\n return new Promise((resolve, reject) => {\n\n log('[WireClient]', method, url);\n\n let timedOut = false;\n\n const timer = setTimeout(() => {\n timedOut = true;\n reject('timeout');\n }, config.requestTimeout);\n\n const xhr = new XMLHttpRequest();\n xhr.open(method, url, true);\n\n if (options.responseType) {\n xhr.responseType = options.responseType;\n }\n\n if (options.headers) {\n for (const key in options.headers) {\n xhr.setRequestHeader(key, options.headers[key]);\n }\n }\n\n xhr.onload = (): void => {\n if (timedOut) {\n return;\n }\n clearTimeout(timer);\n resolve(xhr);\n };\n\n xhr.onerror = (error): void => {\n if (timedOut) {\n return;\n }\n clearTimeout(timer);\n reject(error);\n };\n\n let body = options.body;\n\n if (typeof (body) === 'object' && !isArrayBufferView(body) && body instanceof ArrayBuffer) {\n body = new Uint8Array(body);\n }\n xhr.send(body);\n });\n }\n\n static _rs_init (remoteStorage): void {\n remoteStorage.remote = new WireClient(remoteStorage);\n remoteStorage.remote.online = true;\n }\n\n static _rs_supported (): boolean {\n return typeof fetch === 'function' || typeof XMLHttpRequest === 'function';\n }\n\n static _rs_cleanup (): void {\n if (hasLocalStorage) {\n delete localStorage[SETTINGS_KEY];\n }\n }\n}\n\ninterface WireClient extends EventHandling {}\napplyMixins(WireClient, [EventHandling]);\n\nexport = WireClient;\n","class SyncError extends Error {\n originalError: Error;\n\n constructor (originalError: string | Error) {\n super();\n this.name = 'SyncError';\n this.message = 'Sync failed: ';\n if (typeof originalError === 'string') {\n this.message += originalError;\n } else {\n this.message += originalError.message;\n this.stack = originalError.stack;\n this.originalError = originalError;\n }\n }\n}\n\nexport = SyncError;\n","import type { ChangeObj } from './interfaces/change_obj';\nimport type { QueuedRequestResponse } from './interfaces/queued_request_response';\nimport type { RSEvent } from './interfaces/rs_event';\nimport type { RSNode, RSNodes, ProcessNodes } from './interfaces/rs_node';\nimport EventHandling from './eventhandling';\nimport config from './config';\nimport log from './log';\nimport {\n applyMixins,\n deepClone,\n equal,\n isDocument,\n isFolder,\n pathsFromRoot\n} from './util';\n\nfunction getLatest (node: RSNode): any {\n if (typeof (node) !== 'object' || typeof (node.path) !== 'string') {\n return;\n }\n if (isFolder(node.path)) {\n if (node.local && node.local.itemsMap) {\n return node.local;\n }\n if (node.common && node.common.itemsMap) {\n return node.common;\n }\n } else {\n if (node.local) {\n if (node.local.body && node.local.contentType) {\n return node.local;\n }\n if (node.local.body === false) {\n return;\n }\n }\n if (node.common && node.common.body && node.common.contentType) {\n return node.common;\n }\n // Migration code! Once all apps use at least this version of the lib, we\n // can publish clean-up code that migrates over any old-format data, and\n // stop supporting it. For now, new apps will support data in both\n // formats, thanks to this:\n if (node.body && node.contentType) {\n return {\n body: node.body,\n contentType: node.contentType\n };\n }\n }\n}\n\nfunction isOutdated (nodes: RSNodes, maxAge: number): boolean {\n for (const path in nodes) {\n if (nodes[path] && nodes[path].remote) {\n return true;\n }\n const nodeVersion = getLatest(nodes[path]);\n if (nodeVersion && nodeVersion.timestamp && (new Date().getTime()) - nodeVersion.timestamp <= maxAge) {\n return false;\n } else if (!nodeVersion) {\n return true;\n }\n }\n return true;\n}\n\n\nfunction makeNode (path: string): RSNode {\n const node: RSNode = {path: path, common: {}};\n\n if (isFolder(path)) {\n node.common.itemsMap = {};\n }\n return node;\n}\n\nfunction updateFolderNodeWithItemName (node: RSNode, itemName: string): RSNode {\n if (!node.common) {\n node.common = {\n itemsMap: {}\n };\n }\n if (!node.common.itemsMap) {\n node.common.itemsMap = {};\n }\n if (!node.local) {\n node.local = deepClone(node.common);\n }\n if (!node.local.itemsMap) {\n node.local.itemsMap = node.common.itemsMap;\n }\n node.local.itemsMap[itemName] = true;\n\n return node;\n}\n\n/**\n * This module defines functions that are mixed into remoteStorage.local when\n * it is instantiated (currently one of indexeddb.js, localstorage.js, or\n * inmemorystorage.js).\n *\n * All remoteStorage.local implementations should therefore implement\n * this.getNodes, this.setNodes, and this.forAllNodes. The rest is blended in\n * here to create a GPD (get/put/delete) interface which the BaseClient can\n * talk to.\n *\n * @interface\n */\n\nabstract class CachingLayer {\n // FIXME\n // this process of updating nodes needs to be heavily documented first, then\n // refactored. Right now it's almost impossible to refactor as there's no\n // explanation of why things are implemented certain ways or what the goal(s)\n // of the behavior are. -slvrbckt (+1 -les)\n private _updateNodesRunning = false;\n private _updateNodesQueued = [];\n\n\n // functions that will be overwritten\n // ----------------------------------\n abstract getNodes(paths: string[]): Promise;\n\n abstract diffHandler(...args: any[]);\n\n abstract forAllNodes(cb: (node) => any): Promise;\n\n abstract setNodes(nodes: RSNodes): Promise;\n\n\n // --------------------------------------------------\n\n // TODO: improve our code structure so that this function\n // could call sync.queueGetRequest directly instead of needing\n // this hacky third parameter as a callback\n async get (path: string, maxAge: number, queueGetRequest: (path2: string) => Promise): Promise {\n\n if (typeof (maxAge) === 'number') {\n return this.getNodes(pathsFromRoot(path))\n .then((objs) => {\n const node: RSNode = getLatest(objs[path]);\n\n if (isOutdated(objs, maxAge)) {\n return queueGetRequest(path);\n } else if (node) {\n return {\n statusCode: 200,\n body: node.body || node.itemsMap,\n contentType: node.contentType\n };\n } else {\n return { statusCode: 404 };\n }\n });\n } else {\n return this.getNodes([path])\n .then((objs) => {\n const node: RSNode = getLatest(objs[path]);\n\n if (node) {\n if (isFolder(path)) {\n for (const i in node.itemsMap) {\n // the hasOwnProperty check here is only because our jshint settings require it:\n if (node.itemsMap.hasOwnProperty(i) && node.itemsMap[i] === false) {\n delete node.itemsMap[i];\n }\n }\n }\n return {\n statusCode: 200,\n body: node.body || node.itemsMap,\n contentType: node.contentType\n };\n } else {\n return {statusCode: 404};\n }\n });\n }\n }\n\n async put (path: string, body: unknown, contentType: string): Promise {\n const paths = pathsFromRoot(path);\n\n function _processNodes(nodePaths: string[], nodes: RSNodes): RSNodes {\n try {\n for (let i = 0, len = nodePaths.length; i < len; i++) {\n const nodePath = nodePaths[i];\n let node = nodes[nodePath];\n let previous: RSNode;\n\n if (!node) {\n nodes[nodePath] = node = makeNode(nodePath);\n }\n\n // Document\n if (i === 0) {\n previous = getLatest(node);\n node.local = {\n body: body,\n contentType: contentType,\n previousBody: (previous ? previous.body : undefined),\n previousContentType: (previous ? previous.contentType : undefined),\n };\n }\n // Folder\n else {\n const itemName = nodePaths[i - 1].substring(nodePath.length);\n node = updateFolderNodeWithItemName(node, itemName);\n }\n }\n return nodes;\n } catch (e) {\n log('[Cachinglayer] Error during PUT', nodes, e);\n throw e;\n }\n }\n\n return this._updateNodes(paths, _processNodes);\n }\n\n delete (path: string): unknown {\n const paths = pathsFromRoot(path);\n\n return this._updateNodes(paths, function (nodePaths, nodes) {\n for (let i = 0, len = nodePaths.length; i < len; i++) {\n const nodePath = nodePaths[i];\n const node = nodes[nodePath];\n let previous;\n\n if (!node) {\n console.error('Cannot delete non-existing node ' + nodePath);\n continue;\n }\n\n if (i === 0) {\n // Document\n previous = getLatest(node);\n node.local = {\n body: false,\n previousBody: (previous ? previous.body : undefined),\n previousContentType: (previous ? previous.contentType : undefined),\n };\n } else {\n // Folder\n if (!node.local) {\n node.local = deepClone(node.common);\n }\n const itemName = nodePaths[i - 1].substring(nodePath.length);\n delete node.local.itemsMap[itemName];\n\n if (Object.getOwnPropertyNames(node.local.itemsMap).length > 0) {\n // This folder still contains other items, don't remove any further ancestors\n break;\n }\n }\n }\n return nodes;\n });\n }\n\n flush(path: string): unknown {\n\n return this._getAllDescendentPaths(path).then((paths: string[]) => {\n return this.getNodes(paths);\n }).then((nodes: RSNodes) => {\n for (const nodePath in nodes) {\n const node = nodes[nodePath];\n\n if (node && node.common && node.local) {\n this._emitChange({\n path: node.path,\n origin: 'local',\n oldValue: (node.local.body === false ? undefined : node.local.body),\n newValue: (node.common.body === false ? undefined : node.common.body)\n });\n }\n nodes[nodePath] = undefined;\n }\n\n return this.setNodes(nodes);\n });\n }\n\n private _emitChange(obj: ChangeObj): void {\n if (config.changeEvents[obj.origin]) {\n this._emit('change', obj);\n }\n }\n\n fireInitial (): void {\n if (!config.changeEvents.local) { return; }\n\n this.forAllNodes((node) => {\n if (isDocument(node.path)) {\n const latest = getLatest(node);\n if (latest) {\n this._emitChange({\n path: node.path,\n origin: 'local',\n oldValue: undefined,\n oldContentType: undefined,\n newValue: latest.body,\n newContentType: latest.contentType\n });\n }\n }\n }).then(() => {\n this._emit('local-events-done');\n });\n }\n\n // TODO add proper type\n onDiff(diffHandler: any) {\n this.diffHandler = diffHandler;\n }\n\n migrate(node: RSNode): RSNode {\n if (typeof (node) === 'object' && !node.common) {\n node.common = {};\n if (typeof (node.path) === 'string') {\n if (node.path.substr(-1) === '/' && typeof (node.body) === 'object') {\n node.common.itemsMap = node.body;\n }\n } else {\n //save legacy content of document node as local version\n if (!node.local) {\n node.local = {};\n }\n node.local.body = node.body;\n node.local.contentType = node.contentType;\n }\n }\n return node;\n }\n\n\n private _updateNodes(paths: string[], _processNodes: ProcessNodes): Promise {\n return new Promise((resolve, reject) => {\n this._doUpdateNodes(paths, _processNodes, {\n resolve: resolve,\n reject: reject\n });\n });\n }\n\n private _doUpdateNodes(paths: string[], _processNodes: ProcessNodes, promise) {\n if (this._updateNodesRunning) {\n this._updateNodesQueued.push({\n paths: paths,\n cb: _processNodes,\n promise: promise\n });\n return;\n } else {\n this._updateNodesRunning = true;\n }\n\n this.getNodes(paths).then((nodes) => {\n const existingNodes = deepClone(nodes);\n const changeEvents = [];\n\n nodes = _processNodes(paths, nodes);\n\n for (const path in nodes) {\n const node = nodes[path];\n if (equal(node, existingNodes[path])) {\n delete nodes[path];\n } else if (isDocument(path)) {\n if (\n !equal(node.local.body, node.local.previousBody) ||\n node.local.contentType !== node.local.previousContentType\n ) {\n changeEvents.push({\n path: path,\n origin: 'window',\n oldValue: node.local.previousBody,\n newValue: node.local.body === false ? undefined : node.local.body,\n oldContentType: node.local.previousContentType,\n newContentType: node.local.contentType\n });\n }\n delete node.local.previousBody;\n delete node.local.previousContentType;\n }\n }\n\n this.setNodes(nodes).then(() => {\n this._emitChangeEvents(changeEvents);\n promise.resolve({statusCode: 200});\n });\n }).then(() => {\n return Promise.resolve();\n }, (err) => {\n promise.reject(err);\n }).then(() => {\n this._updateNodesRunning = false;\n const nextJob = this._updateNodesQueued.shift();\n if (nextJob) {\n this._doUpdateNodes(nextJob.paths, nextJob.cb, nextJob.promise);\n }\n });\n }\n\n private _emitChangeEvents(events: RSEvent[]) {\n for (let i = 0, len = events.length; i < len; i++) {\n this._emitChange(events[i]);\n if (this.diffHandler) {\n this.diffHandler(events[i].path);\n }\n }\n }\n\n private _getAllDescendentPaths(path: string) {\n if (isFolder(path)) {\n return this.getNodes([path]).then((nodes) => {\n const allPaths = [path];\n const latest = getLatest(nodes[path]);\n\n const itemNames = Object.keys(latest.itemsMap);\n const calls = itemNames.map((itemName) => {\n return this._getAllDescendentPaths(path + itemName).then((paths) => {\n for (let i = 0, len = paths.length; i < len; i++) {\n allPaths.push(paths[i]);\n }\n });\n });\n return Promise.all(calls).then(() => {\n return allPaths;\n });\n });\n } else {\n return Promise.resolve([path]);\n }\n }\n\n // treated as private but made public for unit testing\n _getInternals() {\n return {\n getLatest: getLatest,\n makeNode: makeNode,\n isOutdated: isOutdated\n };\n }\n}\n\n\ninterface CachingLayer extends EventHandling {}\napplyMixins(CachingLayer, [EventHandling]);\n\nexport = CachingLayer;\n","// TODO maybe move to common interfaces & types file\n// also worth considering enums\ntype AccessMode = 'r' | 'rw';\ntype AccessScope = string;\n\ninterface ScopeEntry {\n name: string;\n mode: AccessMode;\n}\n\ninterface ScopeModeMap {\n // NOTE: key is actually AccessScope\n [key: string]: AccessMode;\n}\n\n/**\n * @class Access\n *\n * Keeps track of claimed access and scopes.\n */\nclass Access {\n scopeModeMap: ScopeModeMap;\n rootPaths: string[];\n storageType: string;\n\n // TODO create custom type for init function\n static _rs_init(): void {\n return;\n }\n\n constructor() {\n this.reset();\n }\n\n /**\n * Property: scopes\n *\n * Holds an array of claimed scopes in the form\n * > { name: \"\", mode: \"\" }\n */\n get scopes(): ScopeEntry[] {\n return Object.keys(this.scopeModeMap).map((key) => {\n return { name: key, mode: this.scopeModeMap[key] };\n });\n }\n\n get scopeParameter(): string {\n return this.scopes.map((scope) => {\n return `${this._scopeNameForParameter(scope)}:${scope.mode}`;\n }).join(' ');\n }\n\n /**\n * Claim access on a given scope with given mode.\n *\n * @param {string} scope - An access scope, such as \"contacts\" or \"calendar\"\n * @param {string} mode - Access mode. Either \"r\" for read-only or \"rw\" for read/write\n */\n claim (scope: AccessScope, mode: AccessMode): void {\n if (typeof (scope) !== 'string' || scope.indexOf('/') !== -1 || scope.length === 0) {\n throw new Error('Scope should be a non-empty string without forward slashes');\n }\n if (!mode.match(/^rw?$/)) {\n throw new Error('Mode should be either \\'r\\' or \\'rw\\'');\n }\n this._adjustRootPaths(scope);\n this.scopeModeMap[scope] = mode;\n }\n\n /**\n * Get the access mode for a given scope.\n *\n * @param {string} scope - Access scope\n * @returns {string} Access mode\n */\n get (scope: AccessScope): AccessMode {\n return this.scopeModeMap[scope];\n }\n\n\n /**\n * Remove access for the given scope.\n *\n * @param {string} scope - Access scope\n */\n remove (scope: AccessScope): void {\n const savedMap: ScopeModeMap = {};\n for (const name in this.scopeModeMap) {\n savedMap[name] = this.scopeModeMap[name];\n }\n this.reset();\n delete savedMap[scope];\n for (const name in savedMap) {\n this.claim(name as AccessScope, savedMap[name]);\n }\n }\n\n /**\n * Verify permission for a given scope.\n *\n * @param {string} scope - Access scope\n * @param {string} mode - Access mode\n * @returns {boolean} true if the requested access mode is active, false otherwise\n */\n checkPermission (scope: AccessScope, mode: AccessMode): boolean {\n const actualMode = this.get(scope);\n return actualMode && (mode === 'r' || actualMode === 'rw');\n }\n\n /**\n * Verify permission for a given path.\n *\n * @param {string} path - Path\n * @param {string} mode - Access mode\n * @returns {boolean} true if the requested access mode is active, false otherwise\n */\n checkPathPermission (path: string, mode: AccessMode): boolean {\n if (this.checkPermission('*', mode)) {\n return true;\n }\n // TODO check if this is reliable\n const scope = this._getModuleName(path) as AccessScope;\n return !!this.checkPermission(scope, mode);\n }\n\n /**\n * Reset all access permissions.\n */\n reset(): void {\n this.rootPaths = [];\n this.scopeModeMap = {};\n }\n\n /**\n * Return the module name for a given path.\n */\n private _getModuleName (path): string {\n if (path[0] !== '/') {\n throw new Error('Path should start with a slash');\n }\n const moduleMatch = path.replace(/^\\/public/, '').match(/^\\/([^/]*)\\//);\n return moduleMatch ? moduleMatch[1] : '*';\n }\n\n /**\n * TODO: document\n */\n private _adjustRootPaths (newScope: AccessScope): void {\n if ('*' in this.scopeModeMap || newScope === '*') {\n this.rootPaths = ['/'];\n } else if (!(newScope in this.scopeModeMap)) {\n this.rootPaths.push('/' + newScope + '/');\n this.rootPaths.push('/public/' + newScope + '/');\n }\n }\n\n /**\n * TODO: document\n */\n private _scopeNameForParameter (scope: ScopeEntry): string {\n if (scope.name === '*' && this.storageType) {\n if (this.storageType === '2012.04') {\n return '';\n } else if (this.storageType.match(/remotestorage-0[01]/)) {\n return 'root';\n }\n }\n return scope.name;\n }\n\n /**\n * Set the storage type of the remote.\n *\n * @param {string} type - Storage type\n */\n setStorageType (type: string): void {\n this.storageType = type;\n }\n}\n\nexport = Access;\n","import { containingFolder, isFolder } from './util';\nimport log from './log';\n\n/**\n * @class Caching\n *\n * Holds/manages caching configuration.\n **/\nclass Caching {\n pendingActivations: string[] = [];\n // TODO add correct type\n activateHandler: (firstPending: string) => void;\n\n private _rootPaths: object;\n\n constructor () {\n this.reset();\n }\n\n /**\n * Configure caching for a given path explicitly.\n *\n * Not needed when using ``enable``/``disable``.\n *\n * @param {string} path - Path to cache\n * @param {string} strategy - Caching strategy. One of 'ALL', 'SEEN', or 'FLUSH'.\n */\n set (path: string, strategy: 'ALL' | 'SEEN' | 'FLUSH'): void {\n if (typeof path !== 'string') {\n throw new Error('path should be a string');\n }\n if (!isFolder(path)) {\n throw new Error('path should be a folder');\n }\n // FIXME We need to get to the access instance somehow. But I'm not sure\n // this check is even necessary in the first place. -raucao\n // if (!this._remoteStorage.access.checkPathPermission(path, 'r')) {\n // throw new Error('No access to path \"' + path + '\". You have to claim access to it first.');\n // }\n if (!strategy.match(/^(FLUSH|SEEN|ALL)$/)) {\n throw new Error(\"strategy should be 'FLUSH', 'SEEN', or 'ALL'\");\n }\n\n this._rootPaths[path] = strategy;\n\n if (strategy === 'ALL') {\n if (this.activateHandler) {\n this.activateHandler(path);\n } else {\n this.pendingActivations.push(path);\n }\n }\n }\n\n /**\n * Enable caching for a given path.\n *\n * Uses caching strategy ``ALL``.\n *\n * @param {string} path - Path to enable caching for\n */\n enable (path: string): void {\n this.set(path, 'ALL');\n }\n\n /**\n * Disable caching for a given path.\n *\n * Uses caching strategy ``FLUSH`` (meaning items are only cached until\n * successfully pushed to the remote).\n *\n * @param {string} path - Path to disable caching for\n */\n disable (path: string): void {\n this.set(path, 'FLUSH');\n }\n\n /**\n * Set a callback for when caching is activated for a path.\n *\n * @param {function} cb - Callback function\n */\n onActivate (cb: (firstPending: string) => void): void {\n log('[Caching] Setting activate handler', cb, this.pendingActivations);\n this.activateHandler = cb;\n for (let i = 0; i < this.pendingActivations.length; i++) {\n cb(this.pendingActivations[i]);\n }\n this.pendingActivations = [];\n }\n\n /**\n * Retrieve caching setting for a given path, or its next parent\n * with a caching strategy set.\n *\n * @param {string} path - Path to retrieve setting for\n * @returns {string} caching strategy for the path\n **/\n checkPath (path: string): string {\n if (this._rootPaths[path] !== undefined) {\n return this._rootPaths[path];\n } else if (path === '/') {\n return 'SEEN';\n } else {\n return this.checkPath(containingFolder(path));\n }\n }\n\n /**\n * Reset the state of caching by deleting all caching information.\n **/\n reset (): void {\n this._rootPaths = {};\n }\n\n /**\n * Setup function that is called on initialization.\n *\n * @private\n **/\n static _rs_init (/*remoteStorage*/): void {\n return;\n }\n}\n\nexport = Caching;\n","import BaseClient from './baseclient';\nimport WireClient from './wireclient';\nimport EventHandling from './eventhandling';\nimport {\n applyMixins,\n isFolder,\n cleanPath,\n shouldBeTreatedAsBinary,\n getJSONFromLocalStorage,\n getTextFromArrayBuffer,\n localStorageAvailable\n} from './util';\n\nconst BASE_URL = 'https://www.googleapis.com';\nconst AUTH_URL = 'https://accounts.google.com/o/oauth2/auth';\nconst AUTH_SCOPE = 'https://www.googleapis.com/auth/drive';\nconst SETTINGS_KEY = 'remotestorage:googledrive';\nconst PATH_PREFIX = '/remotestorage';\n\nconst GD_DIR_MIME_TYPE = 'application/vnd.google-apps.folder';\nconst RS_DIR_MIME_TYPE = 'application/json; charset=UTF-8';\n\nlet hasLocalStorage;\n\n/**\n * Produce a title from a filename for metadata.\n *\n * @param {string} filename\n * @returns {string} title\n *\n * @private\n */\nfunction metaTitleFromFileName (filename: string): string {\n if (filename.substr(-1) === '/') {\n filename = filename.substr(0, filename.length - 1);\n }\n\n return decodeURIComponent(filename);\n}\n\n/**\n * Get the parent directory for the given path.\n *\n * @param {string} path\n * @returns {string} parent directory\n *\n * @private\n */\nfunction parentPath (path: string): string {\n return path.replace(/[^\\/]+\\/?$/, '');\n}\n\n/**\n * Get only the filename from a full path.\n *\n * @param {string} path\n * @returns {string} filename\n *\n * @private\n */\nfunction baseName (path: string): string {\n const parts = path.split('/');\n if (path.substr(-1) === '/') {\n return parts[parts.length-2]+'/';\n } else {\n return parts[parts.length-1];\n }\n}\n\n/**\n * Prepend the path with the remoteStorage base directory.\n *\n * @param {string} path - Path\n * @returns {string} Actual path on Google Drive\n *\n * @private\n */\nfunction googleDrivePath (path: string): string {\n return cleanPath(`${PATH_PREFIX}/${path}`);\n}\n\n/**\n * Remove surrounding quotes from a string.\n *\n * @param {string} string - string with surrounding quotes\n * @returns {string} string without surrounding quotes\n *\n * @private\n */\nfunction removeQuotes (str: string): string {\n return str.replace(/^[\"'](.*)[\"']$/, \"$1\");\n}\n\n/**\n * Internal cache object for storing Google file IDs.\n *\n * @param {number} maxAge - Maximum age (in seconds) the content should be cached for\n */\nclass FileIdCache {\n maxAge: number;\n _items = {};\n\n constructor(maxAge?: number) {\n this.maxAge = maxAge;\n this._items = {};\n }\n\n get (key): number | undefined {\n const item = this._items[key];\n const now = new Date().getTime();\n return (item && item.t >= (now - this.maxAge)) ? item.v : undefined;\n }\n\n set (key, value): void {\n this._items[key] = {\n v: value,\n t: new Date().getTime()\n };\n }\n}\n\n/**\n * Overwrite BaseClient's getItemURL with our own implementation\n *\n * TODO: Still needs to be implemented. At the moment it just throws\n * and error saying that it's not implemented yet.\n *\n * @param {object} rs - RemoteStorage instance\n *\n * @private\n */\nfunction hookGetItemURL (rs): void {\n if (rs._origBaseClientGetItemURL) { return; }\n rs._origBaseClientGetItemURL = BaseClient.prototype.getItemURL;\n BaseClient.prototype.getItemURL = function (/* path */): never {\n throw new Error('getItemURL is not implemented for Google Drive yet');\n };\n}\n\n/**\n * Restore BaseClient's getItemURL original implementation\n *\n * @param {object} rs - RemoteStorage instance\n *\n * @private\n */\nfunction unHookGetItemURL (rs): void {\n if (!rs._origBaseClientGetItemURL) { return; }\n BaseClient.prototype.getItemURL = rs._origBaseClientGetItemURL;\n delete rs._origBaseClientGetItemURL;\n}\n\n/**\n * @class GoogleDrive\n *\n * To use this backend, you need to specify the app's client ID like so:\n *\n * @example\n * remoteStorage.setApiKeys({\n * googledrive: 'your-client-id'\n * });\n *\n * A client ID can be obtained by registering your app in the Google\n * Developers Console: https://console.developers.google.com/flows/enableapi?apiid=drive\n *\n * Docs: https://developers.google.com/drive/v3/web/quickstart/js\n**/\nclass GoogleDrive {\n rs: any;\n clientId: string;\n userAddress: string;\n token: string;\n connected = false;\n online = true;\n\n _fileIdCache: FileIdCache;\n\n constructor(remoteStorage, clientId) {\n this.addEvents(['connected', 'not-connected']);\n\n this.rs = remoteStorage;\n this.clientId = clientId;\n\n this._fileIdCache = new FileIdCache(60 * 5); // IDs expire after 5 minutes (is this a good idea?)\n\n hasLocalStorage = localStorageAvailable();\n\n if (hasLocalStorage){\n const settings = getJSONFromLocalStorage(SETTINGS_KEY);\n if (settings) {\n this.configure(settings);\n }\n }\n }\n\n /**\n * Configure the Google Drive backend.\n *\n * Fetches the user info from Google when no ``userAddress`` is given.\n *\n * @param {Object} settings\n * @param {string} [settings.userAddress] - The user's email address\n * @param {string} [settings.token] - Authorization token\n *\n * @protected\n */\n configure (settings) { // Settings parameter compatible with WireClient\n // We only update this.userAddress if settings.userAddress is set to a string or to null\n if (typeof settings.userAddress !== 'undefined') { this.userAddress = settings.userAddress; }\n // Same for this.token. If only one of these two is set, we leave the other one at its existing value\n if (typeof settings.token !== 'undefined') { this.token = settings.token; }\n\n const writeSettingsToCache = function() {\n if (hasLocalStorage) {\n localStorage.setItem(SETTINGS_KEY, JSON.stringify({\n userAddress: this.userAddress,\n token: this.token\n }));\n }\n };\n\n const handleError = function() {\n this.connected = false;\n delete this.token;\n if (hasLocalStorage) {\n localStorage.removeItem(SETTINGS_KEY);\n }\n };\n\n if (this.token) {\n this.connected = true;\n\n if (this.userAddress) {\n this._emit('connected');\n writeSettingsToCache.apply(this);\n } else {\n this.info().then((info) => {\n this.userAddress = info.user.emailAddress;\n this._emit('connected');\n writeSettingsToCache.apply(this);\n }).catch(() => {\n handleError.apply(this);\n this.rs._emit('error', new Error('Could not fetch user info.'));\n });\n }\n } else {\n handleError.apply(this);\n }\n }\n\n /**\n * Initiate the authorization flow's OAuth dance.\n */\n connect (): void {\n this.rs.setBackend('googledrive');\n this.rs.authorize({ authURL: AUTH_URL, scope: AUTH_SCOPE, clientId: this.clientId });\n }\n\n /**\n * Stop the authorization process.\n *\n * @protected\n */\n stopWaitingForToken (): void {\n if (!this.connected) {\n this._emit('not-connected');\n }\n }\n\n /**\n * Request a resource (file or directory).\n *\n * @param {string} path - Path of the resource\n * @param {Object} options - Request options\n * @returns {Promise} Resolves with an object containing the status code,\n * body, content-type and revision\n *\n * @protected\n */\n get (path, options) {\n if (isFolder(path)) {\n return this._getFolder(googleDrivePath(path));\n } else {\n return this._getFile(googleDrivePath(path), options);\n }\n }\n\n /**\n * Create or update a file.\n *\n * @param {string} path - File path\n * @param body - File content\n * @param {string} contentType - File content-type\n * @param {Object} options\n * @param {string} options.ifNoneMatch - Only create of update the file if the\n * current ETag doesn't match this string\n * @returns {Promise} Resolves with an object containing the status code,\n * content-type and revision\n *\n * @protected\n */\n put (path, body, contentType, options) {\n const fullPath = googleDrivePath(path);\n\n function putDone(response) {\n if (response.status >= 200 && response.status < 300) {\n const meta = JSON.parse(response.responseText);\n const etagWithoutQuotes = removeQuotes(meta.etag);\n return Promise.resolve({statusCode: 200, contentType: meta.mimeType, revision: etagWithoutQuotes});\n } else if (response.status === 412) {\n return Promise.resolve({statusCode: 412, revision: 'conflict'});\n } else {\n return Promise.reject(\"PUT failed with status \" + response.status + \" (\" + response.responseText + \")\");\n }\n }\n\n return this._getFileId(fullPath).then((id) => {\n if (id) {\n if (options && (options.ifNoneMatch === '*')) {\n return putDone({ status: 412 });\n }\n return this._updateFile(id, fullPath, body, contentType, options).then(putDone);\n } else {\n return this._createFile(fullPath, body, contentType).then(putDone);\n }\n });\n }\n\n /**\n * Delete a file.\n *\n * @param {string} path - File path\n * @param {Object} options\n * @param {string} options.ifMatch - only delete the file if it's ETag\n * matches this string\n * @returns {Promise} Resolves with an object containing the status code\n *\n * @protected\n */\n delete (path, options) {\n const fullPath = googleDrivePath(path);\n\n return this._getFileId(fullPath).then((id) => {\n if (!id) {\n // File doesn't exist. Ignore.\n return Promise.resolve({statusCode: 200});\n }\n\n return this._getMeta(id).then((meta) => {\n let etagWithoutQuotes;\n if ((typeof meta === 'object') && (typeof meta.etag === 'string')) {\n etagWithoutQuotes = removeQuotes(meta.etag);\n }\n if (options && options.ifMatch && (options.ifMatch !== etagWithoutQuotes)) {\n return {statusCode: 412, revision: etagWithoutQuotes};\n }\n\n return this._request('DELETE', BASE_URL + '/drive/v2/files/' + id, {}).then((response) => {\n if (response.status === 200 || response.status === 204) {\n return {statusCode: 200};\n } else {\n return Promise.reject(\"Delete failed: \" + response.status + \" (\" + response.responseText + \")\");\n }\n });\n });\n });\n }\n\n /**\n * Fetch the user's info from Google.\n *\n * @returns {Promise} resolves with the user's info.\n *\n * @protected\n */\n info () {\n const url = BASE_URL + '/drive/v2/about?fields=user';\n // requesting user info(mainly for userAdress)\n return this._request('GET', url, {}).then(function (resp){\n try {\n const info = JSON.parse(resp.responseText);\n return Promise.resolve(info);\n } catch (e) {\n return Promise.reject(e);\n }\n });\n }\n\n /**\n * Update an existing file.\n *\n * @param {string} id - File ID\n * @param {string} path - File path\n * @param body - File content\n * @param {string} contentType - File content-type\n * @param {Object} options\n * @param {string} options.ifMatch - Only update the file if its ETag\n * matches this string\n * @returns {Promise} Resolves with the response of the network request\n *\n * @private\n */\n _updateFile (id, path, body, contentType, options) {\n const metadata = {\n mimeType: contentType\n };\n const headers = {\n 'Content-Type': 'application/json; charset=UTF-8'\n };\n\n if (options && options.ifMatch) {\n headers['If-Match'] = '\"' + options.ifMatch + '\"';\n }\n\n return this._request('PUT', BASE_URL + '/upload/drive/v2/files/' + id + '?uploadType=resumable', {\n body: JSON.stringify(metadata),\n headers: headers\n }).then((response) => {\n if (response.status === 412) {\n return (response);\n } else {\n return this._request('PUT', response.getResponseHeader('Location'), {\n body: contentType.match(/^application\\/json/) ? JSON.stringify(body) : body\n });\n }\n });\n }\n\n /**\n * Create a new file.\n *\n * @param {string} path - File path\n * @param body - File content\n * @param {string} contentType - File content-type\n * @returns {Promise} Resolves with the response of the network request\n *\n * @private\n */\n _createFile (path, body, contentType) {\n return this._getParentId(path).then((parentId) => {\n const fileName = baseName(path);\n const metadata = {\n title: metaTitleFromFileName(fileName),\n mimeType: contentType,\n parents: [{\n kind: \"drive#fileLink\",\n id: parentId\n }]\n };\n return this._request('POST', BASE_URL + '/upload/drive/v2/files?uploadType=resumable', {\n body: JSON.stringify(metadata),\n headers: {\n 'Content-Type': 'application/json; charset=UTF-8'\n }\n }).then((response) => {\n return this._request('POST', response.getResponseHeader('Location'), {\n body: contentType.match(/^application\\/json/) ? JSON.stringify(body) : body\n });\n });\n });\n }\n\n /**\n * Request a file.\n *\n * @param {string} path - File path\n * @param {Object} options\n * @param {string} [options.ifNoneMath] - Only return the file if its ETag\n * doesn't match the given string\n * @returns {Promise} Resolves with an object containing the status code,\n * body, content-type and revision\n *\n * @private\n */\n _getFile (path, options) {\n return this._getFileId(path).then((id) => {\n return this._getMeta(id).then((meta) => {\n let etagWithoutQuotes;\n if (typeof(meta) === 'object' && typeof(meta.etag) === 'string') {\n etagWithoutQuotes = removeQuotes(meta.etag);\n }\n\n if (options && options.ifNoneMatch && (etagWithoutQuotes === options.ifNoneMatch)) {\n return Promise.resolve({statusCode: 304});\n }\n\n if (!meta.downloadUrl) {\n if (meta.exportLinks && meta.exportLinks['text/html']) {\n // Documents that were generated inside GoogleDocs have no\n // downloadUrl, but you can export them to text/html instead:\n meta.mimeType += ';export=text/html';\n meta.downloadUrl = meta.exportLinks['text/html'];\n } else {\n // empty file\n return Promise.resolve({statusCode: 200, body: '', contentType: meta.mimeType, revision: etagWithoutQuotes});\n }\n }\n\n const params = {\n responseType: 'arraybuffer'\n };\n return this._request('GET', meta.downloadUrl, params).then((response) => {\n //first encode the response as text, and later check if\n //text appears to actually be binary data\n return getTextFromArrayBuffer(response.response, 'UTF-8').then(function (responseText) {\n let body = responseText;\n if (meta.mimeType.match(/^application\\/json/)) {\n try {\n body = JSON.parse(body as string);\n } catch(e) {\n // body couldn't be parsed as JSON, so we'll just return it as is\n }\n } else if (shouldBeTreatedAsBinary(responseText, meta.mimeType)) {\n //return unprocessed response\n body = response.response;\n }\n\n return {\n statusCode: 200,\n body: body,\n contentType: meta.mimeType,\n revision: etagWithoutQuotes\n };\n });\n });\n });\n });\n }\n\n /**\n * Request a directory.\n *\n * @param {string} path - Directory path\n * @param {Object} options\n * @returns {Promise} Resolves with an object containing the status code,\n * body and content-type\n *\n * @private\n */\n _getFolder (path) {\n return this._getFileId(path).then((id) => {\n let data, etagWithoutQuotes, itemsMap;\n if (! id) {\n return Promise.resolve({statusCode: 404});\n }\n\n const query = '\\'' + id + '\\' in parents';\n const fields = 'items(downloadUrl,etag,fileSize,id,mimeType,title,labels)';\n return this._request('GET', BASE_URL + '/drive/v2/files?'\n + 'q=' + encodeURIComponent(query)\n + '&fields=' + encodeURIComponent(fields)\n + '&maxResults=1000'\n + '&trashed=false',\n {})\n .then((response) => {\n if (response.status !== 200) {\n return Promise.reject('request failed or something: ' + response.status);\n }\n\n try {\n data = JSON.parse(response.responseText);\n } catch(e) {\n return Promise.reject('non-JSON response from GoogleDrive');\n }\n\n itemsMap = {};\n for (const item of data.items) {\n if (item.labels?.trashed) { continue; } // ignore deleted files\n\n etagWithoutQuotes = removeQuotes(item.etag);\n if (item.mimeType === GD_DIR_MIME_TYPE) {\n this._fileIdCache.set(path + cleanPath(item.title) + '/', item.id);\n itemsMap[item.title + '/'] = {\n ETag: etagWithoutQuotes\n };\n } else {\n this._fileIdCache.set(path + cleanPath(item.title), item.id);\n itemsMap[item.title] = {\n ETag: etagWithoutQuotes,\n 'Content-Type': item.mimeType,\n 'Content-Length': item.fileSize\n };\n }\n }\n\n // FIXME: add revision of folder!\n return Promise.resolve({statusCode: 200, body: itemsMap, contentType: RS_DIR_MIME_TYPE, revision: undefined});\n });\n });\n }\n\n /**\n * Get the ID of a parent path.\n *\n * Creates the directory if it doesn't exist yet.\n *\n * @param {string} path - Full path of a directory or file\n * @returns {Promise} Resolves with ID of the parent directory.\n *\n * @private\n */\n _getParentId (path) {\n const foldername = parentPath(path);\n\n return this._getFileId(foldername).then((parentId) => {\n if (parentId) {\n return Promise.resolve(parentId);\n } else {\n return this._createFolder(foldername);\n }\n });\n }\n\n /**\n * Create a directory.\n *\n * Creates all parent directories as well if any of them didn't exist yet.\n *\n * @param {string} path - Directory path\n * @returns {Promise} Resolves with the ID of the new directory\n *\n * @private\n */\n _createFolder (path) {\n return this._getParentId(path).then((parentId) => {\n return this._request('POST', BASE_URL + '/drive/v2/files', {\n body: JSON.stringify({\n title: metaTitleFromFileName(baseName(path)),\n mimeType: GD_DIR_MIME_TYPE,\n parents: [{\n id: parentId\n }]\n }),\n headers: {\n 'Content-Type': 'application/json; charset=UTF-8'\n }\n }).then((response) => {\n const meta = JSON.parse(response.responseText);\n return Promise.resolve(meta.id);\n });\n });\n }\n\n /**\n * Get the ID of a file.\n *\n * @param {string} path - File path\n * @returns {Promise} Resolves with the ID\n *\n * @private\n */\n _getFileId (path) {\n let id;\n\n if (path === '/') {\n // \"root\" is a special alias for the fileId of the root folder\n return Promise.resolve('root');\n } else if ((id = this._fileIdCache.get(path))) {\n // id is cached.\n return Promise.resolve(id);\n }\n // id is not cached (or file doesn't exist).\n // load parent folder listing to propagate / update id cache.\n return this._getFolder(parentPath(path)).then(() => {\n id = this._fileIdCache.get(path);\n if (!id) {\n if (path.substr(-1) === '/') {\n return this._createFolder(path).then(() => {\n return this._getFileId(path);\n });\n } else {\n return Promise.resolve();\n }\n }\n return Promise.resolve(id);\n });\n }\n\n /**\n * Get the metadata for a given file ID.\n *\n * @param {string} id - File ID\n * @returns {Promise} Resolves with an object containing the metadata\n *\n * @private\n */\n _getMeta (id) {\n return this._request('GET', BASE_URL + '/drive/v2/files/' + id, {}).then(function (response) {\n if (response.status === 200) {\n return Promise.resolve(JSON.parse(response.responseText));\n } else {\n return Promise.reject(\"request (getting metadata for \" + id + \") failed with status: \" + response.status);\n }\n });\n }\n\n /**\n * Make a network request.\n *\n * @param {string} method - Request method\n * @param {string} url - Target URL\n * @param {Object} options - Request options\n * @returns {Promise} Resolves with the response of the network request\n *\n * @private\n */\n _request (method, url, options) {\n if (! options.headers) { options.headers = {}; }\n options.headers['Authorization'] = 'Bearer ' + this.token;\n\n this.rs._emit('wire-busy', {\n method: method,\n isFolder: isFolder(url)\n });\n\n return WireClient.request.call(this, method, url, options).then((xhr) => {\n // Google tokens expire from time to time...\n if (xhr && xhr.status === 401) {\n this.connect();\n return;\n } else {\n if (!this.online) {\n this.online = true;\n this.rs._emit('network-online');\n }\n this.rs._emit('wire-done', {\n method: method,\n isFolder: isFolder(url),\n success: true\n });\n\n return Promise.resolve(xhr);\n }\n }, (error) => {\n if (this.online) {\n this.online = false;\n this.rs._emit('network-offline');\n }\n this.rs._emit('wire-done', {\n method: method,\n isFolder: isFolder(url),\n success: false\n });\n\n return Promise.reject(error);\n });\n }\n\n /**\n * Initialize the Google Drive backend.\n *\n * @param {Object} remoteStorage - RemoteStorage instance\n *\n * @protected\n */\n static _rs_init (remoteStorage): void {\n const config = remoteStorage.apiKeys.googledrive;\n if (config) {\n remoteStorage.googledrive = new GoogleDrive(remoteStorage, config.clientId);\n if (remoteStorage.backend === 'googledrive') {\n remoteStorage._origRemote = remoteStorage.remote;\n remoteStorage.remote = remoteStorage.googledrive;\n\n hookGetItemURL(remoteStorage);\n }\n }\n }\n\n /**\n * Inform about the availability of the Google Drive backend.\n *\n * @param {Object} rs - RemoteStorage instance\n * @returns {Boolean}\n *\n * @protected\n */\n static _rs_supported (): boolean {\n return true;\n }\n\n /**\n * Remove Google Drive as a backend.\n *\n * @param {Object} remoteStorage - RemoteStorage instance\n *\n * @protected\n */\n static _rs_cleanup (remoteStorage): void {\n remoteStorage.setBackend(undefined);\n if (remoteStorage._origRemote) {\n remoteStorage.remote = remoteStorage._origRemote;\n delete remoteStorage._origRemote;\n }\n unHookGetItemURL(remoteStorage);\n }\n}\n\ninterface GoogleDrive extends EventHandling {}\napplyMixins(GoogleDrive, [EventHandling]);\n\nexport = GoogleDrive;\n","import EventHandling from './eventhandling';\nimport WireClient from './wireclient';\nimport BaseClient from './baseclient';\nimport RevisionCache from './revisioncache';\nimport SyncError from './sync-error';\nimport UnauthorizedError from './unauthorized-error';\nimport {\n applyMixins,\n cleanPath,\n isFolder,\n shouldBeTreatedAsBinary,\n getJSONFromLocalStorage,\n getTextFromArrayBuffer,\n localStorageAvailable\n} from './util';\n\n/**\n * WORK IN PROGRESS, NOT RECOMMENDED FOR PRODUCTION USE\n *\n * Dropbox backend for RemoteStorage.js\n * This file exposes a get/put/delete interface which is compatible with\n * .\n *\n * When remoteStorage.backend is set to 'dropbox', this backend will\n * initialize and replace remoteStorage.remote with remoteStorage.dropbox.\n *\n * In order to ensure compatibility with the public folder, \n * gets hijacked to return the Dropbox public share URL.\n *\n * To use this backend, you need to specify the Dropbox app key like so:\n *\n * @example\n * remoteStorage.setApiKeys({\n * dropbox: 'your-app-key'\n * });\n *\n * An app key can be obtained by registering your app at https://www.dropbox.com/developers/apps\n *\n * Known issues:\n *\n * - Storing files larger than 150MB is not yet supported\n * - Listing and deleting folders with more than 10'000 files will cause problems\n * - Content-Type is not fully supported due to limitations of the Dropbox API\n * - Dropbox preserves cases but is not case-sensitive\n * - getItemURL is asynchronous which means it returns useful values\n * after the syncCycle\n */\n\nlet hasLocalStorage;\nconst AUTH_URL = 'https://www.dropbox.com/oauth2/authorize';\nconst SETTINGS_KEY = 'remotestorage:dropbox';\nconst PATH_PREFIX = '/remotestorage';\n\n/**\n * Map a local path to a path in Dropbox.\n *\n * @param {string} path - Path\n * @returns {string} Actual path in Dropbox\n *\n * @private\n */\nfunction getDropboxPath (path: string): string {\n return cleanPath(PATH_PREFIX + '/' + path).replace(/\\/$/, '');\n}\n\nfunction compareApiError (response, expect) {\n return new RegExp('^' + expect.join('\\\\/') + '(\\\\/|$)').test(response.error_summary);\n}\n\nfunction isBinaryData (data) {\n return data instanceof ArrayBuffer || WireClient.isArrayBufferView(data);\n}\n\n/**\n * @class\n */\nclass Dropbox {\n rs: any;\n connected: boolean;\n online: boolean;\n clientId: string;\n token: string;\n userAddress: string;\n\n _initialFetchDone: boolean;\n _revCache: RevisionCache;\n _fetchDeltaCursor: any;\n _fetchDeltaPromise: any;\n _itemRefs: any;\n\n // TODO remove when refactoring eventhandling\n _emit: any;\n\n constructor (rs) {\n this.rs = rs;\n this.connected = false;\n this.online = true; // TODO implement offline detection on failed request\n this._initialFetchDone = false;\n\n this.addEvents(['connected', 'not-connected']);\n\n this.clientId = rs.apiKeys.dropbox.appKey;\n this._revCache = new RevisionCache('rev');\n this._fetchDeltaCursor = null;\n this._fetchDeltaPromise = null;\n this._itemRefs = {};\n\n hasLocalStorage = localStorageAvailable();\n\n if (hasLocalStorage){\n const settings = getJSONFromLocalStorage(SETTINGS_KEY);\n if (settings) {\n this.configure(settings);\n }\n this._itemRefs = getJSONFromLocalStorage(`${SETTINGS_KEY}:shares`) || {};\n }\n if (this.connected) {\n setTimeout(this._emit.bind(this), 0, 'connected');\n }\n }\n\n /**\n * Set the backed to 'dropbox' and start the authentication flow in order\n * to obtain an API token from Dropbox.\n */\n connect () {\n // TODO handling when token is already present\n this.rs.setBackend('dropbox');\n if (this.token){\n hookIt(this.rs);\n } else {\n this.rs.authorize({ authURL: AUTH_URL, scope: '', clientId: this.clientId });\n }\n }\n\n /**\n * Sets the connected flag\n * Accepts its parameters according to the .\n * @param {Object} settings\n * @param {string} [settings.userAddress] - The user's email address\n * @param {string} [settings.token] - Authorization token\n *\n * @protected\n **/\n configure (settings) {\n // We only update this.userAddress if settings.userAddress is set to a string or to null:\n if (typeof settings.userAddress !== 'undefined') { this.userAddress = settings.userAddress; }\n // Same for this.token. If only one of these two is set, we leave the other one at its existing value:\n if (typeof settings.token !== 'undefined') { this.token = settings.token; }\n\n const writeSettingsToCache = function() {\n if (hasLocalStorage) {\n localStorage.setItem(SETTINGS_KEY, JSON.stringify({\n userAddress: this.userAddress,\n token: this.token\n }));\n }\n };\n\n const handleError = function() {\n this.connected = false;\n if (hasLocalStorage) {\n localStorage.removeItem(SETTINGS_KEY);\n }\n };\n\n if (this.token) {\n this.connected = true;\n if (this.userAddress) {\n this._emit('connected');\n writeSettingsToCache.apply(this);\n } else {\n this.info().then(function (info){\n this.userAddress = info.email;\n this._emit('connected');\n writeSettingsToCache.apply(this);\n }.bind(this)).catch(function() {\n handleError.apply(this);\n this.rs._emit('error', new Error('Could not fetch user info.'));\n }.bind(this));\n }\n } else {\n handleError.apply(this);\n }\n }\n\n /**\n * Stop waiting for the token and emit not-connected\n *\n * @protected\n */\n stopWaitingForToken () {\n if (!this.connected) {\n this._emit('not-connected');\n }\n }\n\n /**\n * Get all items in a folder.\n *\n * @param path {string} - path of the folder to get, with leading slash\n * @return {Object}\n * statusCode - HTTP status code\n * body - array of the items found\n * contentType - 'application/json; charset=UTF-8'\n * revision - revision of the folder\n *\n * @private\n */\n _getFolder (path) {\n const url = 'https://api.dropboxapi.com/2/files/list_folder';\n const revCache = this._revCache;\n\n const processResponse = (resp) => {\n let body;\n\n if (resp.status !== 200 && resp.status !== 409) {\n return Promise.reject('Unexpected response status: ' + resp.status);\n }\n\n try {\n body = JSON.parse(resp.responseText);\n } catch (e) {\n return Promise.reject(e);\n }\n\n if (resp.status === 409) {\n if (compareApiError(body, ['path', 'not_found'])) {\n // if the folder is not found, handle it as an empty folder\n return Promise.resolve({});\n }\n\n return Promise.reject(new Error('API returned an error: ' + body.error_summary));\n }\n\n const listing = body.entries.reduce((map, item) => {\n const isDir = item['.tag'] === 'folder';\n const itemName = item.path_lower.split('/').slice(-1)[0] + (isDir ? '/' : '');\n if (isDir){\n map[itemName] = { ETag: revCache.get(path+itemName) };\n } else {\n map[itemName] = { ETag: item.rev };\n this._revCache.set(path+itemName, item.rev);\n }\n return map;\n }, {});\n\n if (body.has_more) {\n return loadNext(body.cursor).then(function (nextListing) {\n return Object.assign(listing, nextListing);\n });\n }\n\n return Promise.resolve(listing);\n };\n\n const loadNext = (cursor) => {\n const continueURL = 'https://api.dropboxapi.com/2/files/list_folder/continue';\n const params = {\n body: { cursor: cursor }\n };\n\n return this._request('POST', continueURL, params).then(processResponse);\n };\n\n return this._request('POST', url, {\n body: {\n path: getDropboxPath(path)\n }\n }).then(processResponse).then(function (listing) {\n return Promise.resolve({\n statusCode: 200,\n body: listing,\n contentType: 'application/json; charset=UTF-8',\n revision: revCache.get(path)\n });\n });\n }\n\n /**\n * Checks for the path in ``_revCache`` and decides based on that if file\n * has changed. Calls ``_getFolder`` is the path points to a folder.\n *\n * Calls ``Dropbox.share`` afterwards to fill ``_itemRefs``.\n *\n * Compatible with ``WireClient.get``\n *\n * @param path {string} - path of the folder to get, with leading slash\n * @param options {Object}\n *\n * @protected\n */\n get (path, options) {\n if (! this.connected) { return Promise.reject(\"not connected (path: \" + path + \")\"); }\n const url = 'https://content.dropboxapi.com/2/files/download';\n\n const savedRev = this._revCache.get(path);\n if (savedRev === null) {\n // file was deleted server side\n return Promise.resolve({statusCode: 404});\n }\n if (options && options.ifNoneMatch) {\n // We must wait for local revision cache to be initialized before\n // checking if local revision is outdated\n if (! this._initialFetchDone) {\n return this.fetchDelta().then(() => {\n return this.get(path, options);\n });\n }\n\n if (savedRev && (savedRev === options.ifNoneMatch)) {\n // nothing changed.\n return Promise.resolve({statusCode: 304});\n }\n }\n\n // use _getFolder for folders\n if (path.substr(-1) === '/') {\n return this._getFolder(path);\n }\n\n const params = {\n headers: {\n 'Dropbox-API-Arg': JSON.stringify({path: getDropboxPath(path)}),\n },\n responseType: 'arraybuffer'\n };\n if (options && options.ifNoneMatch) {\n params.headers['If-None-Match'] = options.ifNoneMatch;\n }\n\n return this._request('GET', url, params).then(resp => {\n const status = resp.status;\n let meta, body, mime, rev;\n if (status !== 200 && status !== 409) {\n return Promise.resolve({statusCode: status});\n }\n meta = resp.getResponseHeader('Dropbox-API-Result');\n //first encode the response as text, and later check if \n //text appears to actually be binary data\n return getTextFromArrayBuffer(resp.response, 'UTF-8').then(responseText => {\n body = responseText;\n if (status === 409) {\n meta = body;\n }\n\n try {\n meta = JSON.parse(meta);\n } catch(e) {\n return Promise.reject(e);\n }\n\n if (status === 409) {\n if (compareApiError(meta, ['path', 'not_found'])) {\n return {statusCode: 404};\n }\n return Promise.reject(new Error('API error while downloading file (\"' + path + '\"): ' + meta.error_summary));\n }\n\n mime = resp.getResponseHeader('Content-Type');\n rev = meta.rev;\n this._revCache.set(path, rev);\n this._shareIfNeeded(path);\n\n if (shouldBeTreatedAsBinary(responseText, mime)) {\n // return unprocessed response\n body = resp.response;\n } else {\n // handling json (always try)\n try {\n body = JSON.parse(body);\n mime = 'application/json; charset=UTF-8';\n } catch(e) {\n //Failed parsing Json, assume it is something else then\n }\n }\n\n return {\n statusCode: status,\n body: body,\n contentType: mime,\n revision: rev\n };\n });\n });\n }\n\n /**\n * Checks for the path in ``_revCache`` and decides based on that if file\n * has changed.\n *\n * Compatible with ``WireClient``\n *\n * Calls ``Dropbox.share`` afterwards to fill ``_itemRefs``.\n *\n * @param {string} path - path of the folder to put, with leading slash\n * @param {Object} options\n * @param {string} options.ifNoneMatch - Only create of update the file if the\n * current ETag doesn't match this string\n * @returns {Promise} Resolves with an object containing the status code,\n * content-type and revision\n * @protected\n */\n put (path, body, contentType, options) {\n if (!this.connected) {\n throw new Error(\"not connected (path: \" + path + \")\");\n }\n\n // check if file has changed and return 412\n const savedRev = this._revCache.get(path);\n if (options && options.ifMatch &&\n savedRev && (savedRev !== options.ifMatch)) {\n return Promise.resolve({statusCode: 412, revision: savedRev});\n }\n if (options && (options.ifNoneMatch === '*') &&\n savedRev && (savedRev !== 'rev')) {\n return Promise.resolve({statusCode: 412, revision: savedRev});\n }\n\n if ((!contentType.match(/charset=/)) && isBinaryData(body)) {\n contentType += '; charset=binary';\n }\n\n if (body.length > 150 * 1024 * 1024) {\n //https://www.dropbox.com/developers/core/docs#chunked-upload\n return Promise.reject(new Error(\"Cannot upload file larger than 150MB\"));\n }\n\n let result;\n const needsMetadata = options && (options.ifMatch || (options.ifNoneMatch === '*'));\n const uploadParams = {\n body: body,\n contentType: contentType,\n path: path\n };\n\n if (needsMetadata) {\n result = this._getMetadata(path).then(metadata => {\n if (options && (options.ifNoneMatch === '*') && metadata) {\n // if !!metadata === true, the file exists\n return Promise.resolve({\n statusCode: 412,\n revision: metadata.rev\n });\n }\n\n if (options && options.ifMatch && metadata && (metadata.rev !== options.ifMatch)) {\n return Promise.resolve({\n statusCode: 412,\n revision: metadata.rev\n });\n }\n\n return this._uploadSimple(uploadParams);\n });\n } else {\n result = this._uploadSimple(uploadParams);\n }\n\n return result.then(res => {\n this._shareIfNeeded(path);\n return res;\n });\n }\n\n /**\n * Checks for the path in ``_revCache`` and decides based on that if file\n * has changed.\n *\n * Compatible with ``WireClient.delete``\n *\n * Calls ``Dropbox.share`` afterwards to fill ``_itemRefs``.\n *\n * @param {string} path - path of the folder to delete, with leading slash\n * @param {Object} options\n *\n * @protected\n */\n 'delete' (path, options) {\n if (!this.connected) {\n throw new Error(\"not connected (path: \" + path + \")\");\n }\n\n // check if file has changed and return 412\n const savedRev = this._revCache.get(path);\n if (options && options.ifMatch && savedRev && (options.ifMatch !== savedRev)) {\n return Promise.resolve({ statusCode: 412, revision: savedRev });\n }\n\n if (options && options.ifMatch) {\n return this._getMetadata(path).then((metadata) => {\n if (options && options.ifMatch && metadata && (metadata.rev !== options.ifMatch)) {\n return Promise.resolve({\n statusCode: 412,\n revision: metadata.rev\n });\n }\n\n return this._deleteSimple(path);\n });\n }\n\n return this._deleteSimple(path);\n }\n\n /**\n * Calls share, if the provided path resides in a public folder.\n *\n * @private\n */\n _shareIfNeeded (path) {\n if (path.match(/^\\/public\\/.*[^/]$/) && this._itemRefs[path] === undefined) {\n this.share(path);\n }\n }\n\n /**\n * Gets a publicly-accessible URL for the path from Dropbox and stores it\n * in ``_itemRefs``.\n *\n * @return {Promise} a promise for the URL\n *\n * @private\n */\n share (path) {\n const url = 'https://api.dropboxapi.com/2/sharing/create_shared_link_with_settings';\n const options = {\n body: {path: getDropboxPath(path)}\n };\n\n return this._request('POST', url, options).then((response) => {\n if (response.status !== 200 && response.status !== 409) {\n return Promise.reject(new Error('Invalid response status:' + response.status));\n }\n\n let body;\n\n try {\n body = JSON.parse(response.responseText);\n } catch (e) {\n return Promise.reject(new Error('Invalid response body: ' + response.responseText));\n }\n\n if (response.status === 409) {\n if (compareApiError(body, ['shared_link_already_exists'])) {\n return this._getSharedLink(path);\n }\n\n return Promise.reject(new Error('API error: ' + body.error_summary));\n }\n\n return Promise.resolve(body.url);\n }).then((link) => {\n this._itemRefs[path] = link;\n\n if (hasLocalStorage) {\n localStorage.setItem(SETTINGS_KEY+':shares', JSON.stringify(this._itemRefs));\n }\n\n return Promise.resolve(link);\n }, (error) => {\n error.message = 'Sharing Dropbox file or folder (\"' + path + '\") failed: ' + error.message;\n return Promise.reject(error);\n });\n }\n\n /**\n * Fetches the user's info from dropbox and returns a promise for it.\n *\n * @return {Promise} a promise for user info object (email - the user's email address)\n *\n * @protected\n */\n info () {\n const url = 'https://api.dropboxapi.com/2/users/get_current_account';\n\n return this._request('POST', url, {}).then(function (response) {\n let info = response.responseText;\n\n try {\n info = JSON.parse(info);\n } catch (e) {\n return Promise.reject(new Error('Could not query current account info: Invalid API response: ' + info));\n }\n\n return Promise.resolve({\n email: info.email\n });\n });\n }\n\n /**\n * Make a network request.\n *\n * @param {string} method - Request method\n * @param {string} url - Target URL\n * @param {object} options - Request options\n * @returns {Promise} Resolves with the response of the network request\n *\n * @private\n */\n _request (method, url, options) {\n if (!options.headers) { options.headers = {}; }\n options.headers['Authorization'] = 'Bearer ' + this.token;\n\n if (typeof options.body === 'object' && !isBinaryData(options.body)) {\n options.body = JSON.stringify(options.body);\n options.headers['Content-Type'] = 'application/json; charset=UTF-8';\n }\n\n this.rs._emit('wire-busy', {\n method: method,\n isFolder: isFolder(url)\n });\n\n return WireClient.request.call(this, method, url, options).then(xhr => {\n // 503 means retry this later\n if (xhr && xhr.status === 503) {\n if (this.online) {\n this.online = false;\n this.rs._emit('network-offline');\n }\n return setTimeout(this._request(method, url, options), 3210);\n } else {\n if (!this.online) {\n this.online = true;\n this.rs._emit('network-online');\n }\n this.rs._emit('wire-done', {\n method: method,\n isFolder: isFolder(url),\n success: true\n });\n\n return Promise.resolve(xhr);\n }\n }, error => {\n if (this.online) {\n this.online = false;\n this.rs._emit('network-offline');\n }\n this.rs._emit('wire-done', {\n method: method,\n isFolder: isFolder(url),\n success: false\n });\n\n return Promise.reject(error);\n });\n }\n\n /**\n * Fetches the revision of all the files from dropbox API and puts them\n * into ``_revCache``. These values can then be used to determine if\n * something has changed.\n *\n * @private\n */\n fetchDelta (...args) {\n // If fetchDelta was already called, and didn't finish, return the existing\n // promise instead of calling Dropbox API again\n if (this._fetchDeltaPromise) {\n return this._fetchDeltaPromise;\n }\n\n const fetch = (cursor) => {\n let url = 'https://api.dropboxapi.com/2/files/list_folder';\n let requestBody;\n\n if (typeof cursor === 'string') {\n url += '/continue';\n requestBody = { cursor };\n } else {\n requestBody = {\n path: PATH_PREFIX,\n recursive: true,\n include_deleted: true\n };\n }\n\n return this._request('POST', url, { body: requestBody }).then(response => {\n if (response.status === 401) {\n this.rs._emit('error', new UnauthorizedError());\n return Promise.resolve(args);\n }\n\n if (response.status !== 200 && response.status !== 409) {\n return Promise.reject(new Error('Invalid response status: ' + response.status));\n }\n\n let responseBody;\n\n try {\n responseBody = JSON.parse(response.responseText);\n } catch (e) {\n return Promise.reject(new Error('Invalid response body: ' + response.responseText));\n }\n\n if (response.status === 409) {\n if (compareApiError(responseBody, ['path', 'not_found'])) {\n responseBody = {\n cursor: null,\n entries: [],\n has_more: false\n };\n } else {\n return Promise.reject(new Error('API returned an error: ' + responseBody.error_summary));\n }\n }\n\n if (!cursor) {\n //we are doing a complete fetch, so propagation would introduce unnecessary overhead\n this._revCache.deactivatePropagation();\n }\n\n responseBody.entries.forEach(entry => {\n const path = entry.path_lower.substr(PATH_PREFIX.length);\n\n if (entry['.tag'] === 'deleted') {\n // there's no way to know whether the entry was a file or a folder\n this._revCache.delete(path);\n this._revCache.delete(path + '/');\n } else if (entry['.tag'] === 'file') {\n this._revCache.set(path, entry.rev);\n }\n });\n\n this._fetchDeltaCursor = responseBody.cursor;\n if (responseBody.has_more) {\n return fetch(responseBody.cursor);\n } else {\n this._revCache.activatePropagation();\n this._initialFetchDone = true;\n }\n }).catch(error => {\n if (error === 'timeout' || error instanceof ProgressEvent) {\n // Offline is handled elsewhere already, just ignore it here\n return Promise.resolve();\n } else {\n return Promise.reject(error);\n }\n });\n };\n\n this._fetchDeltaPromise = fetch(this._fetchDeltaCursor).catch(error => {\n if (typeof(error) === 'object' && 'message' in error) {\n error.message = 'Dropbox: fetchDelta: ' + error.message;\n } else {\n error = `Dropbox: fetchDelta: ${error}`;\n }\n this._fetchDeltaPromise = null;\n return Promise.reject(error);\n }).then(() => {\n this._fetchDeltaPromise = null;\n return Promise.resolve(args);\n });\n\n return this._fetchDeltaPromise;\n }\n\n /**\n * Gets metadata for a path (can point to either a file or a folder).\n *\n * @param {string} path - the path to get metadata for\n *\n * @returns {Promise} A promise for the metadata\n *\n * @private\n */\n _getMetadata (path) {\n const url = 'https://api.dropboxapi.com/2/files/get_metadata';\n const requestBody = {\n path: getDropboxPath(path)\n };\n\n return this._request('POST', url, { body: requestBody }).then((response) => {\n if (response.status !== 200 && response.status !== 409) {\n return Promise.reject(new Error('Invalid response status:' + response.status));\n }\n\n let responseBody;\n\n try {\n responseBody = JSON.parse(response.responseText);\n } catch (e) {\n return Promise.reject(new Error('Invalid response body: ' + response.responseText));\n }\n\n if (response.status === 409) {\n if (compareApiError(responseBody, ['path', 'not_found'])) {\n return Promise.resolve();\n }\n\n return Promise.reject(new Error('API error: ' + responseBody.error_summary));\n }\n\n return Promise.resolve(responseBody);\n }).then(undefined, (error) => {\n error.message = 'Could not load metadata for file or folder (\"' + path + '\"): ' + error.message;\n return Promise.reject(error);\n });\n }\n\n /**\n * Upload a simple file (the size is no more than 150MB).\n *\n * @param {Object} params\n * @param {string} options.ifMatch - Only update the file if its ETag\n * matches this string\n * @param {string} options.path - path of the file\n * @param {string} options.body - contents of the file to upload\n * @param {string} options.contentType - mime type of the file\n *\n * @return {Promise} A promise for an object with the following structure:\n * statusCode - HTTP status code\n * revision - revision of the newly-created file, if any\n *\n * @private\n */\n _uploadSimple (params) {\n const url = 'https://content.dropboxapi.com/2/files/upload';\n const args = {\n path: getDropboxPath(params.path),\n mode: { '.tag': 'overwrite', update: undefined },\n mute: true\n };\n\n if (params.ifMatch) {\n args.mode = { '.tag': 'update', update: params.ifMatch };\n }\n\n return this._request('POST', url, {\n body: params.body,\n headers: {\n 'Content-Type': 'application/octet-stream',\n 'Dropbox-API-Arg': JSON.stringify(args)\n }\n }).then(response => {\n if (response.status !== 200 && response.status !== 409) {\n return Promise.resolve({statusCode: response.status});\n }\n\n let body = response.responseText;\n\n try {\n body = JSON.parse(body);\n } catch (e) {\n return Promise.reject(new Error('Invalid API result: ' + body));\n }\n\n if (response.status === 409) {\n if (compareApiError(body, ['path', 'conflict'])) {\n return this._getMetadata(params.path).then(function (metadata) {\n return Promise.resolve({\n statusCode: 412,\n revision: metadata.rev\n });\n });\n }\n return Promise.reject(new Error('API error: ' + body.error_summary));\n }\n\n this._revCache.set(params.path, body.rev);\n\n return Promise.resolve({ statusCode: response.status, revision: body.rev });\n });\n }\n\n /**\n * Deletes a file or a folder.\n *\n * @param {string} path - the path to delete\n *\n * @returns {Promise} A promise for an object with the following structure:\n * statusCode - HTTP status code\n *\n * @private\n */\n _deleteSimple (path) {\n const url = 'https://api.dropboxapi.com/2/files/delete';\n const requestBody = { path: getDropboxPath(path) };\n\n return this._request('POST', url, { body: requestBody }).then((response) => {\n if (response.status !== 200 && response.status !== 409) {\n return Promise.resolve({statusCode: response.status});\n }\n\n let responseBody = response.responseText;\n\n try {\n responseBody = JSON.parse(responseBody);\n } catch (e) {\n return Promise.reject(new Error('Invalid response body: ' + responseBody));\n }\n\n if (response.status === 409) {\n if (compareApiError(responseBody, ['path_lookup', 'not_found'])) {\n return Promise.resolve({statusCode: 404});\n }\n return Promise.reject(new Error('API error: ' + responseBody.error_summary));\n }\n\n return Promise.resolve({statusCode: 200});\n }).then(result => {\n if (result.statusCode === 200 || result.statusCode === 404) {\n this._revCache.delete(path);\n delete this._itemRefs[path];\n }\n return Promise.resolve(result);\n }, (error) => {\n error.message = 'Could not delete Dropbox file or folder (\"' + path + '\"): ' + error.message;\n return Promise.reject(error);\n });\n }\n\n /**\n * Requests the link for an already-shared file or folder.\n *\n * @param {string} path - path to the file or folder\n *\n * @returns {Promise} A promise for the shared link\n *\n * @private\n */\n async _getSharedLink (path: string): Promise {\n const url = 'https://api.dropbox.com/2/sharing/list_shared_links';\n const options = {\n body: {\n path: getDropboxPath(path),\n direct_only: true\n }\n };\n\n return this._request('POST', url, options).then((response) => {\n if (response.status !== 200 && response.status !== 409) {\n return Promise.reject(new Error('Invalid response status: ' + response.status));\n }\n\n let body;\n\n try {\n body = JSON.parse(response.responseText);\n } catch (e) {\n return Promise.reject(new Error('Invalid response body: ' + response.responseText));\n }\n\n if (response.status === 409) {\n return Promise.reject(new Error('API error: ' + response.error_summary));\n }\n\n if (!body.links.length) {\n return Promise.reject(new Error('No links returned'));\n }\n\n return Promise.resolve(body.links[0].url);\n }, error => {\n error.message = 'Could not get link to a shared file or folder (\"' + path + '\"): ' + error.message;\n return Promise.reject(error);\n });\n }\n\n /**\n * Initialize the Dropbox backend.\n *\n * @param {object} remoteStorage - RemoteStorage instance\n *\n * @protected\n */\n static _rs_init (rs): void {\n hasLocalStorage = localStorageAvailable();\n if ( rs.apiKeys.dropbox ) {\n rs.dropbox = new Dropbox(rs);\n }\n if (rs.backend === 'dropbox') {\n hookIt(rs);\n }\n }\n\n /**\n * Inform about the availability of the Dropbox backend.\n *\n * @param {object} rs - RemoteStorage instance\n * @returns {Boolean}\n *\n * @protected\n */\n static _rs_supported (): boolean {\n return true;\n }\n\n /**\n * Remove Dropbox as a backend.\n *\n * @param {object} remoteStorage - RemoteStorage instance\n *\n * @protected\n */\n static _rs_cleanup (rs): void {\n unHookIt(rs);\n if (hasLocalStorage){\n localStorage.removeItem(SETTINGS_KEY);\n }\n rs.setBackend(undefined);\n }\n}\n\n/**\n * Hooking the sync\n *\n * TODO: document\n */\nfunction hookSync(rs, ...args) {\n if (rs._dropboxOrigSync) { return; } // already hooked\n rs._dropboxOrigSync = rs.sync.sync.bind(rs.sync);\n rs.sync.sync = function () {\n return this.dropbox.fetchDelta(rs, ...args).\n then(rs._dropboxOrigSync, function (err) {\n rs._emit('error', new SyncError(err));\n rs._emit('sync-done');\n });\n }.bind(rs);\n}\n\n/**\n * Unhooking the sync\n *\n * TODO: document\n */\nfunction unHookSync(rs) {\n if (! rs._dropboxOrigSync) { return; } // not hooked\n rs.sync.sync = rs._dropboxOrigSync;\n delete rs._dropboxOrigSync;\n}\n\n/**\n * Hook RemoteStorage.syncCycle as it's the first function called\n * after RemoteStorage.sync is initialized, so we can then hook\n * the sync function\n * @param {object} rs RemoteStorage instance\n */\nfunction hookSyncCycle(rs, ...args) {\n if (rs._dropboxOrigSyncCycle) { return; } // already hooked\n rs._dropboxOrigSyncCycle = rs.syncCycle;\n rs.syncCycle = () => {\n if (rs.sync) {\n hookSync(rs);\n rs._dropboxOrigSyncCycle(rs, ...args);\n unHookSyncCycle(rs);\n } else {\n throw new Error('expected sync to be initialized by now');\n }\n };\n}\n\n/**\n * Restore RemoteStorage's syncCycle original implementation\n * @param {object} rs RemoteStorage instance\n */\nfunction unHookSyncCycle(rs) {\n if (!rs._dropboxOrigSyncCycle) { return; } // not hooked\n rs.syncCycle = rs._dropboxOrigSyncCycle;\n delete rs._dropboxOrigSyncCycle;\n}\n\n/**\n * Overwrite BaseClient's getItemURL with our own implementation\n *\n * TODO: getItemURL still needs to be implemented\n *\n * @param {object} rs - RemoteStorage instance\n *\n * @private\n */\nfunction hookGetItemURL (rs) {\n if (rs._origBaseClientGetItemURL) { return; }\n rs._origBaseClientGetItemURL = BaseClient.prototype.getItemURL;\n BaseClient.prototype.getItemURL = function (/*path*/) {\n throw new Error('getItemURL is not implemented for Dropbox yet');\n };\n}\n\n/**\n * Restore BaseClient's getItemURL original implementation\n *\n * @param {object} rs - RemoteStorage instance\n *\n * @private\n */\nfunction unHookGetItemURL(rs){\n if (! rs._origBaseClientGetItemURL) { return; }\n BaseClient.prototype.getItemURL = rs._origBaseClientGetItemURL;\n delete rs._origBaseClientGetItemURL;\n}\n\n/**\n * TODO: document\n */\nfunction hookRemote(rs){\n if (rs._origRemote) { return; }\n rs._origRemote = rs.remote;\n rs.remote = rs.dropbox;\n}\n\n/**\n * TODO: document\n */\nfunction unHookRemote(rs){\n if (rs._origRemote) {\n rs.remote = rs._origRemote;\n delete rs._origRemote;\n }\n}\n\n/**\n * TODO: document\n */\nfunction hookIt(rs){\n hookRemote(rs);\n if (rs.sync) {\n hookSync(rs);\n } else {\n // when sync is not available yet, we hook the syncCycle function which is called\n // right after sync is initialized\n hookSyncCycle(rs);\n }\n hookGetItemURL(rs);\n}\n\n/**\n * TODO: document\n */\nfunction unHookIt(rs){\n unHookRemote(rs);\n unHookSync(rs);\n unHookGetItemURL(rs);\n unHookSyncCycle(rs);\n}\n\ninterface Dropbox extends EventHandling {}\napplyMixins(Dropbox, [EventHandling]);\n\nexport = Dropbox;\n","'use strict';\n\nimport WebFinger from 'webfinger.js';\nimport type { StorageInfo } from './interfaces/storage_info';\nimport log from './log';\nimport { globalContext, localStorageAvailable } from './util';\n\n// feature detection flags\nlet haveXMLHttpRequest, hasLocalStorage;\n\n// used to store settings in localStorage\nconst SETTINGS_KEY = 'remotestorage:discover';\n\n// cache loaded from localStorage\n// TODO use class property\nlet cachedInfo = {};\n\n/**\n * This function deals with the Webfinger lookup, discovering a connecting\n * user's storage details.\n *\n * @param {string} userAddress - user@host or URL\n *\n * @returns {Promise} A promise for an object with the following properties.\n * href - Storage base URL,\n * storageApi - RS protocol version,\n * authUrl - OAuth URL,\n * properties - Webfinger link properties\n **/\n\nconst Discover = function Discover(userAddress: string): Promise {\n return new Promise((resolve, reject) => {\n\n if (userAddress in cachedInfo) {\n return resolve(cachedInfo[userAddress]);\n }\n\n const webFinger = new WebFinger({\n tls_only: false,\n uri_fallback: true,\n request_timeout: 5000\n });\n\n return webFinger.lookup(userAddress, function (err, response) {\n if (err) {\n return reject(err);\n } else if ((typeof response.idx.links.remotestorage !== 'object') ||\n (typeof response.idx.links.remotestorage.length !== 'number') ||\n (response.idx.links.remotestorage.length <= 0)) {\n log(\"[Discover] WebFinger record for \" + userAddress + \" does not have remotestorage defined in the links section \", JSON.stringify(response.json));\n return reject(\"WebFinger record for \" + userAddress + \" does not have remotestorage defined in the links section.\");\n }\n\n const rs = response.idx.links.remotestorage[0];\n const authURL = rs.properties['http://tools.ietf.org/html/rfc6749#section-4.2'] ||\n rs.properties['auth-endpoint'];\n const storageApi = rs.properties['http://remotestorage.io/spec/version'] ||\n rs.type;\n\n // cache fetched data\n cachedInfo[userAddress] = {\n href: rs.href,\n storageApi: storageApi,\n authURL: authURL,\n properties: rs.properties\n };\n\n if (hasLocalStorage) {\n localStorage[SETTINGS_KEY] = JSON.stringify({ cache: cachedInfo });\n }\n\n return resolve(cachedInfo[userAddress]);\n });\n });\n};\n\nDiscover.DiscoveryError = function(message) {\n this.name = 'DiscoveryError';\n this.message = message;\n this.stack = (new Error()).stack;\n};\nDiscover.DiscoveryError.prototype = Object.create(Error.prototype);\nDiscover.DiscoveryError.prototype.constructor = Discover.DiscoveryError;\n\nDiscover._rs_init = function (/*remoteStorage*/): void {\n hasLocalStorage = localStorageAvailable();\n if (hasLocalStorage) {\n try {\n const settings = JSON.parse(localStorage[SETTINGS_KEY]);\n cachedInfo = settings.cache;\n } catch(e) {\n /* empty */\n }\n }\n};\n\nDiscover._rs_supported = function (): boolean {\n haveXMLHttpRequest = Object.prototype.hasOwnProperty.call(globalContext, 'XMLHttpRequest');\n return haveXMLHttpRequest;\n};\n\nDiscover._rs_cleanup = function (): void {\n if (hasLocalStorage) {\n delete localStorage[SETTINGS_KEY];\n }\n};\n\n\nexport = Discover;\n","import EventHandling from './eventhandling';\nimport { applyMixins } from './util';\n\nclass Env {\n hiddenProperty: \"hidden\" | \"mozHidden\" | \"msHidden\" | \"webkitHidden\";\n visibilityChangeEvent: \"visibilitychange\" | \"mozvisibilitychange\" | \"msvisibilitychange\" | \"webkitvisibilitychange\";\n mode: \"browser\" | \"node\";\n\n constructor() {\n this.addEvents([\"background\", \"foreground\"]);\n\n this.mode = typeof(window) !== 'undefined' ? 'browser' : 'node';\n\n if (this.mode === 'browser') {\n this.setBrowserPrefixedNames();\n document.addEventListener(this.visibilityChangeEvent, this.setVisibility.bind(this), false);\n this.setVisibility();\n }\n }\n\n setBrowserPrefixedNames (): void {\n if (this.mode !== 'browser') { return; }\n\n if (typeof document.hidden !== \"undefined\") {\n this.hiddenProperty = \"hidden\";\n this.visibilityChangeEvent = \"visibilitychange\";\n } else if (typeof document[\"mozHidden\"] !== \"undefined\") {\n this.hiddenProperty = \"mozHidden\";\n this.visibilityChangeEvent = \"mozvisibilitychange\";\n } else if (typeof document[\"msHidden\"] !== \"undefined\") {\n this.hiddenProperty = \"msHidden\";\n this.visibilityChangeEvent = \"msvisibilitychange\";\n } else if (typeof document[\"webkitHidden\"] !== \"undefined\") {\n this.hiddenProperty = \"webkitHidden\";\n this.visibilityChangeEvent = \"webkitvisibilitychange\";\n }\n }\n\n setVisibility (): void {\n if (document[this.hiddenProperty]) {\n this.goBackground();\n } else {\n this.goForeground();\n }\n }\n\n isBrowser (): boolean {\n return this.mode === \"browser\";\n }\n\n isNode (): boolean {\n return this.mode === \"node\";\n }\n\n goBackground (): void {\n this._emit(\"background\");\n }\n\n goForeground (): void {\n this._emit(\"foreground\");\n }\n\n static _rs_init (/* remoteStorage */): void {\n return;\n }\n\n static _rs_cleanup (/* remoteStorage */): void {\n return;\n }\n}\n\ninterface Env extends EventHandling {}\napplyMixins(Env, [EventHandling]);\n\nexport = Env;\n","'use strict';\n\nimport type { StorageInfo } from './interfaces/storage_info';\nimport config from './config';\nimport log from './log';\nimport {\n applyMixins,\n getGlobalContext,\n getJSONFromLocalStorage,\n extend,\n localStorageAvailable\n} from './util';\n\nimport Access from './access';\nimport Authorize from './authorize';\nimport BaseClient from './baseclient';\nimport Caching from './caching';\nimport IndexedDB from './indexeddb';\nimport InMemoryStorage from './inmemorystorage';\nimport LocalStorage from './localstorage';\nimport EventHandling from './eventhandling';\nimport GoogleDrive from './googledrive';\nimport Dropbox from './dropbox';\nimport Discover from './discover';\nimport SyncError from './sync-error';\nimport UnauthorizedError from './unauthorized-error';\nimport Features from './features';\n\n// TODO this is assigned to RemoteStorage.util later; check if still needed\nimport * as util from './util';\n\ninterface RSModule {\n name: string;\n builder; // TODO detailed type\n}\n\nconst globalContext = getGlobalContext();\n// declare global {\n// interface Window { cordova: any };\n// }\n\nlet hasLocalStorage: boolean;\n\n// TODO document and/or refactor (seems weird)\nfunction emitUnauthorized(r) {\n if (r.statusCode === 403 || r.statusCode === 401) {\n this._emit('error', new UnauthorizedError());\n }\n return Promise.resolve(r);\n}\n\n/**\n* Check if interval is valid: numeric and between 2s and 1hr inclusive\n*/\nfunction isValidInterval(interval: unknown): interval is number {\n return (typeof interval === 'number' &&\n interval >= 2000 &&\n interval <= 3600000);\n}\n\n/**\n * Constructor for the remoteStorage object/instance\n *\n * This class primarily contains feature detection code and convenience API.\n *\n * Depending on which features are built in, it contains different attributes\n * and functions. See the individual features for more information.\n *\n * @param {object} config - an optional configuration object\n * @class\n */\nclass RemoteStorage {\n /**\n * Pending get/put/delete calls\n * @private\n */\n _pending: {[key: string]: any}[] = [];\n\n /**\n * TODO: document\n */\n _cleanups: [] = [];\n\n /**\n * TODO: document\n */\n _pathHandlers: { [key: string]: any } = { change: {} };\n\n /**\n * Holds OAuth app keys for Dropbox, Google Drive\n */\n apiKeys: object = {};\n\n /**\n * Holds the feature class instance, added by feature initialization\n * TODO use type Access\n */\n access: any;\n /**\n * Holds the feature class instance, added by feature initialization\n * TODO use type Sync\n */\n sync: any;\n /**\n * Holds the feature class instance, added by feature initialization\n */\n caching: Caching;\n\n // TODO use correct types, document\n _syncTimer: any;\n syncStopped: any;\n get: any;\n put: any;\n delete: any;\n\n backend: 'remotestorage' | 'dropbox' | 'googledrive';\n\n /**\n * Holds a WireClient instance, added by feature initialization\n * TODO use correct type\n */\n remote: any;\n\n /*\n * Access to the local caching backend used. Usually either a\n * or instance.\n *\n * Not available, when caching is turned off.\n */\n local: IndexedDB | LocalStorage | InMemoryStorage;\n\n dropbox: Dropbox;\n googledrive: GoogleDrive;\n\n fireInitial;\n\n on: any;\n\n constructor (cfg?: object) {\n // Initial configuration property settings.\n // TODO use modern JS to merge object properties\n if (typeof cfg === 'object') { extend(config, cfg); }\n\n this.addEvents([\n 'ready', 'authing', 'connecting', 'connected', 'disconnected',\n 'not-connected', 'conflict', 'error', 'features-loaded',\n 'sync-interval-change', 'sync-req-done', 'sync-done',\n 'wire-busy', 'wire-done', 'network-offline', 'network-online'\n ]);\n\n this._setGPD({\n get: this._pendingGPD('get'),\n put: this._pendingGPD('put'),\n delete: this._pendingGPD('delete')\n });\n\n hasLocalStorage = localStorageAvailable();\n\n if (hasLocalStorage) {\n this.apiKeys = getJSONFromLocalStorage('remotestorage:api-keys') || {};\n this.setBackend(localStorage.getItem('remotestorage:backend') || 'remotestorage');\n }\n\n // Keep a reference to the orginal `on` function\n const origOn = this.on;\n\n /**\n * Register an event handler. See :ref:`rs-events` for available event names.\n *\n * @param {string} eventName - Name of the event\n * @param {function} handler - Event handler\n */\n this.on = function (eventName: string, handler): void {\n if (this._allLoaded) {\n // check if the handler should be called immediately, because the\n // event has happened already\n switch(eventName) {\n case 'features-loaded':\n setTimeout(handler, 0);\n break;\n case 'ready':\n if (this.remote) {\n setTimeout(handler, 0);\n }\n break;\n case 'connected':\n if (this.remote && this.remote.connected) {\n setTimeout(handler, 0);\n }\n break;\n case 'not-connected':\n if (this.remote && !this.remote.connected) {\n setTimeout(handler, 0);\n }\n break;\n }\n }\n\n return origOn.call(this, eventName, handler);\n };\n\n // load all features and emit `ready`\n this._init();\n\n /**\n * TODO: document\n */\n this.fireInitial = function () {\n if (this.local) {\n setTimeout(this.local.fireInitial.bind(this.local), 0);\n }\n }.bind(this);\n\n this.on('ready', this.fireInitial.bind(this));\n this.loadModules();\n }\n\n /**\n * Indicating if remoteStorage is currently connected.\n */\n get connected (): boolean {\n return this.remote.connected;\n }\n\n // FIXME: Instead of doing this, would be better to only\n // export setAuthURL / getAuthURL from RemoteStorage prototype\n static Authorize = Authorize;\n\n static SyncError = SyncError;\n static Unauthorized = UnauthorizedError;\n static DiscoveryError = Discover.DiscoveryError;\n static util = util;\n\n /**\n * Load all modules passed as arguments\n * @private\n */\n loadModules(): void {\n config.modules.forEach(this.addModule.bind(this));\n }\n\n /**\n * Initiate the OAuth authorization flow.\n *\n * This function is called by custom storage backend implementations\n * (e.g. Dropbox or Google Drive).\n *\n * @param {object} options\n * @param {string} options.authURL - URL of the authorization endpoint\n * @param {string} [options.scope] - access scope\n * @param {string} [options.clientId] - client identifier (defaults to the\n * origin of the redirectUri)\n * @private\n */\n authorize (options: { authURL: string; scope?: string; clientId?: string; redirectUri?: string }): void {\n this.access.setStorageType(this.remote.storageApi);\n if (typeof options.scope === 'undefined') {\n options.scope = this.access.scopeParameter;\n }\n\n if (globalContext.cordova) {\n options.redirectUri = config.cordovaRedirectUri;\n } else {\n const location = Authorize.getLocation();\n let redirectUri = location.origin;\n if (location.pathname !== '/') {\n redirectUri += location.pathname;\n }\n\n options.redirectUri = redirectUri;\n }\n\n if (typeof options.clientId === 'undefined') {\n options.clientId = options.redirectUri.match(/^(https?:\\/\\/[^/]+)/)[0];\n }\n\n Authorize.authorize(this, options);\n }\n\n /**\n * TODO: document\n * @private\n */\n impliedauth (storageApi?: string, redirectUri?: string): void {\n // TODO shouldn't these be default argument values?\n storageApi = storageApi || this.remote.storageApi;\n redirectUri = redirectUri || String(document.location);\n\n log('ImpliedAuth proceeding due to absent authURL; storageApi = ' + storageApi + ' redirectUri = ' + redirectUri);\n // Set a fixed access token, signalling to not send it as Bearer\n this.remote.configure({\n token: Authorize.IMPLIED_FAKE_TOKEN\n });\n document.location.href = redirectUri;\n }\n\n /**\n * @property {object} remote\n *\n * Depending on the chosen backend, this is either an instance of ``WireClient``,\n * ``Dropbox`` or ``GoogleDrive``.\n *\n * @property {boolean} remote.connected - Whether or not a remote store is connected\n * @property {boolean} remote.online - Whether last sync action was successful or not\n * @property {string} remote.userAddress - The user address of the connected user\n * @property {string} remote.properties - The properties of the WebFinger link\n */\n\n /**\n * Connect to a remoteStorage server.\n *\n * Discovers the WebFinger profile of the given user address and initiates\n * the OAuth dance.\n *\n * This method must be called *after* all required access has been claimed.\n * When using the connect widget, it will call this method itself.\n *\n * Special cases:\n *\n * 1. If a bearer token is supplied as second argument, the OAuth dance\n * will be skipped and the supplied token be used instead. This is\n * useful outside of browser environments, where the token has been\n * acquired in a different way.\n *\n * 2. If the Webfinger profile for the given user address doesn't contain\n * an auth URL, the library will assume that client and server have\n * established authorization among themselves, which will omit bearer\n * tokens in all requests later on. This is useful for example when using\n * Kerberos and similar protocols.\n *\n * @param {string} userAddress - The user address (user@host) or URL to connect to.\n * @param {string} token - (optional) A bearer token acquired beforehand\n */\n connect (userAddress: string, token?: string): void {\n this.setBackend('remotestorage');\n if (userAddress.indexOf('@') < 0 && !userAddress.match(/^(https?:\\/\\/)?[^\\s\\/$\\.?#]+\\.[^\\s]*$/)) {\n this._emit('error', new RemoteStorage.DiscoveryError(\"Not a valid user address or URL.\"));\n return;\n }\n\n // Prefix URL with https:// if it's missing\n if (userAddress.indexOf('@') < 0 && !userAddress.match(/^https?:\\/\\//)) {\n userAddress = `https://${userAddress}`;\n }\n\n if (globalContext.cordova) {\n if (typeof config.cordovaRedirectUri !== 'string') {\n this._emit('error', new RemoteStorage.DiscoveryError(\"Please supply a custom HTTPS redirect URI for your Cordova app\"));\n return;\n }\n if (!globalContext.cordova.InAppBrowser) {\n this._emit('error', new RemoteStorage.DiscoveryError(\"Please include the InAppBrowser Cordova plugin to enable OAuth\"));\n return;\n }\n }\n\n this.remote.configure({\n userAddress: userAddress\n });\n this._emit('connecting');\n\n const discoveryTimeout = setTimeout((): void => {\n this._emit('error', new RemoteStorage.DiscoveryError(\"No storage information found for this user address.\"));\n }, config.discoveryTimeout);\n\n Discover(userAddress).then((info: StorageInfo): void => {\n clearTimeout(discoveryTimeout);\n this._emit('authing');\n info.userAddress = userAddress;\n this.remote.configure(info);\n if (! this.remote.connected) {\n if (info.authURL) {\n if (typeof token === 'undefined') {\n // Normal authorization step; the default way to connect\n this.authorize({ authURL: info.authURL });\n } else if (typeof token === 'string') {\n // Token supplied directly by app/developer/user\n log('Skipping authorization sequence and connecting with known token');\n this.remote.configure({ token: token });\n } else {\n throw new Error(\"Supplied bearer token must be a string\");\n }\n } else {\n // In lieu of an excplicit authURL, assume that the browser and\n // server handle any authorization needs; for instance, TLS may\n // trigger the browser to use a client certificate, or a 401 Not\n // Authorized response may make the browser send a Kerberos ticket\n // using the SPNEGO method.\n this.impliedauth();\n }\n }\n }, (/*err*/) => {\n clearTimeout(discoveryTimeout);\n this._emit('error', new RemoteStorage.DiscoveryError(\"No storage information found for this user address.\"));\n });\n }\n\n /**\n * Reconnect the remote server to get a new authorization.\n */\n reconnect (): void {\n this.remote.configure({ token: null });\n\n if (this.backend === 'remotestorage') {\n this.connect(this.remote.userAddress);\n } else {\n this.remote.connect();\n }\n }\n\n /**\n * \"Disconnect\" from remote server to terminate current session.\n *\n * This method clears all stored settings and deletes the entire local\n * cache.\n */\n disconnect (): void {\n if (this.remote) {\n this.remote.configure({\n userAddress: null,\n href: null,\n storageApi: null,\n token: null,\n properties: null\n });\n }\n this._setGPD({\n get: this._pendingGPD('get'),\n put: this._pendingGPD('put'),\n delete: this._pendingGPD('delete')\n });\n const n = this._cleanups.length;\n let i = 0;\n\n const oneDone = (): void => {\n i++;\n if (i >= n) {\n this._init();\n // FIXME Re-enable when modules are all imports\n // log('Done cleaning up, emitting disconnected and disconnect events');\n this._emit('disconnected');\n }\n };\n\n if (n > 0) {\n this._cleanups.forEach((cleanup: (thisarg: object) => Promise) => {\n const cleanupResult = cleanup(this);\n if (typeof(cleanupResult) === 'object' && typeof(cleanupResult.then) === 'function') {\n cleanupResult.then(oneDone);\n } else {\n oneDone();\n }\n });\n } else {\n oneDone();\n }\n }\n\n /**\n * TODO: document\n * @private\n */\n setBackend (what): void {\n this.backend = what;\n if (hasLocalStorage) {\n if (what) {\n localStorage.setItem('remotestorage:backend', what);\n } else {\n localStorage.removeItem('remotestorage:backend');\n }\n }\n }\n\n /**\n * Add a \"change\" event handler to the given path. Whenever a \"change\"\n * happens (as determined by the backend, such as e.g.\n * ) and the affected path is equal to or below the\n * given 'path', the given handler is called.\n *\n * You should usually not use this method directly, but instead use the\n * \"change\" events provided by :doc:`BaseClient `\n *\n * @param {string} path - Absolute path to attach handler to\n * @param {function} handler - Handler function\n */\n onChange (path: string, handler): void {\n if (! this._pathHandlers.change[path]) {\n this._pathHandlers.change[path] = [];\n }\n this._pathHandlers.change[path].push(handler);\n }\n\n /**\n * TODO: do we still need this, now that we always instantiate the prototype?\n *\n * Enable remoteStorage logging.\n */\n enableLog (): void {\n config.logging = true;\n }\n\n /**\n * TODO: do we still need this, now that we always instantiate the prototype?\n *\n * Disable remoteStorage logging\n */\n disableLog (): void {\n config.logging = false;\n }\n\n /**\n * log\n *\n * The same as .\n */\n log (...args): void {\n log.apply(RemoteStorage, args);\n }\n\n /**\n * Set the OAuth key/ID for either GoogleDrive or Dropbox backend support.\n *\n * @param {Object} apiKeys - A config object with these properties:\n * @param {string} [apiKeys.type] - Backend type: 'googledrive' or 'dropbox'\n * @param {string} [apiKeys.key] - Client ID for GoogleDrive, or app key for Dropbox\n */\n setApiKeys (apiKeys: {[key in ApiKeyType]?: string}): void | boolean {\n const validTypes: string[] = [ApiKeyType.GOOGLE, ApiKeyType.DROPBOX];\n if (typeof apiKeys !== 'object' || !Object.keys(apiKeys).every(type => validTypes.includes(type))) {\n console.error('setApiKeys() was called with invalid arguments') ;\n return false;\n }\n\n Object.keys(apiKeys).forEach(type => {\n const key = apiKeys[type];\n if (!key) { delete this.apiKeys[type]; return; }\n\n switch(type) {\n case ApiKeyType.DROPBOX:\n this.apiKeys[ApiKeyType.DROPBOX] = { appKey: key };\n if (typeof this.dropbox === 'undefined' ||\n this.dropbox.clientId !== key) {\n Dropbox._rs_init(this);\n }\n break;\n case ApiKeyType.GOOGLE:\n this.apiKeys[ApiKeyType.GOOGLE] = { clientId: key };\n if (typeof this.googledrive === 'undefined' ||\n this.googledrive.clientId !== key) {\n GoogleDrive._rs_init(this);\n }\n break;\n }\n return true;\n });\n\n if (hasLocalStorage) {\n localStorage.setItem('remotestorage:api-keys', JSON.stringify(this.apiKeys));\n }\n\n }\n\n /**\n * Set redirect URI to be used for the OAuth redirect within the\n * in-app-browser window in Cordova apps.\n *\n * @param uri - A valid HTTP(S) URI\n */\n setCordovaRedirectUri (uri: string): void {\n if (typeof uri !== 'string' || !uri.match(/http(s)?:\\/\\//)) {\n throw new Error(\"Cordova redirect URI must be a URI string\");\n }\n config.cordovaRedirectUri = uri;\n }\n\n //\n // FEATURES INITIALIZATION\n //\n\n _init = Features.loadFeatures;\n features = Features.features;\n loadFeature = Features.loadFeature;\n featureSupported = Features.featureSupported;\n featureDone = Features.featureDone;\n featuresDone = Features.featuresDone;\n featuresLoaded = Features.featuresLoaded;\n featureInitialized = Features.featureInitialized;\n featureFailed = Features.featureFailed;\n hasFeature = Features.hasFeature;\n _setCachingModule = Features._setCachingModule;\n _collectCleanupFunctions = Features._collectCleanupFunctions;\n _fireReady = Features._fireReady;\n initFeature = Features.initFeature;\n\n //\n // GET/PUT/DELETE INTERFACE HELPERS\n //\n\n /**\n * TODO: document\n * @private\n */\n _setGPD (impl, context?) {\n function wrap(func) {\n return function (...args) {\n return func.apply(context, args)\n .then(emitUnauthorized.bind(this));\n };\n }\n this.get = wrap(impl.get);\n this.put = wrap(impl.put);\n this.delete = wrap(impl.delete);\n }\n\n /**\n * TODO: document\n * @private\n */\n _pendingGPD (methodName): () => Promise {\n return (...args) => {\n const methodArguments = Array.prototype.slice.call(args);\n return new Promise((resolve, reject) => {\n this._pending.push({\n method: methodName,\n args: methodArguments,\n promise: {\n resolve: resolve,\n reject: reject\n }\n });\n });\n };\n }\n\n /**\n * TODO: document\n * @private\n */\n _processPending (): void {\n this._pending.forEach((pending) => {\n try {\n this[pending.method](...pending.args).then(pending.promise.resolve, pending.promise.reject);\n } catch(e) {\n pending.promise.reject(e);\n }\n });\n this._pending = [];\n }\n\n //\n // CHANGE EVENT HANDLING\n //\n\n /**\n * TODO: document\n * @private\n */\n _bindChange (object: { on }): void {\n object.on('change', this._dispatchEvent.bind(this, 'change'));\n }\n\n /**\n * TODO: document\n * @private\n */\n _dispatchEvent (eventName: string, event): void {\n Object.keys(this._pathHandlers[eventName]).forEach((path: string) => {\n const pl = path.length;\n if (event.path.substr(0, pl) === path) {\n this._pathHandlers[eventName][path].forEach((handler) => {\n const ev: { relativePath?: string } = {};\n for (const key in event) { ev[key] = event[key]; }\n ev.relativePath = event.path.replace(new RegExp('^' + path), '');\n try {\n handler(ev);\n } catch(e) {\n console.error(\"'change' handler failed: \", e, e.stack);\n this._emit('error', e);\n }\n });\n }\n });\n }\n\n /**\n * This method enables you to quickly instantiate a BaseClient, which you can\n * use to directly read and manipulate data in the connected storage account.\n *\n * Please use this method only for debugging and development, and choose or\n * create a :doc:`data module ` for your app to use.\n *\n * @param path - The base directory of the BaseClient that will be returned\n * (with a leading and a trailing slash)\n *\n * @returns A client with the specified scope (category/base directory)\n */\n scope (path: string): BaseClient {\n if (typeof(path) !== 'string') {\n throw 'Argument \\'path\\' of baseClient.scope must be a string';\n }\n if (!this.access.checkPathPermission(path, 'r')) {\n console.warn('WARNING: Please use remoteStorage.access.claim() to ask for access permissions first: https://remotestoragejs.readthedocs.io/en/latest/js-api/access.html#claim');\n }\n return new BaseClient(this, path);\n }\n\n /**\n * Get the value of the sync interval when application is in the foreground\n *\n * @returns {number} A number of milliseconds\n */\n getSyncInterval (): number {\n return config.syncInterval;\n }\n\n /**\n * Set the value of the sync interval when application is in the foreground\n *\n * @param interval - Sync interval in milliseconds (between 2000 and 3600000 [1 hour])\n */\n setSyncInterval (interval: number): void {\n if (!isValidInterval(interval)) {\n throw interval + \" is not a valid sync interval\";\n }\n const oldValue = config.syncInterval;\n config.syncInterval = interval;\n this._emit('sync-interval-change', {oldValue: oldValue, newValue: interval});\n }\n\n /**\n * Get the value of the sync interval when application is in the background\n *\n * @returns A number of milliseconds\n */\n getBackgroundSyncInterval (): number {\n return config.backgroundSyncInterval;\n }\n\n /**\n * Set the value of the sync interval when the application is in the\n * background\n *\n * @param interval - Sync interval in milliseconds (between 2000 and 3600000 [1 hour])\n */\n setBackgroundSyncInterval (interval: number): void {\n if (!isValidInterval(interval)) {\n throw interval + \" is not a valid sync interval\";\n }\n const oldValue = config.backgroundSyncInterval;\n config.backgroundSyncInterval = interval;\n this._emit('sync-interval-change', {oldValue: oldValue, newValue: interval});\n }\n\n /**\n * Get the value of the current sync interval. Can be background or\n * foreground, custom or default.\n *\n * @returns {number} A number of milliseconds\n */\n getCurrentSyncInterval (): number {\n return config.isBackground ? config.backgroundSyncInterval : config.syncInterval;\n }\n\n /**\n * Get the value of the current network request timeout\n *\n * @returns {number} A number of milliseconds\n */\n getRequestTimeout (): number {\n return config.requestTimeout;\n }\n\n /**\n * Set the timeout for network requests.\n *\n * @param timeout - Timeout in milliseconds\n */\n setRequestTimeout (timeout: number): void {\n if (typeof timeout !== 'number') {\n throw timeout + \" is not a valid request timeout\";\n }\n config.requestTimeout = timeout;\n }\n\n /**\n * TODO: document\n * @private\n */\n syncCycle (): void {\n if (!this.sync || this.sync.stopped) { return; }\n\n this.on('sync-done', (): void => {\n // FIXME Re-enable when modules are all imports\n // log('[Sync] Sync done. Setting timer to', this.getCurrentSyncInterval());\n if (this.sync && !this.sync.stopped) {\n if (this._syncTimer) {\n clearTimeout(this._syncTimer);\n this._syncTimer = undefined;\n }\n this._syncTimer = setTimeout(this.sync.sync.bind(this.sync), this.getCurrentSyncInterval());\n }\n });\n\n this.sync.sync();\n }\n\n /**\n * Start synchronization with remote storage, downloading and uploading any\n * changes within the cached paths.\n *\n * Please consider: local changes will attempt sync immediately, and remote\n * changes should also be synced timely when using library defaults. So\n * this is mostly useful for letting users sync manually, when pressing a\n * sync button for example. This might feel safer to them sometimes, esp.\n * when shifting between offline and online a lot.\n *\n * @returns {Promise} A Promise which resolves when the sync has finished\n */\n startSync (): Promise {\n if (!config.cache) {\n console.warn('Nothing to sync, because caching is disabled.');\n return Promise.resolve();\n }\n this.sync.stopped = false;\n this.syncStopped = false;\n return this.sync.sync();\n }\n\n /**\n * Stop the periodic synchronization.\n */\n stopSync (): void {\n clearTimeout(this._syncTimer);\n this._syncTimer = undefined;\n\n if (this.sync) {\n // FIXME Re-enable when modules are all imports\n // log('[Sync] Stopping sync');\n this.sync.stopped = true;\n } else {\n // The sync class has not been initialized yet, so we make sure it will\n // not start the syncing process as soon as it's initialized.\n // FIXME Re-enable when modules are all imports\n // log('[Sync] Will instantiate sync stopped');\n this.syncStopped = true;\n }\n }\n\n /*\n * Add remoteStorage data module\n *\n * @param {Object} module - module object needs following properies:\n * @param {string} [module.name] - Name of the module\n * @param {function} [module.builder] - Builder function defining the module\n *\n * The module builder function should return an object containing another\n * object called exports, which will be exported to this \n * instance under the module's name. So when defining a locations module,\n * like in the example below, it would be accessible via\n * `remoteStorage.locations`, which would in turn have a `features` and a\n * `collections` property.\n *\n * The function receives a private and a public client, which are both\n * instances of . In the following example, the\n * scope of privateClient is `/locations` and the scope of publicClient is\n * `/public/locations`.\n *\n * @example\n * RemoteStorage.addModule({name: 'locations', builder: function (privateClient, publicClient) {\n * return {\n * exports: {\n * features: privateClient.scope('features/').defaultType('feature'),\n * collections: privateClient.scope('collections/').defaultType('feature-collection')\n * }\n * };\n * }});\n */\n addModule (module: RSModule): void {\n const moduleName = module.name;\n const moduleBuilder = module.builder;\n\n Object.defineProperty(this, moduleName, {\n configurable: true,\n get: function () {\n const instance = this._loadModule(moduleName, moduleBuilder);\n Object.defineProperty(this, moduleName, {\n value: instance\n });\n return instance;\n }\n });\n\n if (moduleName.indexOf('-') !== -1) {\n const camelizedName = moduleName.replace(/\\-[a-z]/g, function (s) {\n return s[1].toUpperCase();\n });\n\n Object.defineProperty(this, camelizedName, {\n get: function () {\n return this[moduleName];\n }\n });\n }\n }\n\n /**\n * Load module\n * @private\n */\n _loadModule (moduleName: string, moduleBuilder): { [key: string]: unknown } {\n if (moduleBuilder) {\n const module = moduleBuilder(\n new BaseClient(this, '/' + moduleName + '/'),\n new BaseClient(this, '/public/' + moduleName + '/')\n );\n return module.exports;\n } else {\n throw \"Unknown module: \" + moduleName;\n }\n }\n}\n\n/**\n * @property access\n *\n * Tracking claimed access scopes. A instance.\n*/\nObject.defineProperty(RemoteStorage.prototype, 'access', {\n get: function() {\n const access = new Access();\n Object.defineProperty(this, 'access', {\n value: access\n });\n return access;\n },\n configurable: true\n});\n\n// TODO Clean up/harmonize how modules are loaded and/or document this architecture properly\n//\n// At this point the remoteStorage object has not been created yet.\n// Only its prototype exists so far, so we define a self-constructing\n// property on there:\n\n/**\n * Property: caching\n *\n * Caching settings. A instance.\n */\n// FIXME Was in rs_init of Caching but don't want to require RemoteStorage from there.\nObject.defineProperty(RemoteStorage.prototype, 'caching', {\n configurable: true,\n get: function () {\n const caching = new Caching();\n Object.defineProperty(this, 'caching', {\n value: caching\n });\n return caching;\n }\n});\n\ninterface RemoteStorage extends EventHandling {}\napplyMixins(RemoteStorage, [EventHandling]);\n\nenum ApiKeyType {\n GOOGLE = 'googledrive',\n DROPBOX = 'dropbox'\n}\n\nexport = RemoteStorage;\n","/*!\n * The buffer module from node.js, for the browser.\n *\n * @author Feross Aboukhadijeh \n * @license MIT\n */\n/* eslint-disable no-proto */\n\n'use strict'\n\nvar base64 = require('base64-js')\nvar ieee754 = require('ieee754')\nvar isArray = require('isarray')\n\nexports.Buffer = Buffer\nexports.SlowBuffer = SlowBuffer\nexports.INSPECT_MAX_BYTES = 50\n\n/**\n * If `Buffer.TYPED_ARRAY_SUPPORT`:\n * === true Use Uint8Array implementation (fastest)\n * === false Use Object implementation (most compatible, even IE6)\n *\n * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,\n * Opera 11.6+, iOS 4.2+.\n *\n * Due to various browser bugs, sometimes the Object implementation will be used even\n * when the browser supports typed arrays.\n *\n * Note:\n *\n * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,\n * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.\n *\n * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.\n *\n * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of\n * incorrect length in some situations.\n\n * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they\n * get the Object implementation, which is slower but behaves correctly.\n */\nBuffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined\n ? global.TYPED_ARRAY_SUPPORT\n : typedArraySupport()\n\n/*\n * Export kMaxLength after typed array support is determined.\n */\nexports.kMaxLength = kMaxLength()\n\nfunction typedArraySupport () {\n try {\n var arr = new Uint8Array(1)\n arr.__proto__ = {__proto__: Uint8Array.prototype, foo: function () { return 42 }}\n return arr.foo() === 42 && // typed array instances can be augmented\n typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`\n arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`\n } catch (e) {\n return false\n }\n}\n\nfunction kMaxLength () {\n return Buffer.TYPED_ARRAY_SUPPORT\n ? 0x7fffffff\n : 0x3fffffff\n}\n\nfunction createBuffer (that, length) {\n if (kMaxLength() < length) {\n throw new RangeError('Invalid typed array length')\n }\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n that = new Uint8Array(length)\n that.__proto__ = Buffer.prototype\n } else {\n // Fallback: Return an object instance of the Buffer class\n if (that === null) {\n that = new Buffer(length)\n }\n that.length = length\n }\n\n return that\n}\n\n/**\n * The Buffer constructor returns instances of `Uint8Array` that have their\n * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of\n * `Uint8Array`, so the returned instances will have all the node `Buffer` methods\n * and the `Uint8Array` methods. Square bracket notation works as expected -- it\n * returns a single octet.\n *\n * The `Uint8Array` prototype remains unmodified.\n */\n\nfunction Buffer (arg, encodingOrOffset, length) {\n if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) {\n return new Buffer(arg, encodingOrOffset, length)\n }\n\n // Common case.\n if (typeof arg === 'number') {\n if (typeof encodingOrOffset === 'string') {\n throw new Error(\n 'If encoding is specified then the first argument must be a string'\n )\n }\n return allocUnsafe(this, arg)\n }\n return from(this, arg, encodingOrOffset, length)\n}\n\nBuffer.poolSize = 8192 // not used by this implementation\n\n// TODO: Legacy, not needed anymore. Remove in next major version.\nBuffer._augment = function (arr) {\n arr.__proto__ = Buffer.prototype\n return arr\n}\n\nfunction from (that, value, encodingOrOffset, length) {\n if (typeof value === 'number') {\n throw new TypeError('\"value\" argument must not be a number')\n }\n\n if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) {\n return fromArrayBuffer(that, value, encodingOrOffset, length)\n }\n\n if (typeof value === 'string') {\n return fromString(that, value, encodingOrOffset)\n }\n\n return fromObject(that, value)\n}\n\n/**\n * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError\n * if value is a number.\n * Buffer.from(str[, encoding])\n * Buffer.from(array)\n * Buffer.from(buffer)\n * Buffer.from(arrayBuffer[, byteOffset[, length]])\n **/\nBuffer.from = function (value, encodingOrOffset, length) {\n return from(null, value, encodingOrOffset, length)\n}\n\nif (Buffer.TYPED_ARRAY_SUPPORT) {\n Buffer.prototype.__proto__ = Uint8Array.prototype\n Buffer.__proto__ = Uint8Array\n if (typeof Symbol !== 'undefined' && Symbol.species &&\n Buffer[Symbol.species] === Buffer) {\n // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97\n Object.defineProperty(Buffer, Symbol.species, {\n value: null,\n configurable: true\n })\n }\n}\n\nfunction assertSize (size) {\n if (typeof size !== 'number') {\n throw new TypeError('\"size\" argument must be a number')\n } else if (size < 0) {\n throw new RangeError('\"size\" argument must not be negative')\n }\n}\n\nfunction alloc (that, size, fill, encoding) {\n assertSize(size)\n if (size <= 0) {\n return createBuffer(that, size)\n }\n if (fill !== undefined) {\n // Only pay attention to encoding if it's a string. This\n // prevents accidentally sending in a number that would\n // be interpretted as a start offset.\n return typeof encoding === 'string'\n ? createBuffer(that, size).fill(fill, encoding)\n : createBuffer(that, size).fill(fill)\n }\n return createBuffer(that, size)\n}\n\n/**\n * Creates a new filled Buffer instance.\n * alloc(size[, fill[, encoding]])\n **/\nBuffer.alloc = function (size, fill, encoding) {\n return alloc(null, size, fill, encoding)\n}\n\nfunction allocUnsafe (that, size) {\n assertSize(size)\n that = createBuffer(that, size < 0 ? 0 : checked(size) | 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) {\n for (var i = 0; i < size; ++i) {\n that[i] = 0\n }\n }\n return that\n}\n\n/**\n * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance.\n * */\nBuffer.allocUnsafe = function (size) {\n return allocUnsafe(null, size)\n}\n/**\n * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance.\n */\nBuffer.allocUnsafeSlow = function (size) {\n return allocUnsafe(null, size)\n}\n\nfunction fromString (that, string, encoding) {\n if (typeof encoding !== 'string' || encoding === '') {\n encoding = 'utf8'\n }\n\n if (!Buffer.isEncoding(encoding)) {\n throw new TypeError('\"encoding\" must be a valid string encoding')\n }\n\n var length = byteLength(string, encoding) | 0\n that = createBuffer(that, length)\n\n var actual = that.write(string, encoding)\n\n if (actual !== length) {\n // Writing a hex string, for example, that contains invalid characters will\n // cause everything after the first invalid character to be ignored. (e.g.\n // 'abxxcd' will be treated as 'ab')\n that = that.slice(0, actual)\n }\n\n return that\n}\n\nfunction fromArrayLike (that, array) {\n var length = array.length < 0 ? 0 : checked(array.length) | 0\n that = createBuffer(that, length)\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\nfunction fromArrayBuffer (that, array, byteOffset, length) {\n array.byteLength // this throws if `array` is not a valid ArrayBuffer\n\n if (byteOffset < 0 || array.byteLength < byteOffset) {\n throw new RangeError('\\'offset\\' is out of bounds')\n }\n\n if (array.byteLength < byteOffset + (length || 0)) {\n throw new RangeError('\\'length\\' is out of bounds')\n }\n\n if (byteOffset === undefined && length === undefined) {\n array = new Uint8Array(array)\n } else if (length === undefined) {\n array = new Uint8Array(array, byteOffset)\n } else {\n array = new Uint8Array(array, byteOffset, length)\n }\n\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n that = array\n that.__proto__ = Buffer.prototype\n } else {\n // Fallback: Return an object instance of the Buffer class\n that = fromArrayLike(that, array)\n }\n return that\n}\n\nfunction fromObject (that, obj) {\n if (Buffer.isBuffer(obj)) {\n var len = checked(obj.length) | 0\n that = createBuffer(that, len)\n\n if (that.length === 0) {\n return that\n }\n\n obj.copy(that, 0, 0, len)\n return that\n }\n\n if (obj) {\n if ((typeof ArrayBuffer !== 'undefined' &&\n obj.buffer instanceof ArrayBuffer) || 'length' in obj) {\n if (typeof obj.length !== 'number' || isnan(obj.length)) {\n return createBuffer(that, 0)\n }\n return fromArrayLike(that, obj)\n }\n\n if (obj.type === 'Buffer' && isArray(obj.data)) {\n return fromArrayLike(that, obj.data)\n }\n }\n\n throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.')\n}\n\nfunction checked (length) {\n // Note: cannot use `length < kMaxLength()` here because that fails when\n // length is NaN (which is otherwise coerced to zero.)\n if (length >= kMaxLength()) {\n throw new RangeError('Attempt to allocate Buffer larger than maximum ' +\n 'size: 0x' + kMaxLength().toString(16) + ' bytes')\n }\n return length | 0\n}\n\nfunction SlowBuffer (length) {\n if (+length != length) { // eslint-disable-line eqeqeq\n length = 0\n }\n return Buffer.alloc(+length)\n}\n\nBuffer.isBuffer = function isBuffer (b) {\n return !!(b != null && b._isBuffer)\n}\n\nBuffer.compare = function compare (a, b) {\n if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {\n throw new TypeError('Arguments must be Buffers')\n }\n\n if (a === b) return 0\n\n var x = a.length\n var y = b.length\n\n for (var i = 0, len = Math.min(x, y); i < len; ++i) {\n if (a[i] !== b[i]) {\n x = a[i]\n y = b[i]\n break\n }\n }\n\n if (x < y) return -1\n if (y < x) return 1\n return 0\n}\n\nBuffer.isEncoding = function isEncoding (encoding) {\n switch (String(encoding).toLowerCase()) {\n case 'hex':\n case 'utf8':\n case 'utf-8':\n case 'ascii':\n case 'latin1':\n case 'binary':\n case 'base64':\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return true\n default:\n return false\n }\n}\n\nBuffer.concat = function concat (list, length) {\n if (!isArray(list)) {\n throw new TypeError('\"list\" argument must be an Array of Buffers')\n }\n\n if (list.length === 0) {\n return Buffer.alloc(0)\n }\n\n var i\n if (length === undefined) {\n length = 0\n for (i = 0; i < list.length; ++i) {\n length += list[i].length\n }\n }\n\n var buffer = Buffer.allocUnsafe(length)\n var pos = 0\n for (i = 0; i < list.length; ++i) {\n var buf = list[i]\n if (!Buffer.isBuffer(buf)) {\n throw new TypeError('\"list\" argument must be an Array of Buffers')\n }\n buf.copy(buffer, pos)\n pos += buf.length\n }\n return buffer\n}\n\nfunction byteLength (string, encoding) {\n if (Buffer.isBuffer(string)) {\n return string.length\n }\n if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' &&\n (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) {\n return string.byteLength\n }\n if (typeof string !== 'string') {\n string = '' + string\n }\n\n var len = string.length\n if (len === 0) return 0\n\n // Use a for loop to avoid recursion\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'ascii':\n case 'latin1':\n case 'binary':\n return len\n case 'utf8':\n case 'utf-8':\n case undefined:\n return utf8ToBytes(string).length\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return len * 2\n case 'hex':\n return len >>> 1\n case 'base64':\n return base64ToBytes(string).length\n default:\n if (loweredCase) return utf8ToBytes(string).length // assume utf8\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\nBuffer.byteLength = byteLength\n\nfunction slowToString (encoding, start, end) {\n var loweredCase = false\n\n // No need to verify that \"this.length <= MAX_UINT32\" since it's a read-only\n // property of a typed array.\n\n // This behaves neither like String nor Uint8Array in that we set start/end\n // to their upper/lower bounds if the value passed is out of range.\n // undefined is handled specially as per ECMA-262 6th Edition,\n // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization.\n if (start === undefined || start < 0) {\n start = 0\n }\n // Return early if start > this.length. Done here to prevent potential uint32\n // coercion fail below.\n if (start > this.length) {\n return ''\n }\n\n if (end === undefined || end > this.length) {\n end = this.length\n }\n\n if (end <= 0) {\n return ''\n }\n\n // Force coersion to uint32. This will also coerce falsey/NaN values to 0.\n end >>>= 0\n start >>>= 0\n\n if (end <= start) {\n return ''\n }\n\n if (!encoding) encoding = 'utf8'\n\n while (true) {\n switch (encoding) {\n case 'hex':\n return hexSlice(this, start, end)\n\n case 'utf8':\n case 'utf-8':\n return utf8Slice(this, start, end)\n\n case 'ascii':\n return asciiSlice(this, start, end)\n\n case 'latin1':\n case 'binary':\n return latin1Slice(this, start, end)\n\n case 'base64':\n return base64Slice(this, start, end)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return utf16leSlice(this, start, end)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = (encoding + '').toLowerCase()\n loweredCase = true\n }\n }\n}\n\n// The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect\n// Buffer instances.\nBuffer.prototype._isBuffer = true\n\nfunction swap (b, n, m) {\n var i = b[n]\n b[n] = b[m]\n b[m] = i\n}\n\nBuffer.prototype.swap16 = function swap16 () {\n var len = this.length\n if (len % 2 !== 0) {\n throw new RangeError('Buffer size must be a multiple of 16-bits')\n }\n for (var i = 0; i < len; i += 2) {\n swap(this, i, i + 1)\n }\n return this\n}\n\nBuffer.prototype.swap32 = function swap32 () {\n var len = this.length\n if (len % 4 !== 0) {\n throw new RangeError('Buffer size must be a multiple of 32-bits')\n }\n for (var i = 0; i < len; i += 4) {\n swap(this, i, i + 3)\n swap(this, i + 1, i + 2)\n }\n return this\n}\n\nBuffer.prototype.swap64 = function swap64 () {\n var len = this.length\n if (len % 8 !== 0) {\n throw new RangeError('Buffer size must be a multiple of 64-bits')\n }\n for (var i = 0; i < len; i += 8) {\n swap(this, i, i + 7)\n swap(this, i + 1, i + 6)\n swap(this, i + 2, i + 5)\n swap(this, i + 3, i + 4)\n }\n return this\n}\n\nBuffer.prototype.toString = function toString () {\n var length = this.length | 0\n if (length === 0) return ''\n if (arguments.length === 0) return utf8Slice(this, 0, length)\n return slowToString.apply(this, arguments)\n}\n\nBuffer.prototype.equals = function equals (b) {\n if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')\n if (this === b) return true\n return Buffer.compare(this, b) === 0\n}\n\nBuffer.prototype.inspect = function inspect () {\n var str = ''\n var max = exports.INSPECT_MAX_BYTES\n if (this.length > 0) {\n str = this.toString('hex', 0, max).match(/.{2}/g).join(' ')\n if (this.length > max) str += ' ... '\n }\n return ''\n}\n\nBuffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) {\n if (!Buffer.isBuffer(target)) {\n throw new TypeError('Argument must be a Buffer')\n }\n\n if (start === undefined) {\n start = 0\n }\n if (end === undefined) {\n end = target ? target.length : 0\n }\n if (thisStart === undefined) {\n thisStart = 0\n }\n if (thisEnd === undefined) {\n thisEnd = this.length\n }\n\n if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) {\n throw new RangeError('out of range index')\n }\n\n if (thisStart >= thisEnd && start >= end) {\n return 0\n }\n if (thisStart >= thisEnd) {\n return -1\n }\n if (start >= end) {\n return 1\n }\n\n start >>>= 0\n end >>>= 0\n thisStart >>>= 0\n thisEnd >>>= 0\n\n if (this === target) return 0\n\n var x = thisEnd - thisStart\n var y = end - start\n var len = Math.min(x, y)\n\n var thisCopy = this.slice(thisStart, thisEnd)\n var targetCopy = target.slice(start, end)\n\n for (var i = 0; i < len; ++i) {\n if (thisCopy[i] !== targetCopy[i]) {\n x = thisCopy[i]\n y = targetCopy[i]\n break\n }\n }\n\n if (x < y) return -1\n if (y < x) return 1\n return 0\n}\n\n// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`,\n// OR the last index of `val` in `buffer` at offset <= `byteOffset`.\n//\n// Arguments:\n// - buffer - a Buffer to search\n// - val - a string, Buffer, or number\n// - byteOffset - an index into `buffer`; will be clamped to an int32\n// - encoding - an optional encoding, relevant is val is a string\n// - dir - true for indexOf, false for lastIndexOf\nfunction bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) {\n // Empty buffer means no match\n if (buffer.length === 0) return -1\n\n // Normalize byteOffset\n if (typeof byteOffset === 'string') {\n encoding = byteOffset\n byteOffset = 0\n } else if (byteOffset > 0x7fffffff) {\n byteOffset = 0x7fffffff\n } else if (byteOffset < -0x80000000) {\n byteOffset = -0x80000000\n }\n byteOffset = +byteOffset // Coerce to Number.\n if (isNaN(byteOffset)) {\n // byteOffset: it it's undefined, null, NaN, \"foo\", etc, search whole buffer\n byteOffset = dir ? 0 : (buffer.length - 1)\n }\n\n // Normalize byteOffset: negative offsets start from the end of the buffer\n if (byteOffset < 0) byteOffset = buffer.length + byteOffset\n if (byteOffset >= buffer.length) {\n if (dir) return -1\n else byteOffset = buffer.length - 1\n } else if (byteOffset < 0) {\n if (dir) byteOffset = 0\n else return -1\n }\n\n // Normalize val\n if (typeof val === 'string') {\n val = Buffer.from(val, encoding)\n }\n\n // Finally, search either indexOf (if dir is true) or lastIndexOf\n if (Buffer.isBuffer(val)) {\n // Special case: looking for empty string/buffer always fails\n if (val.length === 0) {\n return -1\n }\n return arrayIndexOf(buffer, val, byteOffset, encoding, dir)\n } else if (typeof val === 'number') {\n val = val & 0xFF // Search for a byte value [0-255]\n if (Buffer.TYPED_ARRAY_SUPPORT &&\n typeof Uint8Array.prototype.indexOf === 'function') {\n if (dir) {\n return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset)\n } else {\n return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset)\n }\n }\n return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir)\n }\n\n throw new TypeError('val must be string, number or Buffer')\n}\n\nfunction arrayIndexOf (arr, val, byteOffset, encoding, dir) {\n var indexSize = 1\n var arrLength = arr.length\n var valLength = val.length\n\n if (encoding !== undefined) {\n encoding = String(encoding).toLowerCase()\n if (encoding === 'ucs2' || encoding === 'ucs-2' ||\n encoding === 'utf16le' || encoding === 'utf-16le') {\n if (arr.length < 2 || val.length < 2) {\n return -1\n }\n indexSize = 2\n arrLength /= 2\n valLength /= 2\n byteOffset /= 2\n }\n }\n\n function read (buf, i) {\n if (indexSize === 1) {\n return buf[i]\n } else {\n return buf.readUInt16BE(i * indexSize)\n }\n }\n\n var i\n if (dir) {\n var foundIndex = -1\n for (i = byteOffset; i < arrLength; i++) {\n if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {\n if (foundIndex === -1) foundIndex = i\n if (i - foundIndex + 1 === valLength) return foundIndex * indexSize\n } else {\n if (foundIndex !== -1) i -= i - foundIndex\n foundIndex = -1\n }\n }\n } else {\n if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength\n for (i = byteOffset; i >= 0; i--) {\n var found = true\n for (var j = 0; j < valLength; j++) {\n if (read(arr, i + j) !== read(val, j)) {\n found = false\n break\n }\n }\n if (found) return i\n }\n }\n\n return -1\n}\n\nBuffer.prototype.includes = function includes (val, byteOffset, encoding) {\n return this.indexOf(val, byteOffset, encoding) !== -1\n}\n\nBuffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) {\n return bidirectionalIndexOf(this, val, byteOffset, encoding, true)\n}\n\nBuffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) {\n return bidirectionalIndexOf(this, val, byteOffset, encoding, false)\n}\n\nfunction hexWrite (buf, string, offset, length) {\n offset = Number(offset) || 0\n var remaining = buf.length - offset\n if (!length) {\n length = remaining\n } else {\n length = Number(length)\n if (length > remaining) {\n length = remaining\n }\n }\n\n // must be an even number of digits\n var strLen = string.length\n if (strLen % 2 !== 0) throw new TypeError('Invalid hex string')\n\n if (length > strLen / 2) {\n length = strLen / 2\n }\n for (var i = 0; i < length; ++i) {\n var parsed = parseInt(string.substr(i * 2, 2), 16)\n if (isNaN(parsed)) return i\n buf[offset + i] = parsed\n }\n return i\n}\n\nfunction utf8Write (buf, string, offset, length) {\n return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nfunction asciiWrite (buf, string, offset, length) {\n return blitBuffer(asciiToBytes(string), buf, offset, length)\n}\n\nfunction latin1Write (buf, string, offset, length) {\n return asciiWrite(buf, string, offset, length)\n}\n\nfunction base64Write (buf, string, offset, length) {\n return blitBuffer(base64ToBytes(string), buf, offset, length)\n}\n\nfunction ucs2Write (buf, string, offset, length) {\n return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nBuffer.prototype.write = function write (string, offset, length, encoding) {\n // Buffer#write(string)\n if (offset === undefined) {\n encoding = 'utf8'\n length = this.length\n offset = 0\n // Buffer#write(string, encoding)\n } else if (length === undefined && typeof offset === 'string') {\n encoding = offset\n length = this.length\n offset = 0\n // Buffer#write(string, offset[, length][, encoding])\n } else if (isFinite(offset)) {\n offset = offset | 0\n if (isFinite(length)) {\n length = length | 0\n if (encoding === undefined) encoding = 'utf8'\n } else {\n encoding = length\n length = undefined\n }\n // legacy write(string, encoding, offset, length) - remove in v0.13\n } else {\n throw new Error(\n 'Buffer.write(string, encoding, offset[, length]) is no longer supported'\n )\n }\n\n var remaining = this.length - offset\n if (length === undefined || length > remaining) length = remaining\n\n if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {\n throw new RangeError('Attempt to write outside buffer bounds')\n }\n\n if (!encoding) encoding = 'utf8'\n\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'hex':\n return hexWrite(this, string, offset, length)\n\n case 'utf8':\n case 'utf-8':\n return utf8Write(this, string, offset, length)\n\n case 'ascii':\n return asciiWrite(this, string, offset, length)\n\n case 'latin1':\n case 'binary':\n return latin1Write(this, string, offset, length)\n\n case 'base64':\n // Warning: maxLength not taken into account in base64Write\n return base64Write(this, string, offset, length)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return ucs2Write(this, string, offset, length)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\n\nBuffer.prototype.toJSON = function toJSON () {\n return {\n type: 'Buffer',\n data: Array.prototype.slice.call(this._arr || this, 0)\n }\n}\n\nfunction base64Slice (buf, start, end) {\n if (start === 0 && end === buf.length) {\n return base64.fromByteArray(buf)\n } else {\n return base64.fromByteArray(buf.slice(start, end))\n }\n}\n\nfunction utf8Slice (buf, start, end) {\n end = Math.min(buf.length, end)\n var res = []\n\n var i = start\n while (i < end) {\n var firstByte = buf[i]\n var codePoint = null\n var bytesPerSequence = (firstByte > 0xEF) ? 4\n : (firstByte > 0xDF) ? 3\n : (firstByte > 0xBF) ? 2\n : 1\n\n if (i + bytesPerSequence <= end) {\n var secondByte, thirdByte, fourthByte, tempCodePoint\n\n switch (bytesPerSequence) {\n case 1:\n if (firstByte < 0x80) {\n codePoint = firstByte\n }\n break\n case 2:\n secondByte = buf[i + 1]\n if ((secondByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)\n if (tempCodePoint > 0x7F) {\n codePoint = tempCodePoint\n }\n }\n break\n case 3:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)\n if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {\n codePoint = tempCodePoint\n }\n }\n break\n case 4:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n fourthByte = buf[i + 3]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)\n if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {\n codePoint = tempCodePoint\n }\n }\n }\n }\n\n if (codePoint === null) {\n // we did not generate a valid codePoint so insert a\n // replacement char (U+FFFD) and advance only 1 byte\n codePoint = 0xFFFD\n bytesPerSequence = 1\n } else if (codePoint > 0xFFFF) {\n // encode to utf16 (surrogate pair dance)\n codePoint -= 0x10000\n res.push(codePoint >>> 10 & 0x3FF | 0xD800)\n codePoint = 0xDC00 | codePoint & 0x3FF\n }\n\n res.push(codePoint)\n i += bytesPerSequence\n }\n\n return decodeCodePointsArray(res)\n}\n\n// Based on http://stackoverflow.com/a/22747272/680742, the browser with\n// the lowest limit is Chrome, with 0x10000 args.\n// We go 1 magnitude less, for safety\nvar MAX_ARGUMENTS_LENGTH = 0x1000\n\nfunction decodeCodePointsArray (codePoints) {\n var len = codePoints.length\n if (len <= MAX_ARGUMENTS_LENGTH) {\n return String.fromCharCode.apply(String, codePoints) // avoid extra slice()\n }\n\n // Decode in chunks to avoid \"call stack size exceeded\".\n var res = ''\n var i = 0\n while (i < len) {\n res += String.fromCharCode.apply(\n String,\n codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)\n )\n }\n return res\n}\n\nfunction asciiSlice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; ++i) {\n ret += String.fromCharCode(buf[i] & 0x7F)\n }\n return ret\n}\n\nfunction latin1Slice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; ++i) {\n ret += String.fromCharCode(buf[i])\n }\n return ret\n}\n\nfunction hexSlice (buf, start, end) {\n var len = buf.length\n\n if (!start || start < 0) start = 0\n if (!end || end < 0 || end > len) end = len\n\n var out = ''\n for (var i = start; i < end; ++i) {\n out += toHex(buf[i])\n }\n return out\n}\n\nfunction utf16leSlice (buf, start, end) {\n var bytes = buf.slice(start, end)\n var res = ''\n for (var i = 0; i < bytes.length; i += 2) {\n res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256)\n }\n return res\n}\n\nBuffer.prototype.slice = function slice (start, end) {\n var len = this.length\n start = ~~start\n end = end === undefined ? len : ~~end\n\n if (start < 0) {\n start += len\n if (start < 0) start = 0\n } else if (start > len) {\n start = len\n }\n\n if (end < 0) {\n end += len\n if (end < 0) end = 0\n } else if (end > len) {\n end = len\n }\n\n if (end < start) end = start\n\n var newBuf\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n newBuf = this.subarray(start, end)\n newBuf.__proto__ = Buffer.prototype\n } else {\n var sliceLen = end - start\n newBuf = new Buffer(sliceLen, undefined)\n for (var i = 0; i < sliceLen; ++i) {\n newBuf[i] = this[i + start]\n }\n }\n\n return newBuf\n}\n\n/*\n * Need to make sure that buffer isn't trying to write out of bounds.\n */\nfunction checkOffset (offset, ext, length) {\n if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')\n if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')\n}\n\nBuffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n checkOffset(offset, byteLength, this.length)\n }\n\n var val = this[offset + --byteLength]\n var mul = 1\n while (byteLength > 0 && (mul *= 0x100)) {\n val += this[offset + --byteLength] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n return this[offset]\n}\n\nBuffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return this[offset] | (this[offset + 1] << 8)\n}\n\nBuffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return (this[offset] << 8) | this[offset + 1]\n}\n\nBuffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return ((this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16)) +\n (this[offset + 3] * 0x1000000)\n}\n\nBuffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] * 0x1000000) +\n ((this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n this[offset + 3])\n}\n\nBuffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var i = byteLength\n var mul = 1\n var val = this[offset + --i]\n while (i > 0 && (mul *= 0x100)) {\n val += this[offset + --i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readInt8 = function readInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n if (!(this[offset] & 0x80)) return (this[offset])\n return ((0xff - this[offset] + 1) * -1)\n}\n\nBuffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset] | (this[offset + 1] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset + 1] | (this[offset] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16) |\n (this[offset + 3] << 24)\n}\n\nBuffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] << 24) |\n (this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n (this[offset + 3])\n}\n\nBuffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, true, 23, 4)\n}\n\nBuffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, false, 23, 4)\n}\n\nBuffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, true, 52, 8)\n}\n\nBuffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, false, 52, 8)\n}\n\nfunction checkInt (buf, value, offset, ext, max, min) {\n if (!Buffer.isBuffer(buf)) throw new TypeError('\"buffer\" argument must be a Buffer instance')\n if (value > max || value < min) throw new RangeError('\"value\" argument is out of bounds')\n if (offset + ext > buf.length) throw new RangeError('Index out of range')\n}\n\nBuffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n var maxBytes = Math.pow(2, 8 * byteLength) - 1\n checkInt(this, value, offset, byteLength, maxBytes, 0)\n }\n\n var mul = 1\n var i = 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n var maxBytes = Math.pow(2, 8 * byteLength) - 1\n checkInt(this, value, offset, byteLength, maxBytes, 0)\n }\n\n var i = byteLength - 1\n var mul = 1\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nfunction objectWriteUInt16 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) {\n buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>\n (littleEndian ? i : 1 - i) * 8\n }\n}\n\nBuffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nfunction objectWriteUInt32 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffffffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) {\n buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff\n }\n}\n\nBuffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset + 3] = (value >>> 24)\n this[offset + 2] = (value >>> 16)\n this[offset + 1] = (value >>> 8)\n this[offset] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = 0\n var mul = 1\n var sub = 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) {\n sub = 1\n }\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = byteLength - 1\n var mul = 1\n var sub = 0\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) {\n sub = 1\n }\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n if (value < 0) value = 0xff + value + 1\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nBuffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n this[offset + 2] = (value >>> 16)\n this[offset + 3] = (value >>> 24)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (value < 0) value = 0xffffffff + value + 1\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nfunction checkIEEE754 (buf, value, offset, ext, max, min) {\n if (offset + ext > buf.length) throw new RangeError('Index out of range')\n if (offset < 0) throw new RangeError('Index out of range')\n}\n\nfunction writeFloat (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)\n }\n ieee754.write(buf, value, offset, littleEndian, 23, 4)\n return offset + 4\n}\n\nBuffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {\n return writeFloat(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {\n return writeFloat(this, value, offset, false, noAssert)\n}\n\nfunction writeDouble (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)\n }\n ieee754.write(buf, value, offset, littleEndian, 52, 8)\n return offset + 8\n}\n\nBuffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {\n return writeDouble(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {\n return writeDouble(this, value, offset, false, noAssert)\n}\n\n// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)\nBuffer.prototype.copy = function copy (target, targetStart, start, end) {\n if (!start) start = 0\n if (!end && end !== 0) end = this.length\n if (targetStart >= target.length) targetStart = target.length\n if (!targetStart) targetStart = 0\n if (end > 0 && end < start) end = start\n\n // Copy 0 bytes; we're done\n if (end === start) return 0\n if (target.length === 0 || this.length === 0) return 0\n\n // Fatal error conditions\n if (targetStart < 0) {\n throw new RangeError('targetStart out of bounds')\n }\n if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds')\n if (end < 0) throw new RangeError('sourceEnd out of bounds')\n\n // Are we oob?\n if (end > this.length) end = this.length\n if (target.length - targetStart < end - start) {\n end = target.length - targetStart + start\n }\n\n var len = end - start\n var i\n\n if (this === target && start < targetStart && targetStart < end) {\n // descending copy from end\n for (i = len - 1; i >= 0; --i) {\n target[i + targetStart] = this[i + start]\n }\n } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {\n // ascending copy from start\n for (i = 0; i < len; ++i) {\n target[i + targetStart] = this[i + start]\n }\n } else {\n Uint8Array.prototype.set.call(\n target,\n this.subarray(start, start + len),\n targetStart\n )\n }\n\n return len\n}\n\n// Usage:\n// buffer.fill(number[, offset[, end]])\n// buffer.fill(buffer[, offset[, end]])\n// buffer.fill(string[, offset[, end]][, encoding])\nBuffer.prototype.fill = function fill (val, start, end, encoding) {\n // Handle string cases:\n if (typeof val === 'string') {\n if (typeof start === 'string') {\n encoding = start\n start = 0\n end = this.length\n } else if (typeof end === 'string') {\n encoding = end\n end = this.length\n }\n if (val.length === 1) {\n var code = val.charCodeAt(0)\n if (code < 256) {\n val = code\n }\n }\n if (encoding !== undefined && typeof encoding !== 'string') {\n throw new TypeError('encoding must be a string')\n }\n if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) {\n throw new TypeError('Unknown encoding: ' + encoding)\n }\n } else if (typeof val === 'number') {\n val = val & 255\n }\n\n // Invalid ranges are not set to a default, so can range check early.\n if (start < 0 || this.length < start || this.length < end) {\n throw new RangeError('Out of range index')\n }\n\n if (end <= start) {\n return this\n }\n\n start = start >>> 0\n end = end === undefined ? this.length : end >>> 0\n\n if (!val) val = 0\n\n var i\n if (typeof val === 'number') {\n for (i = start; i < end; ++i) {\n this[i] = val\n }\n } else {\n var bytes = Buffer.isBuffer(val)\n ? val\n : utf8ToBytes(new Buffer(val, encoding).toString())\n var len = bytes.length\n for (i = 0; i < end - start; ++i) {\n this[i + start] = bytes[i % len]\n }\n }\n\n return this\n}\n\n// HELPER FUNCTIONS\n// ================\n\nvar INVALID_BASE64_RE = /[^+\\/0-9A-Za-z-_]/g\n\nfunction base64clean (str) {\n // Node strips out invalid characters like \\n and \\t from the string, base64-js does not\n str = stringtrim(str).replace(INVALID_BASE64_RE, '')\n // Node converts strings with length < 2 to ''\n if (str.length < 2) return ''\n // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not\n while (str.length % 4 !== 0) {\n str = str + '='\n }\n return str\n}\n\nfunction stringtrim (str) {\n if (str.trim) return str.trim()\n return str.replace(/^\\s+|\\s+$/g, '')\n}\n\nfunction toHex (n) {\n if (n < 16) return '0' + n.toString(16)\n return n.toString(16)\n}\n\nfunction utf8ToBytes (string, units) {\n units = units || Infinity\n var codePoint\n var length = string.length\n var leadSurrogate = null\n var bytes = []\n\n for (var i = 0; i < length; ++i) {\n codePoint = string.charCodeAt(i)\n\n // is surrogate component\n if (codePoint > 0xD7FF && codePoint < 0xE000) {\n // last char was a lead\n if (!leadSurrogate) {\n // no lead yet\n if (codePoint > 0xDBFF) {\n // unexpected trail\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n } else if (i + 1 === length) {\n // unpaired lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n }\n\n // valid lead\n leadSurrogate = codePoint\n\n continue\n }\n\n // 2 leads in a row\n if (codePoint < 0xDC00) {\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n leadSurrogate = codePoint\n continue\n }\n\n // valid surrogate pair\n codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000\n } else if (leadSurrogate) {\n // valid bmp char, but last char was a lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n }\n\n leadSurrogate = null\n\n // encode utf8\n if (codePoint < 0x80) {\n if ((units -= 1) < 0) break\n bytes.push(codePoint)\n } else if (codePoint < 0x800) {\n if ((units -= 2) < 0) break\n bytes.push(\n codePoint >> 0x6 | 0xC0,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x10000) {\n if ((units -= 3) < 0) break\n bytes.push(\n codePoint >> 0xC | 0xE0,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x110000) {\n if ((units -= 4) < 0) break\n bytes.push(\n codePoint >> 0x12 | 0xF0,\n codePoint >> 0xC & 0x3F | 0x80,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else {\n throw new Error('Invalid code point')\n }\n }\n\n return bytes\n}\n\nfunction asciiToBytes (str) {\n var byteArray = []\n for (var i = 0; i < str.length; ++i) {\n // Node's code seems to be doing this and not & 0x7F..\n byteArray.push(str.charCodeAt(i) & 0xFF)\n }\n return byteArray\n}\n\nfunction utf16leToBytes (str, units) {\n var c, hi, lo\n var byteArray = []\n for (var i = 0; i < str.length; ++i) {\n if ((units -= 2) < 0) break\n\n c = str.charCodeAt(i)\n hi = c >> 8\n lo = c % 256\n byteArray.push(lo)\n byteArray.push(hi)\n }\n\n return byteArray\n}\n\nfunction base64ToBytes (str) {\n return base64.toByteArray(base64clean(str))\n}\n\nfunction blitBuffer (src, dst, offset, length) {\n for (var i = 0; i < length; ++i) {\n if ((i + offset >= dst.length) || (i >= src.length)) break\n dst[i + offset] = src[i]\n }\n return i\n}\n\nfunction isnan (val) {\n return val !== val // eslint-disable-line no-self-compare\n}\n","'use strict'\n\nexports.byteLength = byteLength\nexports.toByteArray = toByteArray\nexports.fromByteArray = fromByteArray\n\nvar lookup = []\nvar revLookup = []\nvar Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array\n\nvar code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'\nfor (var i = 0, len = code.length; i < len; ++i) {\n lookup[i] = code[i]\n revLookup[code.charCodeAt(i)] = i\n}\n\n// Support decoding URL-safe base64 strings, as Node.js does.\n// See: https://en.wikipedia.org/wiki/Base64#URL_applications\nrevLookup['-'.charCodeAt(0)] = 62\nrevLookup['_'.charCodeAt(0)] = 63\n\nfunction getLens (b64) {\n var len = b64.length\n\n if (len % 4 > 0) {\n throw new Error('Invalid string. Length must be a multiple of 4')\n }\n\n // Trim off extra bytes after placeholder bytes are found\n // See: https://github.com/beatgammit/base64-js/issues/42\n var validLen = b64.indexOf('=')\n if (validLen === -1) validLen = len\n\n var placeHoldersLen = validLen === len\n ? 0\n : 4 - (validLen % 4)\n\n return [validLen, placeHoldersLen]\n}\n\n// base64 is 4/3 + up to two characters of the original data\nfunction byteLength (b64) {\n var lens = getLens(b64)\n var validLen = lens[0]\n var placeHoldersLen = lens[1]\n return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen\n}\n\nfunction _byteLength (b64, validLen, placeHoldersLen) {\n return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen\n}\n\nfunction toByteArray (b64) {\n var tmp\n var lens = getLens(b64)\n var validLen = lens[0]\n var placeHoldersLen = lens[1]\n\n var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen))\n\n var curByte = 0\n\n // if there are placeholders, only get up to the last complete 4 chars\n var len = placeHoldersLen > 0\n ? validLen - 4\n : validLen\n\n var i\n for (i = 0; i < len; i += 4) {\n tmp =\n (revLookup[b64.charCodeAt(i)] << 18) |\n (revLookup[b64.charCodeAt(i + 1)] << 12) |\n (revLookup[b64.charCodeAt(i + 2)] << 6) |\n revLookup[b64.charCodeAt(i + 3)]\n arr[curByte++] = (tmp >> 16) & 0xFF\n arr[curByte++] = (tmp >> 8) & 0xFF\n arr[curByte++] = tmp & 0xFF\n }\n\n if (placeHoldersLen === 2) {\n tmp =\n (revLookup[b64.charCodeAt(i)] << 2) |\n (revLookup[b64.charCodeAt(i + 1)] >> 4)\n arr[curByte++] = tmp & 0xFF\n }\n\n if (placeHoldersLen === 1) {\n tmp =\n (revLookup[b64.charCodeAt(i)] << 10) |\n (revLookup[b64.charCodeAt(i + 1)] << 4) |\n (revLookup[b64.charCodeAt(i + 2)] >> 2)\n arr[curByte++] = (tmp >> 8) & 0xFF\n arr[curByte++] = tmp & 0xFF\n }\n\n return arr\n}\n\nfunction tripletToBase64 (num) {\n return lookup[num >> 18 & 0x3F] +\n lookup[num >> 12 & 0x3F] +\n lookup[num >> 6 & 0x3F] +\n lookup[num & 0x3F]\n}\n\nfunction encodeChunk (uint8, start, end) {\n var tmp\n var output = []\n for (var i = start; i < end; i += 3) {\n tmp =\n ((uint8[i] << 16) & 0xFF0000) +\n ((uint8[i + 1] << 8) & 0xFF00) +\n (uint8[i + 2] & 0xFF)\n output.push(tripletToBase64(tmp))\n }\n return output.join('')\n}\n\nfunction fromByteArray (uint8) {\n var tmp\n var len = uint8.length\n var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes\n var parts = []\n var maxChunkLength = 16383 // must be multiple of 3\n\n // go through the array every three bytes, we'll deal with trailing stuff later\n for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {\n parts.push(encodeChunk(\n uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)\n ))\n }\n\n // pad the end with zeros, but make sure to not forget the extra bytes\n if (extraBytes === 1) {\n tmp = uint8[len - 1]\n parts.push(\n lookup[tmp >> 2] +\n lookup[(tmp << 4) & 0x3F] +\n '=='\n )\n } else if (extraBytes === 2) {\n tmp = (uint8[len - 2] << 8) + uint8[len - 1]\n parts.push(\n lookup[tmp >> 10] +\n lookup[(tmp >> 4) & 0x3F] +\n lookup[(tmp << 2) & 0x3F] +\n '='\n )\n }\n\n return parts.join('')\n}\n","exports.read = function (buffer, offset, isLE, mLen, nBytes) {\n var e, m\n var eLen = (nBytes * 8) - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var nBits = -7\n var i = isLE ? (nBytes - 1) : 0\n var d = isLE ? -1 : 1\n var s = buffer[offset + i]\n\n i += d\n\n e = s & ((1 << (-nBits)) - 1)\n s >>= (-nBits)\n nBits += eLen\n for (; nBits > 0; e = (e * 256) + buffer[offset + i], i += d, nBits -= 8) {}\n\n m = e & ((1 << (-nBits)) - 1)\n e >>= (-nBits)\n nBits += mLen\n for (; nBits > 0; m = (m * 256) + buffer[offset + i], i += d, nBits -= 8) {}\n\n if (e === 0) {\n e = 1 - eBias\n } else if (e === eMax) {\n return m ? NaN : ((s ? -1 : 1) * Infinity)\n } else {\n m = m + Math.pow(2, mLen)\n e = e - eBias\n }\n return (s ? -1 : 1) * m * Math.pow(2, e - mLen)\n}\n\nexports.write = function (buffer, value, offset, isLE, mLen, nBytes) {\n var e, m, c\n var eLen = (nBytes * 8) - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)\n var i = isLE ? 0 : (nBytes - 1)\n var d = isLE ? 1 : -1\n var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0\n\n value = Math.abs(value)\n\n if (isNaN(value) || value === Infinity) {\n m = isNaN(value) ? 1 : 0\n e = eMax\n } else {\n e = Math.floor(Math.log(value) / Math.LN2)\n if (value * (c = Math.pow(2, -e)) < 1) {\n e--\n c *= 2\n }\n if (e + eBias >= 1) {\n value += rt / c\n } else {\n value += rt * Math.pow(2, 1 - eBias)\n }\n if (value * c >= 2) {\n e++\n c /= 2\n }\n\n if (e + eBias >= eMax) {\n m = 0\n e = eMax\n } else if (e + eBias >= 1) {\n m = ((value * c) - 1) * Math.pow(2, mLen)\n e = e + eBias\n } else {\n m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)\n e = 0\n }\n }\n\n for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}\n\n e = (e << mLen) | m\n eLen += mLen\n for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}\n\n buffer[offset + i - d] |= s * 128\n}\n","var toString = {}.toString;\n\nmodule.exports = Array.isArray || function (arr) {\n return toString.call(arr) == '[object Array]';\n};\n","/*\r\nAuthor: Geraint Luff and others\r\nYear: 2013\r\n\r\nThis code is released into the \"public domain\" by its author(s). Anybody may use, alter and distribute the code without restriction. The author makes no guarantees, and takes no liability of any kind for use of this code.\r\n\r\nIf you find a bug or make an improvement, it would be courteous to let the author know, but it is not compulsory.\r\n*/\r\n(function (global, factory) {\r\n if (typeof define === 'function' && define.amd) {\r\n // AMD. Register as an anonymous module.\r\n define([], factory);\r\n } else if (typeof module !== 'undefined' && module.exports){\r\n // CommonJS. Define export.\r\n module.exports = factory();\r\n } else {\r\n // Browser globals\r\n global.tv4 = factory();\r\n }\r\n}(this, function () {\r\n\r\n// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FObject%2Fkeys\r\nif (!Object.keys) {\r\n\tObject.keys = (function () {\r\n\t\tvar hasOwnProperty = Object.prototype.hasOwnProperty,\r\n\t\t\thasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),\r\n\t\t\tdontEnums = [\r\n\t\t\t\t'toString',\r\n\t\t\t\t'toLocaleString',\r\n\t\t\t\t'valueOf',\r\n\t\t\t\t'hasOwnProperty',\r\n\t\t\t\t'isPrototypeOf',\r\n\t\t\t\t'propertyIsEnumerable',\r\n\t\t\t\t'constructor'\r\n\t\t\t],\r\n\t\t\tdontEnumsLength = dontEnums.length;\r\n\r\n\t\treturn function (obj) {\r\n\t\t\tif (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) {\r\n\t\t\t\tthrow new TypeError('Object.keys called on non-object');\r\n\t\t\t}\r\n\r\n\t\t\tvar result = [];\r\n\r\n\t\t\tfor (var prop in obj) {\r\n\t\t\t\tif (hasOwnProperty.call(obj, prop)) {\r\n\t\t\t\t\tresult.push(prop);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (hasDontEnumBug) {\r\n\t\t\t\tfor (var i=0; i < dontEnumsLength; i++) {\r\n\t\t\t\t\tif (hasOwnProperty.call(obj, dontEnums[i])) {\r\n\t\t\t\t\t\tresult.push(dontEnums[i]);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn result;\r\n\t\t};\r\n\t})();\r\n}\r\n// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create\r\nif (!Object.create) {\r\n\tObject.create = (function(){\r\n\t\tfunction F(){}\r\n\r\n\t\treturn function(o){\r\n\t\t\tif (arguments.length !== 1) {\r\n\t\t\t\tthrow new Error('Object.create implementation only accepts one parameter.');\r\n\t\t\t}\r\n\t\t\tF.prototype = o;\r\n\t\t\treturn new F();\r\n\t\t};\r\n\t})();\r\n}\r\n// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FArray%2FisArray\r\nif(!Array.isArray) {\r\n\tArray.isArray = function (vArg) {\r\n\t\treturn Object.prototype.toString.call(vArg) === \"[object Array]\";\r\n\t};\r\n}\r\n// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FArray%2FindexOf\r\nif (!Array.prototype.indexOf) {\r\n\tArray.prototype.indexOf = function (searchElement /*, fromIndex */ ) {\r\n\t\tif (this === null) {\r\n\t\t\tthrow new TypeError();\r\n\t\t}\r\n\t\tvar t = Object(this);\r\n\t\tvar len = t.length >>> 0;\r\n\r\n\t\tif (len === 0) {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\t\tvar n = 0;\r\n\t\tif (arguments.length > 1) {\r\n\t\t\tn = Number(arguments[1]);\r\n\t\t\tif (n !== n) { // shortcut for verifying if it's NaN\r\n\t\t\t\tn = 0;\r\n\t\t\t} else if (n !== 0 && n !== Infinity && n !== -Infinity) {\r\n\t\t\t\tn = (n > 0 || -1) * Math.floor(Math.abs(n));\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (n >= len) {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\t\tvar k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);\r\n\t\tfor (; k < len; k++) {\r\n\t\t\tif (k in t && t[k] === searchElement) {\r\n\t\t\t\treturn k;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn -1;\r\n\t};\r\n}\r\n\r\n// Grungey Object.isFrozen hack\r\nif (!Object.isFrozen) {\r\n\tObject.isFrozen = function (obj) {\r\n\t\tvar key = \"tv4_test_frozen_key\";\r\n\t\twhile (obj.hasOwnProperty(key)) {\r\n\t\t\tkey += Math.random();\r\n\t\t}\r\n\t\ttry {\r\n\t\t\tobj[key] = true;\r\n\t\t\tdelete obj[key];\r\n\t\t\treturn false;\r\n\t\t} catch (e) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t};\r\n}\r\n// Based on: https://github.com/geraintluff/uri-templates, but with all the de-substitution stuff removed\r\n\r\nvar uriTemplateGlobalModifiers = {\r\n\t\"+\": true,\r\n\t\"#\": true,\r\n\t\".\": true,\r\n\t\"/\": true,\r\n\t\";\": true,\r\n\t\"?\": true,\r\n\t\"&\": true\r\n};\r\nvar uriTemplateSuffices = {\r\n\t\"*\": true\r\n};\r\n\r\nfunction notReallyPercentEncode(string) {\r\n\treturn encodeURI(string).replace(/%25[0-9][0-9]/g, function (doubleEncoded) {\r\n\t\treturn \"%\" + doubleEncoded.substring(3);\r\n\t});\r\n}\r\n\r\nfunction uriTemplateSubstitution(spec) {\r\n\tvar modifier = \"\";\r\n\tif (uriTemplateGlobalModifiers[spec.charAt(0)]) {\r\n\t\tmodifier = spec.charAt(0);\r\n\t\tspec = spec.substring(1);\r\n\t}\r\n\tvar separator = \"\";\r\n\tvar prefix = \"\";\r\n\tvar shouldEscape = true;\r\n\tvar showVariables = false;\r\n\tvar trimEmptyString = false;\r\n\tif (modifier === '+') {\r\n\t\tshouldEscape = false;\r\n\t} else if (modifier === \".\") {\r\n\t\tprefix = \".\";\r\n\t\tseparator = \".\";\r\n\t} else if (modifier === \"/\") {\r\n\t\tprefix = \"/\";\r\n\t\tseparator = \"/\";\r\n\t} else if (modifier === '#') {\r\n\t\tprefix = \"#\";\r\n\t\tshouldEscape = false;\r\n\t} else if (modifier === ';') {\r\n\t\tprefix = \";\";\r\n\t\tseparator = \";\";\r\n\t\tshowVariables = true;\r\n\t\ttrimEmptyString = true;\r\n\t} else if (modifier === '?') {\r\n\t\tprefix = \"?\";\r\n\t\tseparator = \"&\";\r\n\t\tshowVariables = true;\r\n\t} else if (modifier === '&') {\r\n\t\tprefix = \"&\";\r\n\t\tseparator = \"&\";\r\n\t\tshowVariables = true;\r\n\t}\r\n\r\n\tvar varNames = [];\r\n\tvar varList = spec.split(\",\");\r\n\tvar varSpecs = [];\r\n\tvar varSpecMap = {};\r\n\tfor (var i = 0; i < varList.length; i++) {\r\n\t\tvar varName = varList[i];\r\n\t\tvar truncate = null;\r\n\t\tif (varName.indexOf(\":\") !== -1) {\r\n\t\t\tvar parts = varName.split(\":\");\r\n\t\t\tvarName = parts[0];\r\n\t\t\ttruncate = parseInt(parts[1], 10);\r\n\t\t}\r\n\t\tvar suffices = {};\r\n\t\twhile (uriTemplateSuffices[varName.charAt(varName.length - 1)]) {\r\n\t\t\tsuffices[varName.charAt(varName.length - 1)] = true;\r\n\t\t\tvarName = varName.substring(0, varName.length - 1);\r\n\t\t}\r\n\t\tvar varSpec = {\r\n\t\t\ttruncate: truncate,\r\n\t\t\tname: varName,\r\n\t\t\tsuffices: suffices\r\n\t\t};\r\n\t\tvarSpecs.push(varSpec);\r\n\t\tvarSpecMap[varName] = varSpec;\r\n\t\tvarNames.push(varName);\r\n\t}\r\n\tvar subFunction = function (valueFunction) {\r\n\t\tvar result = \"\";\r\n\t\tvar startIndex = 0;\r\n\t\tfor (var i = 0; i < varSpecs.length; i++) {\r\n\t\t\tvar varSpec = varSpecs[i];\r\n\t\t\tvar value = valueFunction(varSpec.name);\r\n\t\t\tif (value === null || value === undefined || (Array.isArray(value) && value.length === 0) || (typeof value === 'object' && Object.keys(value).length === 0)) {\r\n\t\t\t\tstartIndex++;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tif (i === startIndex) {\r\n\t\t\t\tresult += prefix;\r\n\t\t\t} else {\r\n\t\t\t\tresult += (separator || \",\");\r\n\t\t\t}\r\n\t\t\tif (Array.isArray(value)) {\r\n\t\t\t\tif (showVariables) {\r\n\t\t\t\t\tresult += varSpec.name + \"=\";\r\n\t\t\t\t}\r\n\t\t\t\tfor (var j = 0; j < value.length; j++) {\r\n\t\t\t\t\tif (j > 0) {\r\n\t\t\t\t\t\tresult += varSpec.suffices['*'] ? (separator || \",\") : \",\";\r\n\t\t\t\t\t\tif (varSpec.suffices['*'] && showVariables) {\r\n\t\t\t\t\t\t\tresult += varSpec.name + \"=\";\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\tresult += shouldEscape ? encodeURIComponent(value[j]).replace(/!/g, \"%21\") : notReallyPercentEncode(value[j]);\r\n\t\t\t\t}\r\n\t\t\t} else if (typeof value === \"object\") {\r\n\t\t\t\tif (showVariables && !varSpec.suffices['*']) {\r\n\t\t\t\t\tresult += varSpec.name + \"=\";\r\n\t\t\t\t}\r\n\t\t\t\tvar first = true;\r\n\t\t\t\tfor (var key in value) {\r\n\t\t\t\t\tif (!first) {\r\n\t\t\t\t\t\tresult += varSpec.suffices['*'] ? (separator || \",\") : \",\";\r\n\t\t\t\t\t}\r\n\t\t\t\t\tfirst = false;\r\n\t\t\t\t\tresult += shouldEscape ? encodeURIComponent(key).replace(/!/g, \"%21\") : notReallyPercentEncode(key);\r\n\t\t\t\t\tresult += varSpec.suffices['*'] ? '=' : \",\";\r\n\t\t\t\t\tresult += shouldEscape ? encodeURIComponent(value[key]).replace(/!/g, \"%21\") : notReallyPercentEncode(value[key]);\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tif (showVariables) {\r\n\t\t\t\t\tresult += varSpec.name;\r\n\t\t\t\t\tif (!trimEmptyString || value !== \"\") {\r\n\t\t\t\t\t\tresult += \"=\";\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tif (varSpec.truncate != null) {\r\n\t\t\t\t\tvalue = value.substring(0, varSpec.truncate);\r\n\t\t\t\t}\r\n\t\t\t\tresult += shouldEscape ? encodeURIComponent(value).replace(/!/g, \"%21\"): notReallyPercentEncode(value);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn result;\r\n\t};\r\n\tsubFunction.varNames = varNames;\r\n\treturn {\r\n\t\tprefix: prefix,\r\n\t\tsubstitution: subFunction\r\n\t};\r\n}\r\n\r\nfunction UriTemplate(template) {\r\n\tif (!(this instanceof UriTemplate)) {\r\n\t\treturn new UriTemplate(template);\r\n\t}\r\n\tvar parts = template.split(\"{\");\r\n\tvar textParts = [parts.shift()];\r\n\tvar prefixes = [];\r\n\tvar substitutions = [];\r\n\tvar varNames = [];\r\n\twhile (parts.length > 0) {\r\n\t\tvar part = parts.shift();\r\n\t\tvar spec = part.split(\"}\")[0];\r\n\t\tvar remainder = part.substring(spec.length + 1);\r\n\t\tvar funcs = uriTemplateSubstitution(spec);\r\n\t\tsubstitutions.push(funcs.substitution);\r\n\t\tprefixes.push(funcs.prefix);\r\n\t\ttextParts.push(remainder);\r\n\t\tvarNames = varNames.concat(funcs.substitution.varNames);\r\n\t}\r\n\tthis.fill = function (valueFunction) {\r\n\t\tvar result = textParts[0];\r\n\t\tfor (var i = 0; i < substitutions.length; i++) {\r\n\t\t\tvar substitution = substitutions[i];\r\n\t\t\tresult += substitution(valueFunction);\r\n\t\t\tresult += textParts[i + 1];\r\n\t\t}\r\n\t\treturn result;\r\n\t};\r\n\tthis.varNames = varNames;\r\n\tthis.template = template;\r\n}\r\nUriTemplate.prototype = {\r\n\ttoString: function () {\r\n\t\treturn this.template;\r\n\t},\r\n\tfillFromObject: function (obj) {\r\n\t\treturn this.fill(function (varName) {\r\n\t\t\treturn obj[varName];\r\n\t\t});\r\n\t}\r\n};\r\nvar ValidatorContext = function ValidatorContext(parent, collectMultiple, errorReporter, checkRecursive, trackUnknownProperties) {\r\n\tthis.missing = [];\r\n\tthis.missingMap = {};\r\n\tthis.formatValidators = parent ? Object.create(parent.formatValidators) : {};\r\n\tthis.schemas = parent ? Object.create(parent.schemas) : {};\r\n\tthis.collectMultiple = collectMultiple;\r\n\tthis.errors = [];\r\n\tthis.handleError = collectMultiple ? this.collectError : this.returnError;\r\n\tif (checkRecursive) {\r\n\t\tthis.checkRecursive = true;\r\n\t\tthis.scanned = [];\r\n\t\tthis.scannedFrozen = [];\r\n\t\tthis.scannedFrozenSchemas = [];\r\n\t\tthis.scannedFrozenValidationErrors = [];\r\n\t\tthis.validatedSchemasKey = 'tv4_validation_id';\r\n\t\tthis.validationErrorsKey = 'tv4_validation_errors_id';\r\n\t}\r\n\tif (trackUnknownProperties) {\r\n\t\tthis.trackUnknownProperties = true;\r\n\t\tthis.knownPropertyPaths = {};\r\n\t\tthis.unknownPropertyPaths = {};\r\n\t}\r\n\tthis.errorReporter = errorReporter || defaultErrorReporter('en');\r\n\tif (typeof this.errorReporter === 'string') {\r\n\t\tthrow new Error('debug');\r\n\t}\r\n\tthis.definedKeywords = {};\r\n\tif (parent) {\r\n\t\tfor (var key in parent.definedKeywords) {\r\n\t\t\tthis.definedKeywords[key] = parent.definedKeywords[key].slice(0);\r\n\t\t}\r\n\t}\r\n};\r\nValidatorContext.prototype.defineKeyword = function (keyword, keywordFunction) {\r\n\tthis.definedKeywords[keyword] = this.definedKeywords[keyword] || [];\r\n\tthis.definedKeywords[keyword].push(keywordFunction);\r\n};\r\nValidatorContext.prototype.createError = function (code, messageParams, dataPath, schemaPath, subErrors, data, schema) {\r\n\tvar error = new ValidationError(code, messageParams, dataPath, schemaPath, subErrors);\r\n\terror.message = this.errorReporter(error, data, schema);\r\n\treturn error;\r\n};\r\nValidatorContext.prototype.returnError = function (error) {\r\n\treturn error;\r\n};\r\nValidatorContext.prototype.collectError = function (error) {\r\n\tif (error) {\r\n\t\tthis.errors.push(error);\r\n\t}\r\n\treturn null;\r\n};\r\nValidatorContext.prototype.prefixErrors = function (startIndex, dataPath, schemaPath) {\r\n\tfor (var i = startIndex; i < this.errors.length; i++) {\r\n\t\tthis.errors[i] = this.errors[i].prefixWith(dataPath, schemaPath);\r\n\t}\r\n\treturn this;\r\n};\r\nValidatorContext.prototype.banUnknownProperties = function (data, schema) {\r\n\tfor (var unknownPath in this.unknownPropertyPaths) {\r\n\t\tvar error = this.createError(ErrorCodes.UNKNOWN_PROPERTY, {path: unknownPath}, unknownPath, \"\", null, data, schema);\r\n\t\tvar result = this.handleError(error);\r\n\t\tif (result) {\r\n\t\t\treturn result;\r\n\t\t}\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.addFormat = function (format, validator) {\r\n\tif (typeof format === 'object') {\r\n\t\tfor (var key in format) {\r\n\t\t\tthis.addFormat(key, format[key]);\r\n\t\t}\r\n\t\treturn this;\r\n\t}\r\n\tthis.formatValidators[format] = validator;\r\n};\r\nValidatorContext.prototype.resolveRefs = function (schema, urlHistory) {\r\n\tif (schema['$ref'] !== undefined) {\r\n\t\turlHistory = urlHistory || {};\r\n\t\tif (urlHistory[schema['$ref']]) {\r\n\t\t\treturn this.createError(ErrorCodes.CIRCULAR_REFERENCE, {urls: Object.keys(urlHistory).join(', ')}, '', '', null, undefined, schema);\r\n\t\t}\r\n\t\turlHistory[schema['$ref']] = true;\r\n\t\tschema = this.getSchema(schema['$ref'], urlHistory);\r\n\t}\r\n\treturn schema;\r\n};\r\nValidatorContext.prototype.getSchema = function (url, urlHistory) {\r\n\tvar schema;\r\n\tif (this.schemas[url] !== undefined) {\r\n\t\tschema = this.schemas[url];\r\n\t\treturn this.resolveRefs(schema, urlHistory);\r\n\t}\r\n\tvar baseUrl = url;\r\n\tvar fragment = \"\";\r\n\tif (url.indexOf('#') !== -1) {\r\n\t\tfragment = url.substring(url.indexOf(\"#\") + 1);\r\n\t\tbaseUrl = url.substring(0, url.indexOf(\"#\"));\r\n\t}\r\n\tif (typeof this.schemas[baseUrl] === 'object') {\r\n\t\tschema = this.schemas[baseUrl];\r\n\t\tvar pointerPath = decodeURIComponent(fragment);\r\n\t\tif (pointerPath === \"\") {\r\n\t\t\treturn this.resolveRefs(schema, urlHistory);\r\n\t\t} else if (pointerPath.charAt(0) !== \"/\") {\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\t\tvar parts = pointerPath.split(\"/\").slice(1);\r\n\t\tfor (var i = 0; i < parts.length; i++) {\r\n\t\t\tvar component = parts[i].replace(/~1/g, \"/\").replace(/~0/g, \"~\");\r\n\t\t\tif (schema[component] === undefined) {\r\n\t\t\t\tschema = undefined;\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tschema = schema[component];\r\n\t\t}\r\n\t\tif (schema !== undefined) {\r\n\t\t\treturn this.resolveRefs(schema, urlHistory);\r\n\t\t}\r\n\t}\r\n\tif (this.missing[baseUrl] === undefined) {\r\n\t\tthis.missing.push(baseUrl);\r\n\t\tthis.missing[baseUrl] = baseUrl;\r\n\t\tthis.missingMap[baseUrl] = baseUrl;\r\n\t}\r\n};\r\nValidatorContext.prototype.searchSchemas = function (schema, url) {\r\n\tif (Array.isArray(schema)) {\r\n\t\tfor (var i = 0; i < schema.length; i++) {\r\n\t\t\tthis.searchSchemas(schema[i], url);\r\n\t\t}\r\n\t} else if (schema && typeof schema === \"object\") {\r\n\t\tif (typeof schema.id === \"string\") {\r\n\t\t\tif (isTrustedUrl(url, schema.id)) {\r\n\t\t\t\tif (this.schemas[schema.id] === undefined) {\r\n\t\t\t\t\tthis.schemas[schema.id] = schema;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\tfor (var key in schema) {\r\n\t\t\tif (key !== \"enum\") {\r\n\t\t\t\tif (typeof schema[key] === \"object\") {\r\n\t\t\t\t\tthis.searchSchemas(schema[key], url);\r\n\t\t\t\t} else if (key === \"$ref\") {\r\n\t\t\t\t\tvar uri = getDocumentUri(schema[key]);\r\n\t\t\t\t\tif (uri && this.schemas[uri] === undefined && this.missingMap[uri] === undefined) {\r\n\t\t\t\t\t\tthis.missingMap[uri] = uri;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n};\r\nValidatorContext.prototype.addSchema = function (url, schema) {\r\n\t//overload\r\n\tif (typeof url !== 'string' || typeof schema === 'undefined') {\r\n\t\tif (typeof url === 'object' && typeof url.id === 'string') {\r\n\t\t\tschema = url;\r\n\t\t\turl = schema.id;\r\n\t\t}\r\n\t\telse {\r\n\t\t\treturn;\r\n\t\t}\r\n\t}\r\n\tif (url === getDocumentUri(url) + \"#\") {\r\n\t\t// Remove empty fragment\r\n\t\turl = getDocumentUri(url);\r\n\t}\r\n\tthis.schemas[url] = schema;\r\n\tdelete this.missingMap[url];\r\n\tnormSchema(schema, url);\r\n\tthis.searchSchemas(schema, url);\r\n};\r\n\r\nValidatorContext.prototype.getSchemaMap = function () {\r\n\tvar map = {};\r\n\tfor (var key in this.schemas) {\r\n\t\tmap[key] = this.schemas[key];\r\n\t}\r\n\treturn map;\r\n};\r\n\r\nValidatorContext.prototype.getSchemaUris = function (filterRegExp) {\r\n\tvar list = [];\r\n\tfor (var key in this.schemas) {\r\n\t\tif (!filterRegExp || filterRegExp.test(key)) {\r\n\t\t\tlist.push(key);\r\n\t\t}\r\n\t}\r\n\treturn list;\r\n};\r\n\r\nValidatorContext.prototype.getMissingUris = function (filterRegExp) {\r\n\tvar list = [];\r\n\tfor (var key in this.missingMap) {\r\n\t\tif (!filterRegExp || filterRegExp.test(key)) {\r\n\t\t\tlist.push(key);\r\n\t\t}\r\n\t}\r\n\treturn list;\r\n};\r\n\r\nValidatorContext.prototype.dropSchemas = function () {\r\n\tthis.schemas = {};\r\n\tthis.reset();\r\n};\r\nValidatorContext.prototype.reset = function () {\r\n\tthis.missing = [];\r\n\tthis.missingMap = {};\r\n\tthis.errors = [];\r\n};\r\n\r\nValidatorContext.prototype.validateAll = function (data, schema, dataPathParts, schemaPathParts, dataPointerPath) {\r\n\tvar topLevel;\r\n\tschema = this.resolveRefs(schema);\r\n\tif (!schema) {\r\n\t\treturn null;\r\n\t} else if (schema instanceof ValidationError) {\r\n\t\tthis.errors.push(schema);\r\n\t\treturn schema;\r\n\t}\r\n\r\n\tvar startErrorCount = this.errors.length;\r\n\tvar frozenIndex, scannedFrozenSchemaIndex = null, scannedSchemasIndex = null;\r\n\tif (this.checkRecursive && data && typeof data === 'object') {\r\n\t\ttopLevel = !this.scanned.length;\r\n\t\tif (data[this.validatedSchemasKey]) {\r\n\t\t\tvar schemaIndex = data[this.validatedSchemasKey].indexOf(schema);\r\n\t\t\tif (schemaIndex !== -1) {\r\n\t\t\t\tthis.errors = this.errors.concat(data[this.validationErrorsKey][schemaIndex]);\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (Object.isFrozen(data)) {\r\n\t\t\tfrozenIndex = this.scannedFrozen.indexOf(data);\r\n\t\t\tif (frozenIndex !== -1) {\r\n\t\t\t\tvar frozenSchemaIndex = this.scannedFrozenSchemas[frozenIndex].indexOf(schema);\r\n\t\t\t\tif (frozenSchemaIndex !== -1) {\r\n\t\t\t\t\tthis.errors = this.errors.concat(this.scannedFrozenValidationErrors[frozenIndex][frozenSchemaIndex]);\r\n\t\t\t\t\treturn null;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\tthis.scanned.push(data);\r\n\t\tif (Object.isFrozen(data)) {\r\n\t\t\tif (frozenIndex === -1) {\r\n\t\t\t\tfrozenIndex = this.scannedFrozen.length;\r\n\t\t\t\tthis.scannedFrozen.push(data);\r\n\t\t\t\tthis.scannedFrozenSchemas.push([]);\r\n\t\t\t}\r\n\t\t\tscannedFrozenSchemaIndex = this.scannedFrozenSchemas[frozenIndex].length;\r\n\t\t\tthis.scannedFrozenSchemas[frozenIndex][scannedFrozenSchemaIndex] = schema;\r\n\t\t\tthis.scannedFrozenValidationErrors[frozenIndex][scannedFrozenSchemaIndex] = [];\r\n\t\t} else {\r\n\t\t\tif (!data[this.validatedSchemasKey]) {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tObject.defineProperty(data, this.validatedSchemasKey, {\r\n\t\t\t\t\t\tvalue: [],\r\n\t\t\t\t\t\tconfigurable: true\r\n\t\t\t\t\t});\r\n\t\t\t\t\tObject.defineProperty(data, this.validationErrorsKey, {\r\n\t\t\t\t\t\tvalue: [],\r\n\t\t\t\t\t\tconfigurable: true\r\n\t\t\t\t\t});\r\n\t\t\t\t} catch (e) {\r\n\t\t\t\t\t//IE 7/8 workaround\r\n\t\t\t\t\tdata[this.validatedSchemasKey] = [];\r\n\t\t\t\t\tdata[this.validationErrorsKey] = [];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tscannedSchemasIndex = data[this.validatedSchemasKey].length;\r\n\t\t\tdata[this.validatedSchemasKey][scannedSchemasIndex] = schema;\r\n\t\t\tdata[this.validationErrorsKey][scannedSchemasIndex] = [];\r\n\t\t}\r\n\t}\r\n\r\n\tvar errorCount = this.errors.length;\r\n\tvar error = this.validateBasic(data, schema, dataPointerPath)\r\n\t\t|| this.validateNumeric(data, schema, dataPointerPath)\r\n\t\t|| this.validateString(data, schema, dataPointerPath)\r\n\t\t|| this.validateArray(data, schema, dataPointerPath)\r\n\t\t|| this.validateObject(data, schema, dataPointerPath)\r\n\t\t|| this.validateCombinations(data, schema, dataPointerPath)\r\n\t\t|| this.validateHypermedia(data, schema, dataPointerPath)\r\n\t\t|| this.validateFormat(data, schema, dataPointerPath)\r\n\t\t|| this.validateDefinedKeywords(data, schema, dataPointerPath)\r\n\t\t|| null;\r\n\r\n\tif (topLevel) {\r\n\t\twhile (this.scanned.length) {\r\n\t\t\tvar item = this.scanned.pop();\r\n\t\t\tdelete item[this.validatedSchemasKey];\r\n\t\t}\r\n\t\tthis.scannedFrozen = [];\r\n\t\tthis.scannedFrozenSchemas = [];\r\n\t}\r\n\r\n\tif (error || errorCount !== this.errors.length) {\r\n\t\twhile ((dataPathParts && dataPathParts.length) || (schemaPathParts && schemaPathParts.length)) {\r\n\t\t\tvar dataPart = (dataPathParts && dataPathParts.length) ? \"\" + dataPathParts.pop() : null;\r\n\t\t\tvar schemaPart = (schemaPathParts && schemaPathParts.length) ? \"\" + schemaPathParts.pop() : null;\r\n\t\t\tif (error) {\r\n\t\t\t\terror = error.prefixWith(dataPart, schemaPart);\r\n\t\t\t}\r\n\t\t\tthis.prefixErrors(errorCount, dataPart, schemaPart);\r\n\t\t}\r\n\t}\r\n\r\n\tif (scannedFrozenSchemaIndex !== null) {\r\n\t\tthis.scannedFrozenValidationErrors[frozenIndex][scannedFrozenSchemaIndex] = this.errors.slice(startErrorCount);\r\n\t} else if (scannedSchemasIndex !== null) {\r\n\t\tdata[this.validationErrorsKey][scannedSchemasIndex] = this.errors.slice(startErrorCount);\r\n\t}\r\n\r\n\treturn this.handleError(error);\r\n};\r\nValidatorContext.prototype.validateFormat = function (data, schema) {\r\n\tif (typeof schema.format !== 'string' || !this.formatValidators[schema.format]) {\r\n\t\treturn null;\r\n\t}\r\n\tvar errorMessage = this.formatValidators[schema.format].call(null, data, schema);\r\n\tif (typeof errorMessage === 'string' || typeof errorMessage === 'number') {\r\n\t\treturn this.createError(ErrorCodes.FORMAT_CUSTOM, {message: errorMessage}, '', '/format', null, data, schema);\r\n\t} else if (errorMessage && typeof errorMessage === 'object') {\r\n\t\treturn this.createError(ErrorCodes.FORMAT_CUSTOM, {message: errorMessage.message || \"?\"}, errorMessage.dataPath || '', errorMessage.schemaPath || \"/format\", null, data, schema);\r\n\t}\r\n\treturn null;\r\n};\r\nValidatorContext.prototype.validateDefinedKeywords = function (data, schema, dataPointerPath) {\r\n\tfor (var key in this.definedKeywords) {\r\n\t\tif (typeof schema[key] === 'undefined') {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\t\tvar validationFunctions = this.definedKeywords[key];\r\n\t\tfor (var i = 0; i < validationFunctions.length; i++) {\r\n\t\t\tvar func = validationFunctions[i];\r\n\t\t\tvar result = func(data, schema[key], schema, dataPointerPath);\r\n\t\t\tif (typeof result === 'string' || typeof result === 'number') {\r\n\t\t\t\treturn this.createError(ErrorCodes.KEYWORD_CUSTOM, {key: key, message: result}, '', '', null, data, schema).prefixWith(null, key);\r\n\t\t\t} else if (result && typeof result === 'object') {\r\n\t\t\t\tvar code = result.code;\r\n\t\t\t\tif (typeof code === 'string') {\r\n\t\t\t\t\tif (!ErrorCodes[code]) {\r\n\t\t\t\t\t\tthrow new Error('Undefined error code (use defineError): ' + code);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tcode = ErrorCodes[code];\r\n\t\t\t\t} else if (typeof code !== 'number') {\r\n\t\t\t\t\tcode = ErrorCodes.KEYWORD_CUSTOM;\r\n\t\t\t\t}\r\n\t\t\t\tvar messageParams = (typeof result.message === 'object') ? result.message : {key: key, message: result.message || \"?\"};\r\n\t\t\t\tvar schemaPath = result.schemaPath || (\"/\" + key.replace(/~/g, '~0').replace(/\\//g, '~1'));\r\n\t\t\t\treturn this.createError(code, messageParams, result.dataPath || null, schemaPath, null, data, schema);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nfunction recursiveCompare(A, B) {\r\n\tif (A === B) {\r\n\t\treturn true;\r\n\t}\r\n\tif (A && B && typeof A === \"object\" && typeof B === \"object\") {\r\n\t\tif (Array.isArray(A) !== Array.isArray(B)) {\r\n\t\t\treturn false;\r\n\t\t} else if (Array.isArray(A)) {\r\n\t\t\tif (A.length !== B.length) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t\tfor (var i = 0; i < A.length; i++) {\r\n\t\t\t\tif (!recursiveCompare(A[i], B[i])) {\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tvar key;\r\n\t\t\tfor (key in A) {\r\n\t\t\t\tif (B[key] === undefined && A[key] !== undefined) {\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tfor (key in B) {\r\n\t\t\t\tif (A[key] === undefined && B[key] !== undefined) {\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tfor (key in A) {\r\n\t\t\t\tif (!recursiveCompare(A[key], B[key])) {\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\treturn false;\r\n}\r\n\r\nValidatorContext.prototype.validateBasic = function validateBasic(data, schema, dataPointerPath) {\r\n\tvar error;\r\n\tif (error = this.validateType(data, schema, dataPointerPath)) {\r\n\t\treturn error.prefixWith(null, \"type\");\r\n\t}\r\n\tif (error = this.validateEnum(data, schema, dataPointerPath)) {\r\n\t\treturn error.prefixWith(null, \"type\");\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.validateType = function validateType(data, schema) {\r\n\tif (schema.type === undefined) {\r\n\t\treturn null;\r\n\t}\r\n\tvar dataType = typeof data;\r\n\tif (data === null) {\r\n\t\tdataType = \"null\";\r\n\t} else if (Array.isArray(data)) {\r\n\t\tdataType = \"array\";\r\n\t}\r\n\tvar allowedTypes = schema.type;\r\n\tif (!Array.isArray(allowedTypes)) {\r\n\t\tallowedTypes = [allowedTypes];\r\n\t}\r\n\r\n\tfor (var i = 0; i < allowedTypes.length; i++) {\r\n\t\tvar type = allowedTypes[i];\r\n\t\tif (type === dataType || (type === \"integer\" && dataType === \"number\" && (data % 1 === 0))) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t}\r\n\treturn this.createError(ErrorCodes.INVALID_TYPE, {type: dataType, expected: allowedTypes.join(\"/\")}, '', '', null, data, schema);\r\n};\r\n\r\nValidatorContext.prototype.validateEnum = function validateEnum(data, schema) {\r\n\tif (schema[\"enum\"] === undefined) {\r\n\t\treturn null;\r\n\t}\r\n\tfor (var i = 0; i < schema[\"enum\"].length; i++) {\r\n\t\tvar enumVal = schema[\"enum\"][i];\r\n\t\tif (recursiveCompare(data, enumVal)) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t}\r\n\treturn this.createError(ErrorCodes.ENUM_MISMATCH, {value: (typeof JSON !== 'undefined') ? JSON.stringify(data) : data}, '', '', null, data, schema);\r\n};\r\n\r\nValidatorContext.prototype.validateNumeric = function validateNumeric(data, schema, dataPointerPath) {\r\n\treturn this.validateMultipleOf(data, schema, dataPointerPath)\r\n\t\t|| this.validateMinMax(data, schema, dataPointerPath)\r\n\t\t|| this.validateNaN(data, schema, dataPointerPath)\r\n\t\t|| null;\r\n};\r\n\r\nvar CLOSE_ENOUGH_LOW = Math.pow(2, -51);\r\nvar CLOSE_ENOUGH_HIGH = 1 - CLOSE_ENOUGH_LOW;\r\nValidatorContext.prototype.validateMultipleOf = function validateMultipleOf(data, schema) {\r\n\tvar multipleOf = schema.multipleOf || schema.divisibleBy;\r\n\tif (multipleOf === undefined) {\r\n\t\treturn null;\r\n\t}\r\n\tif (typeof data === \"number\") {\r\n\t\tvar remainder = (data/multipleOf)%1;\r\n\t\tif (remainder >= CLOSE_ENOUGH_LOW && remainder < CLOSE_ENOUGH_HIGH) {\r\n\t\t\treturn this.createError(ErrorCodes.NUMBER_MULTIPLE_OF, {value: data, multipleOf: multipleOf}, '', '', null, data, schema);\r\n\t\t}\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.validateMinMax = function validateMinMax(data, schema) {\r\n\tif (typeof data !== \"number\") {\r\n\t\treturn null;\r\n\t}\r\n\tif (schema.minimum !== undefined) {\r\n\t\tif (data < schema.minimum) {\r\n\t\t\treturn this.createError(ErrorCodes.NUMBER_MINIMUM, {value: data, minimum: schema.minimum}, '', '/minimum', null, data, schema);\r\n\t\t}\r\n\t\tif (schema.exclusiveMinimum && data === schema.minimum) {\r\n\t\t\treturn this.createError(ErrorCodes.NUMBER_MINIMUM_EXCLUSIVE, {value: data, minimum: schema.minimum}, '', '/exclusiveMinimum', null, data, schema);\r\n\t\t}\r\n\t}\r\n\tif (schema.maximum !== undefined) {\r\n\t\tif (data > schema.maximum) {\r\n\t\t\treturn this.createError(ErrorCodes.NUMBER_MAXIMUM, {value: data, maximum: schema.maximum}, '', '/maximum', null, data, schema);\r\n\t\t}\r\n\t\tif (schema.exclusiveMaximum && data === schema.maximum) {\r\n\t\t\treturn this.createError(ErrorCodes.NUMBER_MAXIMUM_EXCLUSIVE, {value: data, maximum: schema.maximum}, '', '/exclusiveMaximum', null, data, schema);\r\n\t\t}\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.validateNaN = function validateNaN(data, schema) {\r\n\tif (typeof data !== \"number\") {\r\n\t\treturn null;\r\n\t}\r\n\tif (isNaN(data) === true || data === Infinity || data === -Infinity) {\r\n\t\treturn this.createError(ErrorCodes.NUMBER_NOT_A_NUMBER, {value: data}, '', '/type', null, data, schema);\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.validateString = function validateString(data, schema, dataPointerPath) {\r\n\treturn this.validateStringLength(data, schema, dataPointerPath)\r\n\t\t|| this.validateStringPattern(data, schema, dataPointerPath)\r\n\t\t|| null;\r\n};\r\n\r\nValidatorContext.prototype.validateStringLength = function validateStringLength(data, schema) {\r\n\tif (typeof data !== \"string\") {\r\n\t\treturn null;\r\n\t}\r\n\tif (schema.minLength !== undefined) {\r\n\t\tif (data.length < schema.minLength) {\r\n\t\t\treturn this.createError(ErrorCodes.STRING_LENGTH_SHORT, {length: data.length, minimum: schema.minLength}, '', '/minLength', null, data, schema);\r\n\t\t}\r\n\t}\r\n\tif (schema.maxLength !== undefined) {\r\n\t\tif (data.length > schema.maxLength) {\r\n\t\t\treturn this.createError(ErrorCodes.STRING_LENGTH_LONG, {length: data.length, maximum: schema.maxLength}, '', '/maxLength', null, data, schema);\r\n\t\t}\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.validateStringPattern = function validateStringPattern(data, schema) {\r\n\tif (typeof data !== \"string\" || (typeof schema.pattern !== \"string\" && !(schema.pattern instanceof RegExp))) {\r\n\t\treturn null;\r\n\t}\r\n\tvar regexp;\r\n\tif (schema.pattern instanceof RegExp) {\r\n\t regexp = schema.pattern;\r\n\t}\r\n\telse {\r\n\t var body, flags = '';\r\n\t // Check for regular expression literals\r\n\t // @see http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.5\r\n\t var literal = schema.pattern.match(/^\\/(.+)\\/([img]*)$/);\r\n\t if (literal) {\r\n\t body = literal[1];\r\n\t flags = literal[2];\r\n\t }\r\n\t else {\r\n\t body = schema.pattern;\r\n\t }\r\n\t regexp = new RegExp(body, flags);\r\n\t}\r\n\tif (!regexp.test(data)) {\r\n\t\treturn this.createError(ErrorCodes.STRING_PATTERN, {pattern: schema.pattern}, '', '/pattern', null, data, schema);\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.validateArray = function validateArray(data, schema, dataPointerPath) {\r\n\tif (!Array.isArray(data)) {\r\n\t\treturn null;\r\n\t}\r\n\treturn this.validateArrayLength(data, schema, dataPointerPath)\r\n\t\t|| this.validateArrayUniqueItems(data, schema, dataPointerPath)\r\n\t\t|| this.validateArrayItems(data, schema, dataPointerPath)\r\n\t\t|| null;\r\n};\r\n\r\nValidatorContext.prototype.validateArrayLength = function validateArrayLength(data, schema) {\r\n\tvar error;\r\n\tif (schema.minItems !== undefined) {\r\n\t\tif (data.length < schema.minItems) {\r\n\t\t\terror = this.createError(ErrorCodes.ARRAY_LENGTH_SHORT, {length: data.length, minimum: schema.minItems}, '', '/minItems', null, data, schema);\r\n\t\t\tif (this.handleError(error)) {\r\n\t\t\t\treturn error;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\tif (schema.maxItems !== undefined) {\r\n\t\tif (data.length > schema.maxItems) {\r\n\t\t\terror = this.createError(ErrorCodes.ARRAY_LENGTH_LONG, {length: data.length, maximum: schema.maxItems}, '', '/maxItems', null, data, schema);\r\n\t\t\tif (this.handleError(error)) {\r\n\t\t\t\treturn error;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.validateArrayUniqueItems = function validateArrayUniqueItems(data, schema) {\r\n\tif (schema.uniqueItems) {\r\n\t\tfor (var i = 0; i < data.length; i++) {\r\n\t\t\tfor (var j = i + 1; j < data.length; j++) {\r\n\t\t\t\tif (recursiveCompare(data[i], data[j])) {\r\n\t\t\t\t\tvar error = this.createError(ErrorCodes.ARRAY_UNIQUE, {match1: i, match2: j}, '', '/uniqueItems', null, data, schema);\r\n\t\t\t\t\tif (this.handleError(error)) {\r\n\t\t\t\t\t\treturn error;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.validateArrayItems = function validateArrayItems(data, schema, dataPointerPath) {\r\n\tif (schema.items === undefined) {\r\n\t\treturn null;\r\n\t}\r\n\tvar error, i;\r\n\tif (Array.isArray(schema.items)) {\r\n\t\tfor (i = 0; i < data.length; i++) {\r\n\t\t\tif (i < schema.items.length) {\r\n\t\t\t\tif (error = this.validateAll(data[i], schema.items[i], [i], [\"items\", i], dataPointerPath + \"/\" + i)) {\r\n\t\t\t\t\treturn error;\r\n\t\t\t\t}\r\n\t\t\t} else if (schema.additionalItems !== undefined) {\r\n\t\t\t\tif (typeof schema.additionalItems === \"boolean\") {\r\n\t\t\t\t\tif (!schema.additionalItems) {\r\n\t\t\t\t\t\terror = (this.createError(ErrorCodes.ARRAY_ADDITIONAL_ITEMS, {}, '/' + i, '/additionalItems', null, data, schema));\r\n\t\t\t\t\t\tif (this.handleError(error)) {\r\n\t\t\t\t\t\t\treturn error;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t} else if (error = this.validateAll(data[i], schema.additionalItems, [i], [\"additionalItems\"], dataPointerPath + \"/\" + i)) {\r\n\t\t\t\t\treturn error;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t} else {\r\n\t\tfor (i = 0; i < data.length; i++) {\r\n\t\t\tif (error = this.validateAll(data[i], schema.items, [i], [\"items\"], dataPointerPath + \"/\" + i)) {\r\n\t\t\t\treturn error;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.validateObject = function validateObject(data, schema, dataPointerPath) {\r\n\tif (typeof data !== \"object\" || data === null || Array.isArray(data)) {\r\n\t\treturn null;\r\n\t}\r\n\treturn this.validateObjectMinMaxProperties(data, schema, dataPointerPath)\r\n\t\t|| this.validateObjectRequiredProperties(data, schema, dataPointerPath)\r\n\t\t|| this.validateObjectProperties(data, schema, dataPointerPath)\r\n\t\t|| this.validateObjectDependencies(data, schema, dataPointerPath)\r\n\t\t|| null;\r\n};\r\n\r\nValidatorContext.prototype.validateObjectMinMaxProperties = function validateObjectMinMaxProperties(data, schema) {\r\n\tvar keys = Object.keys(data);\r\n\tvar error;\r\n\tif (schema.minProperties !== undefined) {\r\n\t\tif (keys.length < schema.minProperties) {\r\n\t\t\terror = this.createError(ErrorCodes.OBJECT_PROPERTIES_MINIMUM, {propertyCount: keys.length, minimum: schema.minProperties}, '', '/minProperties', null, data, schema);\r\n\t\t\tif (this.handleError(error)) {\r\n\t\t\t\treturn error;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\tif (schema.maxProperties !== undefined) {\r\n\t\tif (keys.length > schema.maxProperties) {\r\n\t\t\terror = this.createError(ErrorCodes.OBJECT_PROPERTIES_MAXIMUM, {propertyCount: keys.length, maximum: schema.maxProperties}, '', '/maxProperties', null, data, schema);\r\n\t\t\tif (this.handleError(error)) {\r\n\t\t\t\treturn error;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.validateObjectRequiredProperties = function validateObjectRequiredProperties(data, schema) {\r\n\tif (schema.required !== undefined) {\r\n\t\tfor (var i = 0; i < schema.required.length; i++) {\r\n\t\t\tvar key = schema.required[i];\r\n\t\t\tif (data[key] === undefined) {\r\n\t\t\t\tvar error = this.createError(ErrorCodes.OBJECT_REQUIRED, {key: key}, '', '/required/' + i, null, data, schema);\r\n\t\t\t\tif (this.handleError(error)) {\r\n\t\t\t\t\treturn error;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.validateObjectProperties = function validateObjectProperties(data, schema, dataPointerPath) {\r\n\tvar error;\r\n\tfor (var key in data) {\r\n\t\tvar keyPointerPath = dataPointerPath + \"/\" + key.replace(/~/g, '~0').replace(/\\//g, '~1');\r\n\t\tvar foundMatch = false;\r\n\t\tif (schema.properties !== undefined && schema.properties[key] !== undefined) {\r\n\t\t\tfoundMatch = true;\r\n\t\t\tif (error = this.validateAll(data[key], schema.properties[key], [key], [\"properties\", key], keyPointerPath)) {\r\n\t\t\t\treturn error;\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (schema.patternProperties !== undefined) {\r\n\t\t\tfor (var patternKey in schema.patternProperties) {\r\n\t\t\t\tvar regexp = new RegExp(patternKey);\r\n\t\t\t\tif (regexp.test(key)) {\r\n\t\t\t\t\tfoundMatch = true;\r\n\t\t\t\t\tif (error = this.validateAll(data[key], schema.patternProperties[patternKey], [key], [\"patternProperties\", patternKey], keyPointerPath)) {\r\n\t\t\t\t\t\treturn error;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (!foundMatch) {\r\n\t\t\tif (schema.additionalProperties !== undefined) {\r\n\t\t\t\tif (this.trackUnknownProperties) {\r\n\t\t\t\t\tthis.knownPropertyPaths[keyPointerPath] = true;\r\n\t\t\t\t\tdelete this.unknownPropertyPaths[keyPointerPath];\r\n\t\t\t\t}\r\n\t\t\t\tif (typeof schema.additionalProperties === \"boolean\") {\r\n\t\t\t\t\tif (!schema.additionalProperties) {\r\n\t\t\t\t\t\terror = this.createError(ErrorCodes.OBJECT_ADDITIONAL_PROPERTIES, {key: key}, '', '/additionalProperties', null, data, schema).prefixWith(key, null);\r\n\t\t\t\t\t\tif (this.handleError(error)) {\r\n\t\t\t\t\t\t\treturn error;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tif (error = this.validateAll(data[key], schema.additionalProperties, [key], [\"additionalProperties\"], keyPointerPath)) {\r\n\t\t\t\t\t\treturn error;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t} else if (this.trackUnknownProperties && !this.knownPropertyPaths[keyPointerPath]) {\r\n\t\t\t\tthis.unknownPropertyPaths[keyPointerPath] = true;\r\n\t\t\t}\r\n\t\t} else if (this.trackUnknownProperties) {\r\n\t\t\tthis.knownPropertyPaths[keyPointerPath] = true;\r\n\t\t\tdelete this.unknownPropertyPaths[keyPointerPath];\r\n\t\t}\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.validateObjectDependencies = function validateObjectDependencies(data, schema, dataPointerPath) {\r\n\tvar error;\r\n\tif (schema.dependencies !== undefined) {\r\n\t\tfor (var depKey in schema.dependencies) {\r\n\t\t\tif (data[depKey] !== undefined) {\r\n\t\t\t\tvar dep = schema.dependencies[depKey];\r\n\t\t\t\tif (typeof dep === \"string\") {\r\n\t\t\t\t\tif (data[dep] === undefined) {\r\n\t\t\t\t\t\terror = this.createError(ErrorCodes.OBJECT_DEPENDENCY_KEY, {key: depKey, missing: dep}, '', '', null, data, schema).prefixWith(null, depKey).prefixWith(null, \"dependencies\");\r\n\t\t\t\t\t\tif (this.handleError(error)) {\r\n\t\t\t\t\t\t\treturn error;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t} else if (Array.isArray(dep)) {\r\n\t\t\t\t\tfor (var i = 0; i < dep.length; i++) {\r\n\t\t\t\t\t\tvar requiredKey = dep[i];\r\n\t\t\t\t\t\tif (data[requiredKey] === undefined) {\r\n\t\t\t\t\t\t\terror = this.createError(ErrorCodes.OBJECT_DEPENDENCY_KEY, {key: depKey, missing: requiredKey}, '', '/' + i, null, data, schema).prefixWith(null, depKey).prefixWith(null, \"dependencies\");\r\n\t\t\t\t\t\t\tif (this.handleError(error)) {\r\n\t\t\t\t\t\t\t\treturn error;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tif (error = this.validateAll(data, dep, [], [\"dependencies\", depKey], dataPointerPath)) {\r\n\t\t\t\t\t\treturn error;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.validateCombinations = function validateCombinations(data, schema, dataPointerPath) {\r\n\treturn this.validateAllOf(data, schema, dataPointerPath)\r\n\t\t|| this.validateAnyOf(data, schema, dataPointerPath)\r\n\t\t|| this.validateOneOf(data, schema, dataPointerPath)\r\n\t\t|| this.validateNot(data, schema, dataPointerPath)\r\n\t\t|| null;\r\n};\r\n\r\nValidatorContext.prototype.validateAllOf = function validateAllOf(data, schema, dataPointerPath) {\r\n\tif (schema.allOf === undefined) {\r\n\t\treturn null;\r\n\t}\r\n\tvar error;\r\n\tfor (var i = 0; i < schema.allOf.length; i++) {\r\n\t\tvar subSchema = schema.allOf[i];\r\n\t\tif (error = this.validateAll(data, subSchema, [], [\"allOf\", i], dataPointerPath)) {\r\n\t\t\treturn error;\r\n\t\t}\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.validateAnyOf = function validateAnyOf(data, schema, dataPointerPath) {\r\n\tif (schema.anyOf === undefined) {\r\n\t\treturn null;\r\n\t}\r\n\tvar errors = [];\r\n\tvar startErrorCount = this.errors.length;\r\n\tvar oldUnknownPropertyPaths, oldKnownPropertyPaths;\r\n\tif (this.trackUnknownProperties) {\r\n\t\toldUnknownPropertyPaths = this.unknownPropertyPaths;\r\n\t\toldKnownPropertyPaths = this.knownPropertyPaths;\r\n\t}\r\n\tvar errorAtEnd = true;\r\n\tfor (var i = 0; i < schema.anyOf.length; i++) {\r\n\t\tif (this.trackUnknownProperties) {\r\n\t\t\tthis.unknownPropertyPaths = {};\r\n\t\t\tthis.knownPropertyPaths = {};\r\n\t\t}\r\n\t\tvar subSchema = schema.anyOf[i];\r\n\r\n\t\tvar errorCount = this.errors.length;\r\n\t\tvar error = this.validateAll(data, subSchema, [], [\"anyOf\", i], dataPointerPath);\r\n\r\n\t\tif (error === null && errorCount === this.errors.length) {\r\n\t\t\tthis.errors = this.errors.slice(0, startErrorCount);\r\n\r\n\t\t\tif (this.trackUnknownProperties) {\r\n\t\t\t\tfor (var knownKey in this.knownPropertyPaths) {\r\n\t\t\t\t\toldKnownPropertyPaths[knownKey] = true;\r\n\t\t\t\t\tdelete oldUnknownPropertyPaths[knownKey];\r\n\t\t\t\t}\r\n\t\t\t\tfor (var unknownKey in this.unknownPropertyPaths) {\r\n\t\t\t\t\tif (!oldKnownPropertyPaths[unknownKey]) {\r\n\t\t\t\t\t\toldUnknownPropertyPaths[unknownKey] = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\t// We need to continue looping so we catch all the property definitions, but we don't want to return an error\r\n\t\t\t\terrorAtEnd = false;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tif (error) {\r\n\t\t\terrors.push(error.prefixWith(null, \"\" + i).prefixWith(null, \"anyOf\"));\r\n\t\t}\r\n\t}\r\n\tif (this.trackUnknownProperties) {\r\n\t\tthis.unknownPropertyPaths = oldUnknownPropertyPaths;\r\n\t\tthis.knownPropertyPaths = oldKnownPropertyPaths;\r\n\t}\r\n\tif (errorAtEnd) {\r\n\t\terrors = errors.concat(this.errors.slice(startErrorCount));\r\n\t\tthis.errors = this.errors.slice(0, startErrorCount);\r\n\t\treturn this.createError(ErrorCodes.ANY_OF_MISSING, {}, \"\", \"/anyOf\", errors, data, schema);\r\n\t}\r\n};\r\n\r\nValidatorContext.prototype.validateOneOf = function validateOneOf(data, schema, dataPointerPath) {\r\n\tif (schema.oneOf === undefined) {\r\n\t\treturn null;\r\n\t}\r\n\tvar validIndex = null;\r\n\tvar errors = [];\r\n\tvar startErrorCount = this.errors.length;\r\n\tvar oldUnknownPropertyPaths, oldKnownPropertyPaths;\r\n\tif (this.trackUnknownProperties) {\r\n\t\toldUnknownPropertyPaths = this.unknownPropertyPaths;\r\n\t\toldKnownPropertyPaths = this.knownPropertyPaths;\r\n\t}\r\n\tfor (var i = 0; i < schema.oneOf.length; i++) {\r\n\t\tif (this.trackUnknownProperties) {\r\n\t\t\tthis.unknownPropertyPaths = {};\r\n\t\t\tthis.knownPropertyPaths = {};\r\n\t\t}\r\n\t\tvar subSchema = schema.oneOf[i];\r\n\r\n\t\tvar errorCount = this.errors.length;\r\n\t\tvar error = this.validateAll(data, subSchema, [], [\"oneOf\", i], dataPointerPath);\r\n\r\n\t\tif (error === null && errorCount === this.errors.length) {\r\n\t\t\tif (validIndex === null) {\r\n\t\t\t\tvalidIndex = i;\r\n\t\t\t} else {\r\n\t\t\t\tthis.errors = this.errors.slice(0, startErrorCount);\r\n\t\t\t\treturn this.createError(ErrorCodes.ONE_OF_MULTIPLE, {index1: validIndex, index2: i}, \"\", \"/oneOf\", null, data, schema);\r\n\t\t\t}\r\n\t\t\tif (this.trackUnknownProperties) {\r\n\t\t\t\tfor (var knownKey in this.knownPropertyPaths) {\r\n\t\t\t\t\toldKnownPropertyPaths[knownKey] = true;\r\n\t\t\t\t\tdelete oldUnknownPropertyPaths[knownKey];\r\n\t\t\t\t}\r\n\t\t\t\tfor (var unknownKey in this.unknownPropertyPaths) {\r\n\t\t\t\t\tif (!oldKnownPropertyPaths[unknownKey]) {\r\n\t\t\t\t\t\toldUnknownPropertyPaths[unknownKey] = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} else if (error) {\r\n\t\t\terrors.push(error);\r\n\t\t}\r\n\t}\r\n\tif (this.trackUnknownProperties) {\r\n\t\tthis.unknownPropertyPaths = oldUnknownPropertyPaths;\r\n\t\tthis.knownPropertyPaths = oldKnownPropertyPaths;\r\n\t}\r\n\tif (validIndex === null) {\r\n\t\terrors = errors.concat(this.errors.slice(startErrorCount));\r\n\t\tthis.errors = this.errors.slice(0, startErrorCount);\r\n\t\treturn this.createError(ErrorCodes.ONE_OF_MISSING, {}, \"\", \"/oneOf\", errors, data, schema);\r\n\t} else {\r\n\t\tthis.errors = this.errors.slice(0, startErrorCount);\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.validateNot = function validateNot(data, schema, dataPointerPath) {\r\n\tif (schema.not === undefined) {\r\n\t\treturn null;\r\n\t}\r\n\tvar oldErrorCount = this.errors.length;\r\n\tvar oldUnknownPropertyPaths, oldKnownPropertyPaths;\r\n\tif (this.trackUnknownProperties) {\r\n\t\toldUnknownPropertyPaths = this.unknownPropertyPaths;\r\n\t\toldKnownPropertyPaths = this.knownPropertyPaths;\r\n\t\tthis.unknownPropertyPaths = {};\r\n\t\tthis.knownPropertyPaths = {};\r\n\t}\r\n\tvar error = this.validateAll(data, schema.not, null, null, dataPointerPath);\r\n\tvar notErrors = this.errors.slice(oldErrorCount);\r\n\tthis.errors = this.errors.slice(0, oldErrorCount);\r\n\tif (this.trackUnknownProperties) {\r\n\t\tthis.unknownPropertyPaths = oldUnknownPropertyPaths;\r\n\t\tthis.knownPropertyPaths = oldKnownPropertyPaths;\r\n\t}\r\n\tif (error === null && notErrors.length === 0) {\r\n\t\treturn this.createError(ErrorCodes.NOT_PASSED, {}, \"\", \"/not\", null, data, schema);\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.validateHypermedia = function validateCombinations(data, schema, dataPointerPath) {\r\n\tif (!schema.links) {\r\n\t\treturn null;\r\n\t}\r\n\tvar error;\r\n\tfor (var i = 0; i < schema.links.length; i++) {\r\n\t\tvar ldo = schema.links[i];\r\n\t\tif (ldo.rel === \"describedby\") {\r\n\t\t\tvar template = new UriTemplate(ldo.href);\r\n\t\t\tvar allPresent = true;\r\n\t\t\tfor (var j = 0; j < template.varNames.length; j++) {\r\n\t\t\t\tif (!(template.varNames[j] in data)) {\r\n\t\t\t\t\tallPresent = false;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (allPresent) {\r\n\t\t\t\tvar schemaUrl = template.fillFromObject(data);\r\n\t\t\t\tvar subSchema = {\"$ref\": schemaUrl};\r\n\t\t\t\tif (error = this.validateAll(data, subSchema, [], [\"links\", i], dataPointerPath)) {\r\n\t\t\t\t\treturn error;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n};\r\n\r\n// parseURI() and resolveUrl() are from https://gist.github.com/1088850\r\n// - released as public domain by author (\"Yaffle\") - see comments on gist\r\n\r\nfunction parseURI(url) {\r\n\tvar m = String(url).replace(/^\\s+|\\s+$/g, '').match(/^([^:\\/?#]+:)?(\\/\\/(?:[^:@]*(?::[^:@]*)?@)?(([^:\\/?#]*)(?::(\\d*))?))?([^?#]*)(\\?[^#]*)?(#[\\s\\S]*)?/);\r\n\t// authority = '//' + user + ':' + pass '@' + hostname + ':' port\r\n\treturn (m ? {\r\n\t\thref : m[0] || '',\r\n\t\tprotocol : m[1] || '',\r\n\t\tauthority: m[2] || '',\r\n\t\thost : m[3] || '',\r\n\t\thostname : m[4] || '',\r\n\t\tport : m[5] || '',\r\n\t\tpathname : m[6] || '',\r\n\t\tsearch : m[7] || '',\r\n\t\thash : m[8] || ''\r\n\t} : null);\r\n}\r\n\r\nfunction resolveUrl(base, href) {// RFC 3986\r\n\r\n\tfunction removeDotSegments(input) {\r\n\t\tvar output = [];\r\n\t\tinput.replace(/^(\\.\\.?(\\/|$))+/, '')\r\n\t\t\t.replace(/\\/(\\.(\\/|$))+/g, '/')\r\n\t\t\t.replace(/\\/\\.\\.$/, '/../')\r\n\t\t\t.replace(/\\/?[^\\/]*/g, function (p) {\r\n\t\t\t\tif (p === '/..') {\r\n\t\t\t\t\toutput.pop();\r\n\t\t\t\t} else {\r\n\t\t\t\t\toutput.push(p);\r\n\t\t\t\t}\r\n\t\t});\r\n\t\treturn output.join('').replace(/^\\//, input.charAt(0) === '/' ? '/' : '');\r\n\t}\r\n\r\n\thref = parseURI(href || '');\r\n\tbase = parseURI(base || '');\r\n\r\n\treturn !href || !base ? null : (href.protocol || base.protocol) +\r\n\t\t(href.protocol || href.authority ? href.authority : base.authority) +\r\n\t\tremoveDotSegments(href.protocol || href.authority || href.pathname.charAt(0) === '/' ? href.pathname : (href.pathname ? ((base.authority && !base.pathname ? '/' : '') + base.pathname.slice(0, base.pathname.lastIndexOf('/') + 1) + href.pathname) : base.pathname)) +\r\n\t\t(href.protocol || href.authority || href.pathname ? href.search : (href.search || base.search)) +\r\n\t\thref.hash;\r\n}\r\n\r\nfunction getDocumentUri(uri) {\r\n\treturn uri.split('#')[0];\r\n}\r\nfunction normSchema(schema, baseUri) {\r\n\tif (schema && typeof schema === \"object\") {\r\n\t\tif (baseUri === undefined) {\r\n\t\t\tbaseUri = schema.id;\r\n\t\t} else if (typeof schema.id === \"string\") {\r\n\t\t\tbaseUri = resolveUrl(baseUri, schema.id);\r\n\t\t\tschema.id = baseUri;\r\n\t\t}\r\n\t\tif (Array.isArray(schema)) {\r\n\t\t\tfor (var i = 0; i < schema.length; i++) {\r\n\t\t\t\tnormSchema(schema[i], baseUri);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tif (typeof schema['$ref'] === \"string\") {\r\n\t\t\t\tschema['$ref'] = resolveUrl(baseUri, schema['$ref']);\r\n\t\t\t}\r\n\t\t\tfor (var key in schema) {\r\n\t\t\t\tif (key !== \"enum\") {\r\n\t\t\t\t\tnormSchema(schema[key], baseUri);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunction defaultErrorReporter(language) {\r\n\tlanguage = language || 'en';\r\n\r\n\tvar errorMessages = languages[language];\r\n\r\n\treturn function (error) {\r\n\t\tvar messageTemplate = errorMessages[error.code] || ErrorMessagesDefault[error.code];\r\n\t\tif (typeof messageTemplate !== 'string') {\r\n\t\t\treturn \"Unknown error code \" + error.code + \": \" + JSON.stringify(error.messageParams);\r\n\t\t}\r\n\t\tvar messageParams = error.params;\r\n\t\t// Adapted from Crockford's supplant()\r\n\t\treturn messageTemplate.replace(/\\{([^{}]*)\\}/g, function (whole, varName) {\r\n\t\t\tvar subValue = messageParams[varName];\r\n\t\t\treturn typeof subValue === 'string' || typeof subValue === 'number' ? subValue : whole;\r\n\t\t});\r\n\t};\r\n}\r\n\r\nvar ErrorCodes = {\r\n\tINVALID_TYPE: 0,\r\n\tENUM_MISMATCH: 1,\r\n\tANY_OF_MISSING: 10,\r\n\tONE_OF_MISSING: 11,\r\n\tONE_OF_MULTIPLE: 12,\r\n\tNOT_PASSED: 13,\r\n\t// Numeric errors\r\n\tNUMBER_MULTIPLE_OF: 100,\r\n\tNUMBER_MINIMUM: 101,\r\n\tNUMBER_MINIMUM_EXCLUSIVE: 102,\r\n\tNUMBER_MAXIMUM: 103,\r\n\tNUMBER_MAXIMUM_EXCLUSIVE: 104,\r\n\tNUMBER_NOT_A_NUMBER: 105,\r\n\t// String errors\r\n\tSTRING_LENGTH_SHORT: 200,\r\n\tSTRING_LENGTH_LONG: 201,\r\n\tSTRING_PATTERN: 202,\r\n\t// Object errors\r\n\tOBJECT_PROPERTIES_MINIMUM: 300,\r\n\tOBJECT_PROPERTIES_MAXIMUM: 301,\r\n\tOBJECT_REQUIRED: 302,\r\n\tOBJECT_ADDITIONAL_PROPERTIES: 303,\r\n\tOBJECT_DEPENDENCY_KEY: 304,\r\n\t// Array errors\r\n\tARRAY_LENGTH_SHORT: 400,\r\n\tARRAY_LENGTH_LONG: 401,\r\n\tARRAY_UNIQUE: 402,\r\n\tARRAY_ADDITIONAL_ITEMS: 403,\r\n\t// Custom/user-defined errors\r\n\tFORMAT_CUSTOM: 500,\r\n\tKEYWORD_CUSTOM: 501,\r\n\t// Schema structure\r\n\tCIRCULAR_REFERENCE: 600,\r\n\t// Non-standard validation options\r\n\tUNKNOWN_PROPERTY: 1000\r\n};\r\nvar ErrorCodeLookup = {};\r\nfor (var key in ErrorCodes) {\r\n\tErrorCodeLookup[ErrorCodes[key]] = key;\r\n}\r\nvar ErrorMessagesDefault = {\r\n\tINVALID_TYPE: \"Invalid type: {type} (expected {expected})\",\r\n\tENUM_MISMATCH: \"No enum match for: {value}\",\r\n\tANY_OF_MISSING: \"Data does not match any schemas from \\\"anyOf\\\"\",\r\n\tONE_OF_MISSING: \"Data does not match any schemas from \\\"oneOf\\\"\",\r\n\tONE_OF_MULTIPLE: \"Data is valid against more than one schema from \\\"oneOf\\\": indices {index1} and {index2}\",\r\n\tNOT_PASSED: \"Data matches schema from \\\"not\\\"\",\r\n\t// Numeric errors\r\n\tNUMBER_MULTIPLE_OF: \"Value {value} is not a multiple of {multipleOf}\",\r\n\tNUMBER_MINIMUM: \"Value {value} is less than minimum {minimum}\",\r\n\tNUMBER_MINIMUM_EXCLUSIVE: \"Value {value} is equal to exclusive minimum {minimum}\",\r\n\tNUMBER_MAXIMUM: \"Value {value} is greater than maximum {maximum}\",\r\n\tNUMBER_MAXIMUM_EXCLUSIVE: \"Value {value} is equal to exclusive maximum {maximum}\",\r\n\tNUMBER_NOT_A_NUMBER: \"Value {value} is not a valid number\",\r\n\t// String errors\r\n\tSTRING_LENGTH_SHORT: \"String is too short ({length} chars), minimum {minimum}\",\r\n\tSTRING_LENGTH_LONG: \"String is too long ({length} chars), maximum {maximum}\",\r\n\tSTRING_PATTERN: \"String does not match pattern: {pattern}\",\r\n\t// Object errors\r\n\tOBJECT_PROPERTIES_MINIMUM: \"Too few properties defined ({propertyCount}), minimum {minimum}\",\r\n\tOBJECT_PROPERTIES_MAXIMUM: \"Too many properties defined ({propertyCount}), maximum {maximum}\",\r\n\tOBJECT_REQUIRED: \"Missing required property: {key}\",\r\n\tOBJECT_ADDITIONAL_PROPERTIES: \"Additional properties not allowed\",\r\n\tOBJECT_DEPENDENCY_KEY: \"Dependency failed - key must exist: {missing} (due to key: {key})\",\r\n\t// Array errors\r\n\tARRAY_LENGTH_SHORT: \"Array is too short ({length}), minimum {minimum}\",\r\n\tARRAY_LENGTH_LONG: \"Array is too long ({length}), maximum {maximum}\",\r\n\tARRAY_UNIQUE: \"Array items are not unique (indices {match1} and {match2})\",\r\n\tARRAY_ADDITIONAL_ITEMS: \"Additional items not allowed\",\r\n\t// Format errors\r\n\tFORMAT_CUSTOM: \"Format validation failed ({message})\",\r\n\tKEYWORD_CUSTOM: \"Keyword failed: {key} ({message})\",\r\n\t// Schema structure\r\n\tCIRCULAR_REFERENCE: \"Circular $refs: {urls}\",\r\n\t// Non-standard validation options\r\n\tUNKNOWN_PROPERTY: \"Unknown property (not in schema)\"\r\n};\r\n\r\nfunction ValidationError(code, params, dataPath, schemaPath, subErrors) {\r\n\tError.call(this);\r\n\tif (code === undefined) {\r\n\t\tthrow new Error (\"No error code supplied: \" + schemaPath);\r\n\t}\r\n\tthis.message = '';\r\n\tthis.params = params;\r\n\tthis.code = code;\r\n\tthis.dataPath = dataPath || \"\";\r\n\tthis.schemaPath = schemaPath || \"\";\r\n\tthis.subErrors = subErrors || null;\r\n\r\n\tvar err = new Error(this.message);\r\n\tthis.stack = err.stack || err.stacktrace;\r\n\tif (!this.stack) {\r\n\t\ttry {\r\n\t\t\tthrow err;\r\n\t\t}\r\n\t\tcatch(err) {\r\n\t\t\tthis.stack = err.stack || err.stacktrace;\r\n\t\t}\r\n\t}\r\n}\r\nValidationError.prototype = Object.create(Error.prototype);\r\nValidationError.prototype.constructor = ValidationError;\r\nValidationError.prototype.name = 'ValidationError';\r\n\r\nValidationError.prototype.prefixWith = function (dataPrefix, schemaPrefix) {\r\n\tif (dataPrefix !== null) {\r\n\t\tdataPrefix = dataPrefix.replace(/~/g, \"~0\").replace(/\\//g, \"~1\");\r\n\t\tthis.dataPath = \"/\" + dataPrefix + this.dataPath;\r\n\t}\r\n\tif (schemaPrefix !== null) {\r\n\t\tschemaPrefix = schemaPrefix.replace(/~/g, \"~0\").replace(/\\//g, \"~1\");\r\n\t\tthis.schemaPath = \"/\" + schemaPrefix + this.schemaPath;\r\n\t}\r\n\tif (this.subErrors !== null) {\r\n\t\tfor (var i = 0; i < this.subErrors.length; i++) {\r\n\t\t\tthis.subErrors[i].prefixWith(dataPrefix, schemaPrefix);\r\n\t\t}\r\n\t}\r\n\treturn this;\r\n};\r\n\r\nfunction isTrustedUrl(baseUrl, testUrl) {\r\n\tif(testUrl.substring(0, baseUrl.length) === baseUrl){\r\n\t\tvar remainder = testUrl.substring(baseUrl.length);\r\n\t\tif ((testUrl.length > 0 && testUrl.charAt(baseUrl.length - 1) === \"/\")\r\n\t\t\t|| remainder.charAt(0) === \"#\"\r\n\t\t\t|| remainder.charAt(0) === \"?\") {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t}\r\n\treturn false;\r\n}\r\n\r\nvar languages = {};\r\nfunction createApi(language) {\r\n\tvar globalContext = new ValidatorContext();\r\n\tvar currentLanguage;\r\n\tvar customErrorReporter;\r\n\tvar api = {\r\n\t\tsetErrorReporter: function (reporter) {\r\n\t\t\tif (typeof reporter === 'string') {\r\n\t\t\t\treturn this.language(reporter);\r\n\t\t\t}\r\n\t\t\tcustomErrorReporter = reporter;\r\n\t\t\treturn true;\r\n\t\t},\r\n\t\taddFormat: function () {\r\n\t\t\tglobalContext.addFormat.apply(globalContext, arguments);\r\n\t\t},\r\n\t\tlanguage: function (code) {\r\n\t\t\tif (!code) {\r\n\t\t\t\treturn currentLanguage;\r\n\t\t\t}\r\n\t\t\tif (!languages[code]) {\r\n\t\t\t\tcode = code.split('-')[0]; // fall back to base language\r\n\t\t\t}\r\n\t\t\tif (languages[code]) {\r\n\t\t\t\tcurrentLanguage = code;\r\n\t\t\t\treturn code; // so you can tell if fall-back has happened\r\n\t\t\t}\r\n\t\t\treturn false;\r\n\t\t},\r\n\t\taddLanguage: function (code, messageMap) {\r\n\t\t\tvar key;\r\n\t\t\tfor (key in ErrorCodes) {\r\n\t\t\t\tif (messageMap[key] && !messageMap[ErrorCodes[key]]) {\r\n\t\t\t\t\tmessageMap[ErrorCodes[key]] = messageMap[key];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tvar rootCode = code.split('-')[0];\r\n\t\t\tif (!languages[rootCode]) { // use for base language if not yet defined\r\n\t\t\t\tlanguages[code] = messageMap;\r\n\t\t\t\tlanguages[rootCode] = messageMap;\r\n\t\t\t} else {\r\n\t\t\t\tlanguages[code] = Object.create(languages[rootCode]);\r\n\t\t\t\tfor (key in messageMap) {\r\n\t\t\t\t\tif (typeof languages[rootCode][key] === 'undefined') {\r\n\t\t\t\t\t\tlanguages[rootCode][key] = messageMap[key];\r\n\t\t\t\t\t}\r\n\t\t\t\t\tlanguages[code][key] = messageMap[key];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn this;\r\n\t\t},\r\n\t\tfreshApi: function (language) {\r\n\t\t\tvar result = createApi();\r\n\t\t\tif (language) {\r\n\t\t\t\tresult.language(language);\r\n\t\t\t}\r\n\t\t\treturn result;\r\n\t\t},\r\n\t\tvalidate: function (data, schema, checkRecursive, banUnknownProperties) {\r\n\t\t\tvar def = defaultErrorReporter(currentLanguage);\r\n\t\t\tvar errorReporter = customErrorReporter ? function (error, data, schema) {\r\n\t\t\t\treturn customErrorReporter(error, data, schema) || def(error, data, schema);\r\n\t\t\t} : def;\r\n\t\t\tvar context = new ValidatorContext(globalContext, false, errorReporter, checkRecursive, banUnknownProperties);\r\n\t\t\tif (typeof schema === \"string\") {\r\n\t\t\t\tschema = {\"$ref\": schema};\r\n\t\t\t}\r\n\t\t\tcontext.addSchema(\"\", schema);\r\n\t\t\tvar error = context.validateAll(data, schema, null, null, \"\");\r\n\t\t\tif (!error && banUnknownProperties) {\r\n\t\t\t\terror = context.banUnknownProperties(data, schema);\r\n\t\t\t}\r\n\t\t\tthis.error = error;\r\n\t\t\tthis.missing = context.missing;\r\n\t\t\tthis.valid = (error === null);\r\n\t\t\treturn this.valid;\r\n\t\t},\r\n\t\tvalidateResult: function () {\r\n\t\t\tvar result = {toString: function () {\r\n\t\t\t\treturn this.valid ? 'valid' : this.error.message;\r\n\t\t\t}};\r\n\t\t\tthis.validate.apply(result, arguments);\r\n\t\t\treturn result;\r\n\t\t},\r\n\t\tvalidateMultiple: function (data, schema, checkRecursive, banUnknownProperties) {\r\n\t\t\tvar def = defaultErrorReporter(currentLanguage);\r\n\t\t\tvar errorReporter = customErrorReporter ? function (error, data, schema) {\r\n\t\t\t\treturn customErrorReporter(error, data, schema) || def(error, data, schema);\r\n\t\t\t} : def;\r\n\t\t\tvar context = new ValidatorContext(globalContext, true, errorReporter, checkRecursive, banUnknownProperties);\r\n\t\t\tif (typeof schema === \"string\") {\r\n\t\t\t\tschema = {\"$ref\": schema};\r\n\t\t\t}\r\n\t\t\tcontext.addSchema(\"\", schema);\r\n\t\t\tcontext.validateAll(data, schema, null, null, \"\");\r\n\t\t\tif (banUnknownProperties) {\r\n\t\t\t\tcontext.banUnknownProperties(data, schema);\r\n\t\t\t}\r\n\t\t\tvar result = {toString: function () {\r\n\t\t\t\treturn this.valid ? 'valid' : this.error.message;\r\n\t\t\t}};\r\n\t\t\tresult.errors = context.errors;\r\n\t\t\tresult.missing = context.missing;\r\n\t\t\tresult.valid = (result.errors.length === 0);\r\n\t\t\treturn result;\r\n\t\t},\r\n\t\taddSchema: function () {\r\n\t\t\treturn globalContext.addSchema.apply(globalContext, arguments);\r\n\t\t},\r\n\t\tgetSchema: function () {\r\n\t\t\treturn globalContext.getSchema.apply(globalContext, arguments);\r\n\t\t},\r\n\t\tgetSchemaMap: function () {\r\n\t\t\treturn globalContext.getSchemaMap.apply(globalContext, arguments);\r\n\t\t},\r\n\t\tgetSchemaUris: function () {\r\n\t\t\treturn globalContext.getSchemaUris.apply(globalContext, arguments);\r\n\t\t},\r\n\t\tgetMissingUris: function () {\r\n\t\t\treturn globalContext.getMissingUris.apply(globalContext, arguments);\r\n\t\t},\r\n\t\tdropSchemas: function () {\r\n\t\t\tglobalContext.dropSchemas.apply(globalContext, arguments);\r\n\t\t},\r\n\t\tdefineKeyword: function () {\r\n\t\t\tglobalContext.defineKeyword.apply(globalContext, arguments);\r\n\t\t},\r\n\t\tdefineError: function (codeName, codeNumber, defaultMessage) {\r\n\t\t\tif (typeof codeName !== 'string' || !/^[A-Z]+(_[A-Z]+)*$/.test(codeName)) {\r\n\t\t\t\tthrow new Error('Code name must be a string in UPPER_CASE_WITH_UNDERSCORES');\r\n\t\t\t}\r\n\t\t\tif (typeof codeNumber !== 'number' || codeNumber%1 !== 0 || codeNumber < 10000) {\r\n\t\t\t\tthrow new Error('Code number must be an integer > 10000');\r\n\t\t\t}\r\n\t\t\tif (typeof ErrorCodes[codeName] !== 'undefined') {\r\n\t\t\t\tthrow new Error('Error already defined: ' + codeName + ' as ' + ErrorCodes[codeName]);\r\n\t\t\t}\r\n\t\t\tif (typeof ErrorCodeLookup[codeNumber] !== 'undefined') {\r\n\t\t\t\tthrow new Error('Error code already used: ' + ErrorCodeLookup[codeNumber] + ' as ' + codeNumber);\r\n\t\t\t}\r\n\t\t\tErrorCodes[codeName] = codeNumber;\r\n\t\t\tErrorCodeLookup[codeNumber] = codeName;\r\n\t\t\tErrorMessagesDefault[codeName] = ErrorMessagesDefault[codeNumber] = defaultMessage;\r\n\t\t\tfor (var langCode in languages) {\r\n\t\t\t\tvar language = languages[langCode];\r\n\t\t\t\tif (language[codeName]) {\r\n\t\t\t\t\tlanguage[codeNumber] = language[codeNumber] || language[codeName];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t},\r\n\t\treset: function () {\r\n\t\t\tglobalContext.reset();\r\n\t\t\tthis.error = null;\r\n\t\t\tthis.missing = [];\r\n\t\t\tthis.valid = true;\r\n\t\t},\r\n\t\tmissing: [],\r\n\t\terror: null,\r\n\t\tvalid: true,\r\n\t\tnormSchema: normSchema,\r\n\t\tresolveUrl: resolveUrl,\r\n\t\tgetDocumentUri: getDocumentUri,\r\n\t\terrorCodes: ErrorCodes\r\n\t};\r\n\tapi.language(language || 'en');\r\n\treturn api;\r\n}\r\n\r\nvar tv4 = createApi();\r\ntv4.addLanguage('en-gb', ErrorMessagesDefault);\r\n\r\n//legacy property\r\ntv4.tv4 = tv4;\r\n\r\nreturn tv4; // used by _header.js to globalise.\r\n\r\n}));","import type { JsonSchemas } from './interfaces/json_schema';\n/**\n * - Manages and validates types of remoteStorage objects, using JSON-LD and\n * JSON Schema\n * - Adds schema declaration/validation methods to BaseClient instances.\n **/\nexport class BaseClientTypes {\n /**\n * -> \n */\n uris: { [key: string]: string } = {};\n\n /**\n * Contains schema objects of all types known to the BaseClient instance\n *\n * -> \n */\n schemas: JsonSchemas = {};\n\n /**\n * -> \n */\n aliases: { [key: string]: string } = {};\n\n /**\n * Called via public function BaseClient.declareType()\n *\n * @private\n */\n declare (moduleName: string, alias: string, uri: string, schema: tv4.JsonSchema): void {\n const fullAlias = moduleName + '/' + alias;\n\n if (schema.extends) {\n const parts = schema.extends.split('/');\n const extendedAlias = (parts.length === 1)\n ? moduleName + '/' + parts.shift()\n : parts.join('/');\n\n const extendedUri = this.uris[extendedAlias];\n if (!extendedUri) {\n throw \"Type '\" + fullAlias + \"' tries to extend unknown schema '\" + extendedAlias + \"'\";\n }\n schema.extends = this.schemas[extendedUri];\n }\n\n this.uris[fullAlias] = uri;\n this.aliases[uri] = fullAlias;\n this.schemas[uri] = schema;\n }\n\n resolveAlias (alias: string): string {\n return this.uris[alias];\n }\n\n getSchema (uri: string): tv4.JsonSchema {\n return this.schemas[uri];\n }\n\n inScope (moduleName: string): JsonSchemas {\n const ml = moduleName.length;\n const schemas = {};\n for (const alias in this.uris) {\n if (alias.substr(0, ml + 1) === moduleName + '/') {\n const uri = this.uris[alias];\n schemas[uri] = this.schemas[uri];\n }\n }\n return schemas;\n }\n}\n\nconst Types = new BaseClientTypes();\nexport default Types;\n","class SchemaNotFound extends Error {\n constructor(uri: string) {\n super();\n const error = new Error(\"Schema not found: \" + uri);\n error.name = \"SchemaNotFound\";\n return error;\n }\n}\n\nexport = SchemaNotFound;\n","/**\n * A cache which can propagate changes up to parent folders and generate new\n * revision ids for them. The generated revision id is consistent across\n * different sessions. The keys for the cache are case-insensitive.\n *\n * @param defaultValue {string} the value that is returned for all keys that\n * don't exist in the cache\n * @class\n */\n\nclass RevisionCache {\n defaultValue: string;\n\n private _itemsRev: { [key: string]: any } = {};\n private _storage: { [key: string]: string } = {};\n private _canPropagate = false;\n\n constructor(defaultValue: string) {\n this.defaultValue = defaultValue;\n this.activatePropagation();\n }\n\n\n /**\n * Get a value from the cache or defaultValue, if the key is not in the\n * cache\n */\n get(key: string): string {\n key = key.toLowerCase();\n let stored = this._storage[key];\n if (typeof stored === 'undefined') {\n stored = this.defaultValue;\n this._storage[key] = stored;\n }\n return stored;\n }\n\n /**\n * Set a value\n */\n set(key: string, value): unknown {\n key = key.toLowerCase();\n if (this._storage[key] === value) {\n return value;\n }\n this._storage[key] = value;\n if (!value) {\n delete this._itemsRev[key];\n }\n this._updateParentFolderItemRev(key, value);\n if (this._canPropagate) {\n this._propagate(key);\n }\n return value;\n }\n\n /**\n * Delete a value\n */\n delete(key: string): unknown {\n return this.set(key, null);\n }\n\n /**\n * Disables automatic update of folder revisions when a key value is updated\n */\n deactivatePropagation(): true {\n this._canPropagate = false;\n return true;\n }\n\n /**\n * Enables automatic update of folder revisions when a key value is updated\n * and refreshes the folder revision ids for entire tree.\n */\n activatePropagation(): true {\n if (this._canPropagate) {\n return true;\n }\n this._generateFolderRev(\"/\");\n this._canPropagate = true;\n return true;\n }\n\n /**\n * Returns a hash code for a string.\n */\n private _hashCode(str: string): number {\n let hash = 0;\n if (str.length === 0) {\n return hash;\n }\n for (let i = 0; i < str.length; i++) {\n const chr = str.charCodeAt(i);\n // eslint-disable-next-line no-bitwise\n hash = ((hash << 5) - hash) + chr;\n // eslint-disable-next-line no-bitwise\n hash |= 0; // Convert to 32bit integer\n }\n return hash;\n }\n\n /**\n * Takes an array of strings and returns a hash of the items\n */\n private _generateHash(items: string[]): string {\n // We sort the items before joining them to ensure correct hash generation\n // every time\n const files = items.sort().join('|');\n const hash = \"\" + this._hashCode(files);\n return hash;\n }\n\n /**\n * Update the revision of a key in it's parent folder data\n */\n private _updateParentFolderItemRev(key: string, rev): void {\n if (key !== '/') {\n const parentFolder = this._getParentFolder(key);\n if (!this._itemsRev[parentFolder]) {\n this._itemsRev[parentFolder] = {};\n }\n const parentFolderItemsRev = this._itemsRev[parentFolder];\n if (!rev) {\n delete parentFolderItemsRev[key];\n } else {\n parentFolderItemsRev[key] = rev;\n }\n //reset revision until root\n this._updateParentFolderItemRev(parentFolder, this.defaultValue);\n }\n }\n\n private _getParentFolder(key: string): string {\n return key.substr(0, key.lastIndexOf('/', key.length - 2) + 1);\n }\n\n /**\n * Propagate the changes to the parent folders and generate new revision ids\n * for them\n */\n private _propagate(key: string): void {\n if (key !== '/') {\n const parentFolder = this._getParentFolder(key);\n const parentFolderItemsRev = this._itemsRev[parentFolder];\n const hashItems = [];\n for (const path in parentFolderItemsRev) {\n hashItems.push(parentFolderItemsRev[path]);\n }\n const newRev = this._generateHash(hashItems);\n this.set(parentFolder, newRev);\n }\n }\n\n /**\n * Generate revision id for a folder and it's subfolders, by hashing it's\n * listing\n */\n private _generateFolderRev(folder: string): string {\n const itemsRev = this._itemsRev[folder];\n let hash = this.defaultValue;\n if (itemsRev) {\n const hashItems = [];\n for (const path in itemsRev) {\n const isDir: boolean = (path.substr(-1) === '/');\n let hashItem;\n if (isDir) {\n hashItem = this._generateFolderRev(path);\n } else {\n hashItem = itemsRev[path];\n }\n hashItems.push(hashItem);\n }\n if (hashItems.length > 0) {\n hash = this._generateHash(hashItems);\n }\n }\n this.set(folder, hash);\n return hash;\n }\n}\n\nexport = RevisionCache;\n","/* global define */\n/*!\n * webfinger.js\n * http://github.com/silverbucket/webfinger.js\n *\n * Developed and Maintained by:\n * Nick Jennings \n *\n * webfinger.js is released under the AGPL (see LICENSE).\n *\n * You don't have to do anything special to choose one license or the other and you don't\n * have to notify anyone which license you are using.\n * Please see the corresponding license file for details of these licenses.\n * You are free to use, modify and distribute this software, but all copyright\n * information must remain.\n *\n */\n\nif (typeof fetch !== 'function' && typeof XMLHttpRequest !== 'function') {\n // XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;\n XMLHttpRequest = require('xhr2');\n}\n\n(function (global) {\n\n // URI to property name map\n var LINK_URI_MAPS = {\n 'http://webfist.org/spec/rel': 'webfist',\n 'http://webfinger.net/rel/avatar': 'avatar',\n 'remotestorage': 'remotestorage',\n 'http://tools.ietf.org/id/draft-dejong-remotestorage': 'remotestorage',\n 'remoteStorage': 'remotestorage',\n 'http://www.packetizer.com/rel/share': 'share',\n 'http://webfinger.net/rel/profile-page': 'profile',\n 'me': 'profile',\n 'vcard': 'vcard',\n 'blog': 'blog',\n 'http://packetizer.com/rel/blog': 'blog',\n 'http://schemas.google.com/g/2010#updates-from': 'updates',\n 'https://camlistore.org/rel/server': 'camilstore'\n };\n\n var LINK_PROPERTIES = {\n 'avatar': [],\n 'remotestorage': [],\n 'blog': [],\n 'vcard': [],\n 'updates': [],\n 'share': [],\n 'profile': [],\n 'webfist': [],\n 'camlistore': []\n };\n\n // list of endpoints to try, fallback from beginning to end.\n var URIS = ['webfinger', 'host-meta', 'host-meta.json'];\n\n function generateErrorObject(obj) {\n obj.toString = function () {\n return this.message;\n };\n return obj;\n }\n\n // given a URL ensures it's HTTPS.\n // returns false for null string or non-HTTPS URL.\n function isSecure(url) {\n if (typeof url !== 'string') {\n return false;\n }\n var parts = url.split('://');\n if (parts[0] === 'https') {\n return true;\n }\n return false;\n }\n\n /**\n * Function: WebFinger\n *\n * WebFinger constructor\n *\n * Returns:\n *\n * return WebFinger object\n */\n function WebFinger(config) {\n if (typeof config !== 'object') {\n config = {};\n }\n\n this.config = {\n tls_only: (typeof config.tls_only !== 'undefined') ? config.tls_only : true,\n webfist_fallback: (typeof config.webfist_fallback !== 'undefined') ? config.webfist_fallback : false,\n uri_fallback: (typeof config.uri_fallback !== 'undefined') ? config.uri_fallback : false,\n request_timeout: (typeof config.request_timeout !== 'undefined') ? config.request_timeout : 10000\n };\n }\n\n // make an http request and look for JRD response, fails if request fails\n // or response not json.\n WebFinger.prototype.__fetchJRD = function (url, errorHandler, successHandler) {\n if (typeof fetch === 'function') {\n return this.__fetchJRD_fetch(url, errorHandler, successHandler);\n } else if (typeof XMLHttpRequest === 'function') {\n return this.__fetchJRD_XHR(url, errorHandler, successHandler);\n } else {\n throw new Error(\"add a polyfill for fetch or XMLHttpRequest\");\n }\n };\n WebFinger.prototype.__fetchJRD_fetch = function (url, errorHandler, successHandler) {\n var webfinger = this;\n var abortController;\n if (typeof AbortController === 'function') {\n abortController = new AbortController();\n }\n var networkPromise = fetch(url, {\n headers: {'Accept': 'application/jrd+json, application/json'},\n signal: abortController ? abortController.signal : undefined\n }).\n then(function (response) {\n if (response.ok) {\n return response.text();\n } else if (response.status === 404) {\n throw generateErrorObject({\n message: 'resource not found',\n url: url,\n status: response.status\n });\n } else { // other HTTP status (redirects are handled transparently)\n throw generateErrorObject({\n message: 'error during request',\n url: url,\n status: response.status\n });\n }\n },\n function (err) { // connection refused, etc.\n throw generateErrorObject({\n message: 'error during request',\n url: url,\n status: undefined,\n err: err\n })\n }).\n then(function (responseText) {\n if (webfinger.__isValidJSON(responseText)) {\n return responseText;\n } else {\n throw generateErrorObject({\n message: 'invalid json',\n url: url,\n status: undefined\n });\n }\n });\n\n var timeoutPromise = new Promise(function (resolve, reject) {\n setTimeout(function () {\n reject(generateErrorObject({\n message: 'request timed out',\n url: url,\n status: undefined\n }));\n if (abortController) {\n abortController.abort();\n }\n }, webfinger.config.request_timeout);\n });\n\n Promise.race([networkPromise, timeoutPromise]).\n then(function (responseText) {\n successHandler(responseText);\n }).catch(function (err) {\n errorHandler(err);\n });\n };\n WebFinger.prototype.__fetchJRD_XHR = function (url, errorHandler, successHandler) {\n var self = this;\n var handlerSpent = false;\n var xhr = new XMLHttpRequest();\n\n function __processState() {\n if (handlerSpent){\n return;\n }else{\n handlerSpent = true;\n }\n\n if (xhr.status === 200) {\n if (self.__isValidJSON(xhr.responseText)) {\n return successHandler(xhr.responseText);\n } else {\n return errorHandler(generateErrorObject({\n message: 'invalid json',\n url: url,\n status: xhr.status\n }));\n }\n } else if (xhr.status === 404) {\n return errorHandler(generateErrorObject({\n message: 'resource not found',\n url: url,\n status: xhr.status\n }));\n } else if ((xhr.status >= 301) && (xhr.status <= 302)) {\n var location = xhr.getResponseHeader('Location');\n if (isSecure(location)) {\n return __makeRequest(location); // follow redirect\n } else {\n return errorHandler(generateErrorObject({\n message: 'no redirect URL found',\n url: url,\n status: xhr.status\n }));\n }\n } else {\n return errorHandler(generateErrorObject({\n message: 'error during request',\n url: url,\n status: xhr.status\n }));\n }\n }\n\n function __makeRequest() {\n xhr.onreadystatechange = function () {\n if (xhr.readyState === 4) {\n __processState();\n }\n };\n\n xhr.onload = function () {\n __processState();\n };\n\n xhr.ontimeout = function () {\n return errorHandler(generateErrorObject({\n message: 'request timed out',\n url: url,\n status: xhr.status\n }));\n };\n\n xhr.open('GET', url, true);\n xhr.timeout = self.config.request_timeout;\n xhr.setRequestHeader('Accept', 'application/jrd+json, application/json');\n xhr.send();\n }\n\n return __makeRequest();\n };\n\n WebFinger.prototype.__isValidJSON = function (str) {\n try {\n JSON.parse(str);\n } catch (e) {\n return false;\n }\n return true;\n };\n\n WebFinger.prototype.__isLocalhost = function (host) {\n var local = /^localhost(\\.localdomain)?(\\:[0-9]+)?$/;\n return local.test(host);\n };\n\n // processes JRD object as if it's a webfinger response object\n // looks for known properties and adds them to profile datat struct.\n WebFinger.prototype.__processJRD = function (URL, JRD, errorHandler, successHandler) {\n var parsedJRD = JSON.parse(JRD);\n if ((typeof parsedJRD !== 'object') ||\n (typeof parsedJRD.links !== 'object')) {\n if (typeof parsedJRD.error !== 'undefined') {\n return errorHandler(generateErrorObject({ message: parsedJRD.error, request: URL }));\n } else {\n return errorHandler(generateErrorObject({ message: 'unknown response from server', request: URL }));\n }\n }\n\n var links = parsedJRD.links;\n if (!Array.isArray(links)) {\n links = [];\n }\n var result = { // webfinger JRD - object, json, and our own indexing\n object: parsedJRD,\n json: JRD,\n idx: {}\n };\n\n result.idx.properties = {\n 'name': undefined\n };\n result.idx.links = JSON.parse(JSON.stringify(LINK_PROPERTIES));\n\n // process links\n links.map(function (link, i) {\n if (LINK_URI_MAPS.hasOwnProperty(link.rel)) {\n if (result.idx.links[LINK_URI_MAPS[link.rel]]) {\n var entry = {};\n Object.keys(link).map(function (item, n) {\n entry[item] = link[item];\n });\n result.idx.links[LINK_URI_MAPS[link.rel]].push(entry);\n }\n }\n });\n\n // process properties\n var props = JSON.parse(JRD).properties;\n for (var key in props) {\n if (props.hasOwnProperty(key)) {\n if (key === 'http://packetizer.com/ns/name') {\n result.idx.properties.name = props[key];\n }\n }\n }\n return successHandler(result);\n };\n\n WebFinger.prototype.lookup = function (address, cb) {\n if (typeof address !== 'string') {\n throw new Error('first parameter must be a user address');\n } else if (typeof cb !== 'function') {\n throw new Error('second parameter must be a callback');\n }\n\n var self = this;\n var host = '';\n if (address.indexOf('://') > -1) {\n // other uri format\n host = address.replace(/ /g,'').split('/')[2];\n } else {\n // useraddress\n host = address.replace(/ /g,'').split('@')[1];\n }\n var uri_index = 0; // track which URIS we've tried already\n var protocol = 'https'; // we use https by default\n\n if (self.__isLocalhost(host)) {\n protocol = 'http';\n }\n\n function __buildURL() {\n var uri = '';\n if (! address.split('://')[1]) {\n // the URI has not been defined, default to acct\n uri = 'acct:';\n }\n return protocol + '://' + host + '/.well-known/' +\n URIS[uri_index] + '?resource=' + uri + address;\n }\n\n // control flow for failures, what to do in various cases, etc.\n function __fallbackChecks(err) {\n if ((self.config.uri_fallback) && (host !== 'webfist.org') && (uri_index !== URIS.length - 1)) { // we have uris left to try\n uri_index = uri_index + 1;\n return __call();\n } else if ((!self.config.tls_only) && (protocol === 'https')) { // try normal http\n uri_index = 0;\n protocol = 'http';\n return __call();\n } else if ((self.config.webfist_fallback) && (host !== 'webfist.org')) { // webfist attempt\n uri_index = 0;\n protocol = 'http';\n host = 'webfist.org';\n // webfist will\n // 1. make a query to the webfist server for the users account\n // 2. from the response, get a link to the actual webfinger json data\n // (stored somewhere in control of the user)\n // 3. make a request to that url and get the json\n // 4. process it like a normal webfinger response\n var URL = __buildURL();\n self.__fetchJRD(URL, cb, function (data) { // get link to users JRD\n self.__processJRD(URL, data, cb, function (result) {\n if ((typeof result.idx.links.webfist === 'object') &&\n (typeof result.idx.links.webfist[0].href === 'string')) {\n self.__fetchJRD(result.idx.links.webfist[0].href, cb, function (JRD) {\n self.__processJRD(URL, JRD, cb, function (result) {\n return cb(null, cb);\n });\n });\n }\n });\n });\n } else {\n return cb(err);\n }\n }\n\n function __call() {\n // make request\n var URL = __buildURL();\n self.__fetchJRD(URL, __fallbackChecks, function (JRD) {\n self.__processJRD(URL, JRD, cb, function (result) { cb(null, result); });\n });\n }\n\n return setTimeout(__call, 0);\n };\n\n WebFinger.prototype.lookupLink = function (address, rel, cb) {\n if (LINK_PROPERTIES.hasOwnProperty(rel)) {\n this.lookup(address, function (err, p) {\n var links = p.idx.links[rel];\n if (err) {\n return cb(err);\n } else if (links.length === 0) {\n return cb('no links found with rel=\"' + rel + '\"');\n } else {\n return cb(null, links[0]);\n }\n });\n } else {\n return cb('unsupported rel ' + rel);\n }\n };\n\n\n\n // AMD support\n if (typeof define === 'function' && define.amd) {\n define([], function () { return WebFinger; });\n // CommonJS and Node.js module support.\n } else if (typeof exports !== 'undefined') {\n // Support Node.js specific `module.exports` (which can be a function)\n if (typeof module !== 'undefined' && module.exports) {\n exports = module.exports = WebFinger;\n }\n // But always support CommonJS module 1.1.1 spec (`exports` cannot be a function)\n exports.WebFinger = WebFinger;\n } else {\n // browser