diff --git a/build/lokijs.min.js b/build/lokijs.min.js index aba4a286..d64affad 100644 --- a/build/lokijs.min.js +++ b/build/lokijs.min.js @@ -1,4 +1,4 @@ (function(root,factory){if(typeof define==="function"&&define.amd){define([],factory)}else if(typeof exports==="object"){module.exports=factory()}else{root.loki=factory()}})(this,function(){return function(){"use strict";var hasOwnProperty=Object.prototype.hasOwnProperty;function deepFreeze(obj){var prop,i;if(Array.isArray(obj)){for(i=0;i=10)return subObj;for(prop in subObj){if(typeof subObj[prop]==="string"&&subObj[prop].indexOf("[%lktxp]")===0){pname=subObj[prop].substring(8);if(params.hasOwnProperty(pname)){subObj[prop]=params[pname]}}else if(typeof subObj[prop]==="object"){subObj[prop]=Utils.resolveTransformObject(subObj[prop],params,depth)}}return subObj},resolveTransformParams:function(transform,params){var idx,clonedStep,resolvedTransform=[];if(typeof params==="undefined")return transform;for(idx=0;idxcv2)return false;return equal}if(cv1===cv1&&cv2!==cv2){return true}if(cv2===cv2&&cv1!==cv1){return false}if(prop1prop2)return false;if(prop1==prop2)return equal;cv1=prop1.toString();cv2=prop2.toString();if(cv1t2}}cv1=Number(prop1);cv2=Number(prop2);if(cv1===cv1&&cv2===cv2){if(cv1>cv2)return true;if(cv1prop2)return true;if(prop1cv2){return true}if(cv1==cv2){return equal}return false}function sortHelper(prop1,prop2,desc){if(Comparators.aeq(prop1,prop2))return 0;if(Comparators.lt(prop1,prop2,false)){return desc?1:-1}if(Comparators.gt(prop1,prop2,false)){return desc?-1:1}return 0}function compoundeval(properties,obj1,obj2){var res=0;var prop,field,val1,val2,arr,path;for(var i=0,len=properties.length;i=paths.length){valueFound=fun(element,value,extra)}else if(Array.isArray(element)){for(var index=0,len=element.length;indexb},$jgte:function(a,b){return a>=b},$jlt:function(a,b){return a=vals[0]&&a<=vals[1]},$in:function(a,b){return b.indexOf(a)!==-1},$inSet:function(a,b){return b.has(a)},$nin:function(a,b){return b.indexOf(a)===-1},$keyin:function(a,b){return a in b},$nkeyin:function(a,b){return!(a in b)},$definedin:function(a,b){return b[a]!==undefined},$undefinedin:function(a,b){return b[a]===undefined},$regex:function(a,b){return b.test(a)},$containsString:function(a,b){return typeof a==="string"&&a.indexOf(b)!==-1},$containsNone:function(a,b){return!LokiOps.$containsAny(a,b)},$containsAny:function(a,b){var checkFn=containsCheckFn(a);if(checkFn!==null){return Array.isArray(b)?b.some(checkFn):checkFn(b)}return false},$contains:function(a,b){var checkFn=containsCheckFn(a);if(checkFn!==null){return Array.isArray(b)?b.every(checkFn):checkFn(b)}return false},$elemMatch:function(a,b){if(Array.isArray(a)){return a.some(function(item){return Object.keys(b).every(function(property){var filter=b[property];if(!(typeof filter==="object"&&filter)){filter={$eq:filter}}if(property.indexOf(".")!==-1){return dotSubScan(item,property.split("."),doQueryOp,b[property],item)}return doQueryOp(item[property],filter,item)})})}return false},$type:function(a,b,record){var type=typeof a;if(type==="object"){if(Array.isArray(a)){type="array"}else if(a instanceof Date){type="date"}}return typeof b!=="object"?type===b:doQueryOp(type,b,record)},$finite:function(a,b){return b===isFinite(a)},$size:function(a,b,record){if(Array.isArray(a)){return typeof b!=="object"?a.length===b:doQueryOp(a.length,b,record)}return false},$len:function(a,b,record){if(typeof a==="string"){return typeof b!=="object"?a.length===b:doQueryOp(a.length,b,record)}return false},$where:function(a,b){return b(a)===true},$not:function(a,b,record){return!doQueryOp(a,b,record)},$and:function(a,b,record){for(var idx=0,len=b.length;idx0){throw new Error("disableMeta option cannot be passed as true when ttl is enabled")}}for(i=0;i=0){return this.serializeCollection({delimited:options.delimited,delimiter:options.delimiter,collectionIndex:options.partition})}dbcopy=new Loki(this.filename);dbcopy.loadJSONObject(this);for(idx=0;idxcollCount){done=true}}else{currObject=JSON.parse(workarray[lineIndex]);cdb.collections[collIndex].data.push(currObject)}workarray[lineIndex++]=null}return cdb};Loki.prototype.deserializeCollection=function(destructuredSource,options){var workarray=[];var idx,len;options=options||{};if(!options.hasOwnProperty("partitioned")){options.partitioned=false}if(!options.hasOwnProperty("delimited")){options.delimited=true}if(!options.hasOwnProperty("delimiter")){options.delimiter=this.options.destructureDelimiter}if(options.delimited){workarray=destructuredSource.split(options.delimiter);workarray.pop()}else{workarray=destructuredSource}len=workarray.length;for(idx=0;idx=cdlen)doneWithPartition=true}if(pageLen>=this.options.pageSize)doneWithPage=true;if(!doneWithPage||doneWithPartition){pageBuilder+=this.options.delimiter;pageLen+=delimlen}if(doneWithPartition||doneWithPage){this.adapter.saveDatabase(keyname,pageBuilder,pageSaveCallback);return}}};function LokiFsAdapter(){try{this.fs=require("fs")}catch(e){this.fs=null}}LokiFsAdapter.prototype.loadDatabase=function loadDatabase(dbname,callback){var self=this;this.fs.stat(dbname,function(err,stats){if(!err&&stats.isFile()){self.fs.readFile(dbname,{encoding:"utf8"},function readFileCallback(err,data){if(err){callback(new Error(err))}else{callback(data)}})}else{callback(null)}})};LokiFsAdapter.prototype.saveDatabase=function saveDatabase(dbname,dbstring,callback){var self=this;var tmpdbname=dbname+"~";this.fs.writeFile(tmpdbname,dbstring,function writeFileCallback(err){if(err){callback(new Error(err))}else{self.fs.rename(tmpdbname,dbname,callback)}})};LokiFsAdapter.prototype.deleteDatabase=function deleteDatabase(dbname,callback){this.fs.unlink(dbname,function deleteDatabaseCallback(err){if(err){callback(new Error(err))}else{callback()}})};function LokiLocalStorageAdapter(){}LokiLocalStorageAdapter.prototype.loadDatabase=function loadDatabase(dbname,callback){if(localStorageAvailable()){callback(localStorage.getItem(dbname))}else{callback(new Error("localStorage is not available"))}};LokiLocalStorageAdapter.prototype.saveDatabase=function saveDatabase(dbname,dbstring,callback){if(localStorageAvailable()){localStorage.setItem(dbname,dbstring);callback(null)}else{callback(new Error("localStorage is not available"))}};LokiLocalStorageAdapter.prototype.deleteDatabase=function deleteDatabase(dbname,callback){if(localStorageAvailable()){localStorage.removeItem(dbname);callback(null)}else{callback(new Error("localStorage is not available"))}};Loki.prototype.throttledSaveDrain=function(callback,options){var self=this;var now=(new Date).getTime();if(!this.throttledSaves){callback(true)}options=options||{};if(!options.hasOwnProperty("recursiveWait")){options.recursiveWait=true}if(!options.hasOwnProperty("recursiveWaitLimit")){options.recursiveWaitLimit=false}if(!options.hasOwnProperty("recursiveWaitLimitDuration")){options.recursiveWaitLimitDuration=2e3}if(!options.hasOwnProperty("started")){options.started=(new Date).getTime()}if(this.throttledSaves&&this.throttledSavePending){if(options.recursiveWait){this.throttledCallbacks.push(function(){if(self.throttledSavePending){if(options.recursiveWaitLimit&&now-options.started>options.recursiveWaitLimitDuration){callback(false);return}self.throttledSaveDrain(callback,options);return}else{callback(true);return}})}else{this.throttledCallbacks.push(callback);return}}else{callback(true)}};Loki.prototype.loadDatabaseInternal=function(options,callback){var cFun=callback||function(err,data){if(err){throw err}},self=this;if(this.persistenceAdapter!==null){this.persistenceAdapter.loadDatabase(this.filename,function loadDatabaseCallback(dbString){if(typeof dbString==="string"){var parseSuccess=false;try{self.loadJSON(dbString,options||{});parseSuccess=true}catch(err){cFun(err)}if(parseSuccess){cFun(null);self.emit("loaded","database "+self.filename+" loaded")}}else{if(!dbString){cFun(null);self.emit("loaded","empty database "+self.filename+" loaded");return}if(dbString instanceof Error){cFun(dbString);return}if(typeof dbString==="object"){self.loadJSONObject(dbString,options||{});cFun(null);self.emit("loaded","database "+self.filename+" loaded");return}cFun("unexpected adapter response : "+dbString)}})}else{cFun(new Error("persistenceAdapter not configured"))}};Loki.prototype.loadDatabase=function(options,callback){var self=this;if(!this.throttledSaves){this.loadDatabaseInternal(options,callback);return}this.throttledSaveDrain(function(success){if(success){self.throttledSavePending=true;self.loadDatabaseInternal(options,function(err){if(self.throttledCallbacks.length===0){self.throttledSavePending=false}else{self.saveDatabase()}if(typeof callback==="function"){callback(err)}});return}else{if(typeof callback==="function"){callback(new Error("Unable to pause save throttling long enough to read database"))}}},options)};Loki.prototype.saveDatabaseInternal=function(callback){var cFun=callback||function(err){if(err){throw err}return};var self=this;if(!this.persistenceAdapter){cFun(new Error("persistenceAdapter not configured"));return}if(this.persistenceAdapter.mode==="incremental"){var lokiCopy=this.copy({removeNonSerializable:true});var cachedDirty=this.collections.map(function(collection){return[collection.dirty,collection.dirtyIds]});this.collections.forEach(function(col){col.dirty=false;col.dirtyIds=[]});this.persistenceAdapter.saveDatabase(this.filename,lokiCopy,function exportDatabaseCallback(err){if(err){self.collections.forEach(function(col,i){var cached=cachedDirty[i];col.dirty=cached[0];col.dirtyIds=col.dirtyIds.concat(cached[1])})}cFun(err)})}else if(this.persistenceAdapter.mode==="reference"&&typeof this.persistenceAdapter.exportDatabase==="function"){this.persistenceAdapter.exportDatabase(this.filename,this.copy({removeNonSerializable:true}),function exportDatabaseCallback(err){self.autosaveClearFlags();cFun(err)})}else{this.autosaveClearFlags();this.persistenceAdapter.saveDatabase(this.filename,this.serialize(),function saveDatabasecallback(err){cFun(err)})}};Loki.prototype.saveDatabase=function(callback){if(!this.throttledSaves){this.saveDatabaseInternal(callback);return}if(this.throttledSavePending){this.throttledCallbacks.push(callback);return}var localCallbacks=this.throttledCallbacks;this.throttledCallbacks=[];localCallbacks.unshift(callback);this.throttledSavePending=true;var self=this;this.saveDatabaseInternal(function(err){self.throttledSavePending=false;localCallbacks.forEach(function(pcb){if(typeof pcb==="function"){setTimeout(function(){pcb(err)},1)}});if(self.throttledCallbacks.length>0){self.saveDatabase()}})};Loki.prototype.save=Loki.prototype.saveDatabase;Loki.prototype.deleteDatabase=function(options,callback){var cFun=callback||function(err,data){if(err){throw err}};if(typeof options==="function"&&!callback){cFun=options}if(this.persistenceAdapter!==null){this.persistenceAdapter.deleteDatabase(this.filename,function deleteDatabaseCallback(err){cFun(err)})}else{cFun(new Error("persistenceAdapter not configured"))}};Loki.prototype.autosaveDirty=function(){for(var idx=0;idx0){this.filteredrows=[]}this.filterInitialized=false;return this};Resultset.prototype.toJSON=function(){var copy=this.copy();copy.collection=null;return copy};Resultset.prototype.limit=function(qty){if(!this.filterInitialized&&this.filteredrows.length===0){this.filteredrows=this.collection.prepareFullDocIndex()}var rscopy=new Resultset(this.collection);rscopy.filteredrows=this.filteredrows.slice(0,qty);rscopy.filterInitialized=true;return rscopy};Resultset.prototype.offset=function(pos){if(!this.filterInitialized&&this.filteredrows.length===0){this.filteredrows=this.collection.prepareFullDocIndex()}var rscopy=new Resultset(this.collection);rscopy.filteredrows=this.filteredrows.slice(pos);rscopy.filterInitialized=true;return rscopy};Resultset.prototype.copy=function(){var result=new Resultset(this.collection);if(this.filteredrows.length>0){result.filteredrows=this.filteredrows.slice()}result.filterInitialized=this.filterInitialized;return result};Resultset.prototype.branch=Resultset.prototype.copy;Resultset.prototype.transform=function(transform,parameters){var idx,step,rs=this;if(typeof transform==="string"){if(this.collection.transforms.hasOwnProperty(transform)){transform=this.collection.transforms[transform]}}if(typeof transform!=="object"||!Array.isArray(transform)){throw new Error("Invalid transform")}if(typeof parameters!=="undefined"){transform=Utils.resolveTransformParams(transform,parameters)}for(idx=0;idxobj2[propname])return 1;if(obj1[propname]1){return this.find({$and:filters},firstOnly)}}if(!property||queryObject==="getAll"){if(firstOnly){if(this.filterInitialized){this.filteredrows=this.filteredrows.slice(0,1)}else{this.filteredrows=this.collection.data.length>0?[0]:[];this.filterInitialized=true}}return this}if(property==="$and"||property==="$or"){this[property](queryObjectOp);if(firstOnly&&this.filteredrows.length>1){this.filteredrows=this.filteredrows.slice(0,1)}return this}if(queryObjectOp===null||(typeof queryObjectOp!=="object"||queryObjectOp instanceof Date)){operator="$eq";value=queryObjectOp}else if(typeof queryObjectOp==="object"){for(key in queryObjectOp){if(hasOwnProperty.call(queryObjectOp,key)){operator=key;value=queryObjectOp[key];break}}}else{throw new Error("Do not know what you want to do.")}if(operator==="$regex"||typeof value==="object"){value=precompileQuery(operator,value)}var usingDotNotation=property.indexOf(".")!==-1;var doIndexCheck=!this.filterInitialized;if(doIndexCheck&&this.collection.binaryIndices[property]&&indexedOps[operator]){if(this.collection.adaptiveBinaryIndices!==true){this.collection.ensureIndex(property)}searchByIndex=true;index=this.collection.binaryIndices[property]}if(!searchByIndex&&operator==="$in"&&Array.isArray(value)&&typeof Set!=="undefined"){value=new Set(value);operator="$inSet"}var fun=LokiOps[operator];var t=this.collection.data;var i=0,len=0;var filter,rowIdx=0,record;if(this.filterInitialized){filter=this.filteredrows;len=filter.length;if(usingDotNotation){property=property.split(".");for(i=0;i0;this.filterPipeline=[];if(wasFrozen){Object.freeze(this.filterPipeline)}this.sortFunction=null;this.sortCriteria=null;this.sortCriteriaSimple=null;this.sortDirty=false;if(options.queueSortPhase===true){this.queueSortPhase()}if(filterChanged){this.emit("filter")}};DynamicView.prototype.applySort=function(comparefun){this.sortFunction=comparefun;this.sortCriteria=null;this.sortCriteriaSimple=null;this.queueSortPhase();this.emit("sort");return this};DynamicView.prototype.applySimpleSort=function(propname,options){this.sortCriteriaSimple={propname:propname,options:options||false};if(!this.collection.disableFreeze){deepFreeze(this.sortCriteriaSimple)}this.sortCriteria=null;this.sortFunction=null;this.queueSortPhase();this.emit("sort");return this};DynamicView.prototype.applySortCriteria=function(criteria){this.sortCriteria=criteria;if(!this.collection.disableFreeze){deepFreeze(this.sortCriteria)}this.sortCriteriaSimple=null;this.sortFunction=null;this.queueSortPhase();this.emit("sort");return this};DynamicView.prototype.startTransaction=function(){this.cachedresultset=this.resultset.copy();return this};DynamicView.prototype.commit=function(){this.cachedresultset=null;return this};DynamicView.prototype.rollback=function(){this.resultset=this.cachedresultset;if(this.options.persistent){this.resultdata=this.resultset.data();this.emit("rebuild",this)}return this};DynamicView.prototype._indexOfFilterWithId=function(uid){if(typeof uid==="string"||typeof uid==="number"){for(var idx=0,len=this.filterPipeline.length;idx=0){var wasFrozen=Object.isFrozen(this.filterPipeline);if(wasFrozen){this.filterPipeline=this.filterPipeline.slice()}this.filterPipeline[idx]=filter;if(wasFrozen){freeze(filter);Object.freeze(this.filterPipeline)}return this.reapplyFilters()}this.cachedresultset=null;if(this.options.persistent){this.resultdata=[];this.resultsdirty=true}this._addFilter(filter);if(this.sortFunction||this.sortCriteria||this.sortCriteriaSimple){this.queueSortPhase()}else{this.queueRebuildEvent()}this.emit("filter");return this};DynamicView.prototype.applyFind=function(query,uid){this.applyFilter({type:"find",val:query,uid:uid});return this};DynamicView.prototype.applyWhere=function(fun,uid){this.applyFilter({type:"where",val:fun,uid:uid});return this};DynamicView.prototype.removeFilter=function(uid){var idx=this._indexOfFilterWithId(uid);if(idx<0){throw new Error("Dynamic view does not contain a filter with ID: "+uid)}var wasFrozen=Object.isFrozen(this.filterPipeline);if(wasFrozen){this.filterPipeline=this.filterPipeline.slice()}this.filterPipeline.splice(idx,1);if(wasFrozen){Object.freeze(this.filterPipeline)}this.reapplyFilters();return this};DynamicView.prototype.count=function(){if(this.resultsdirty){this.resultdata=this.resultset.data()}return this.resultset.count()};DynamicView.prototype.data=function(options){if(this.sortDirty||this.resultsdirty){this.performSortPhase({suppressRebuildEvent:true})}return this.options.persistent?this.resultdata:this.resultset.data(options)};DynamicView.prototype.queueRebuildEvent=function(){if(this.rebuildPending){return}this.rebuildPending=true;var self=this;setTimeout(function(){if(self.rebuildPending){self.rebuildPending=false;self.emit("rebuild",self)}},this.options.minRebuildInterval)};DynamicView.prototype.queueSortPhase=function(){if(this.sortDirty){return}this.sortDirty=true;var self=this;if(this.options.sortPriority==="active"){setTimeout(function(){self.performSortPhase()},this.options.minRebuildInterval)}else{this.queueRebuildEvent()}};DynamicView.prototype.performSortPhase=function(options){if(!this.sortDirty&&!this.resultsdirty){return}options=options||{};if(this.sortDirty){if(this.sortFunction){this.resultset.sort(this.sortFunction)}else if(this.sortCriteria){this.resultset.compoundsort(this.sortCriteria)}else if(this.sortCriteriaSimple){this.resultset.simplesort(this.sortCriteriaSimple.propname,this.sortCriteriaSimple.options)}this.sortDirty=false}if(this.options.persistent){this.resultdata=this.resultset.data();this.resultsdirty=false}if(!options.suppressRebuildEvent){this.emit("rebuild",this)}};DynamicView.prototype.evaluateDocument=function(objIndex,isNew){if(!this.resultset.filterInitialized){if(this.options.persistent){this.resultdata=this.resultset.data()}if(this.sortFunction||this.sortCriteria||this.sortCriteriaSimple){this.queueSortPhase()}else{this.queueRebuildEvent()}return}var ofr=this.resultset.filteredrows;var oldPos=isNew?-1:ofr.indexOf(+objIndex);var oldlen=ofr.length;var evalResultset=new Resultset(this.collection);evalResultset.filteredrows=[objIndex];evalResultset.filterInitialized=true;var filter;for(var idx=0,len=this.filterPipeline.length;idx0){this.resultset.filteredrows=this.resultset.filteredrows.filter(function(di,idx){return!fxo[idx]});if(this.options.persistent){ -this.resultdata=this.resultdata.filter(function(obj,idx){return!fxo[idx]})}if(this.sortFunction||this.sortCriteria||this.sortCriteriaSimple){this.queueSortPhase()}else{this.queueRebuildEvent()}}var filt=function(idx){return function(di){return di=0||propertyName=="$loki"||propertyName=="meta"){delta[propertyName]=newObject[propertyName]}else{var propertyDelta=getObjectDelta(oldObject[propertyName],newObject[propertyName]);if(typeof propertyDelta!=="undefined"&&propertyDelta!={}){delta[propertyName]=propertyDelta}}}}return Object.keys(delta).length===0?undefined:delta}else{return oldObject===newObject?undefined:newObject}}this.getObjectDelta=getObjectDelta;function flushChanges(){self.changes=[]}this.getChanges=function(){return self.changes};this.flushChanges=flushChanges;this.setChangesApi=function(enabled){self.disableChangesApi=!enabled;if(!enabled){self.disableDeltaChangesApi=false}};this.on("delete",function deleteCallback(obj){if(!self.disableChangesApi){self.createChange(self.name,"R",obj)}});this.on("warning",function(warning){self.lokiConsoleWrapper.warn(warning)});flushChanges()}Collection.prototype=new LokiEventEmitter;Collection.prototype.contructor=Collection;Collection.prototype.createChange=function(name,op,obj,old){this.changes.push({name:name,operation:op,obj:op=="U"&&!this.disableDeltaChangesApi?this.getChangeDelta(obj,old):JSON.parse(JSON.stringify(obj))})};Collection.prototype.insertMeta=function(obj){var len,idx;if(this.disableMeta||!obj){return}if(Array.isArray(obj)){len=obj.length;for(idx=0;idx1){options.randomSamplingFactor=.1}var valid=true,idx,iter,pos,len,biv;if(!this.binaryIndices.hasOwnProperty(property)){throw new Error("called checkIndex on property without an index: "+property)}if(!this.adaptiveBinaryIndices){this.ensureIndex(property)}biv=this.binaryIndices[property].values;len=biv.length;if(len!==this.data.length){if(options.repair){this.ensureIndex(property,true)}return false}if(len===0){return true}var usingDotNotation=property.indexOf(".")!==-1;if(len===1){valid=biv[0]===0}else{if(options.randomSampling){if(!LokiOps.$lte(Utils.getIn(this.data[biv[0]],property,usingDotNotation),Utils.getIn(this.data[biv[1]],property,usingDotNotation))){valid=false}if(!LokiOps.$lte(Utils.getIn(this.data[biv[len-2]],property,usingDotNotation),Utils.getIn(this.data[biv[len-1]],property,usingDotNotation))){valid=false}if(valid){iter=Math.floor((len-1)*options.randomSamplingFactor);for(idx=0;idx0;if(adaptiveBatchOverride){this.adaptiveBinaryIndices=false}try{this.emit("pre-insert",doc);for(var i=0,len=doc.length;i0;if(adaptiveBatchOverride){this.adaptiveBinaryIndices=false}try{for(k=0;k0;var doc,self=this;try{this.startTransaction();this.ensureId();for(idx=0;idx0||bic>0||uic>0){if(dlen>0){for(didx=0;didx1){for(idx=0;idx>1;id=typeof id==="number"?id:parseInt(id,10);if(isNaN(id)){throw new TypeError("Passed id is not an integer")}while(data[min]>1;if(data[mid]sortedPositions[rmidx];rmidx++){shift++}bi.values[idx]-=shift}return}}idxPos=this.getBinaryIndexPosition(dataPosition,binaryIndexName);if(idxPos===null){return null}bi.values.splice(idxPos,1);if(removedFromIndexOnly===true){return}len=bi.values.length;for(idx=0;idxdataPosition){bi.values[idx]--}}};Collection.prototype.calculateRangeStart=function(prop,val,adaptive,usingDotNotation){var rcd=this.data;var index=this.binaryIndices[prop].values;var min=0;var max=index.length-1;var mid=0;if(index.length===0){return-1}var minVal=Utils.getIn(rcd[index[min]],prop,usingDotNotation);var maxVal=Utils.getIn(rcd[index[max]],prop,usingDotNotation);while(min>1;if(Comparators.lt(Utils.getIn(rcd[index[mid]],prop,usingDotNotation),val,false)){min=mid+1}else{max=mid}}var lbound=min;if(Comparators.aeq(val,Utils.getIn(rcd[index[lbound]],prop,usingDotNotation))){return lbound}if(Comparators.lt(val,Utils.getIn(rcd[index[lbound]],prop,usingDotNotation),false)){return adaptive?lbound:lbound-1}return adaptive?lbound+1:lbound};Collection.prototype.calculateRangeEnd=function(prop,val,usingDotNotation){var rcd=this.data;var index=this.binaryIndices[prop].values;var min=0;var max=index.length-1;var mid=0;if(index.length===0){return-1}var minVal=Utils.getIn(rcd[index[min]],prop,usingDotNotation);var maxVal=Utils.getIn(rcd[index[max]],prop,usingDotNotation);while(min>1;if(Comparators.lt(val,Utils.getIn(rcd[index[mid]],prop,usingDotNotation),false)){max=mid}else{min=mid+1}}var ubound=max;if(Comparators.aeq(val,Utils.getIn(rcd[index[ubound]],prop,usingDotNotation))){return ubound}if(Comparators.gt(val,Utils.getIn(rcd[index[ubound]],prop,usingDotNotation),false)){return ubound+1}if(Comparators.aeq(val,Utils.getIn(rcd[index[ubound-1]],prop,usingDotNotation))){return ubound-1}return ubound};Collection.prototype.calculateRange=function(op,prop,val){var rcd=this.data;var index=this.binaryIndices[prop].values;var min=0;var max=index.length-1;var mid=0;var lbound,lval;var ubound,uval;if(rcd.length===0){return[0,-1]}var usingDotNotation=prop.indexOf(".")!==-1;var minVal=Utils.getIn(rcd[index[min]],prop,usingDotNotation);var maxVal=Utils.getIn(rcd[index[max]],prop,usingDotNotation);switch(op){case"$eq":case"$aeq":if(Comparators.lt(val,minVal,false)||Comparators.gt(val,maxVal,false)){return[0,-1]}break;case"$dteq":if(Comparators.lt(val,minVal,false)||Comparators.gt(val,maxVal,false)){return[0,-1]}break;case"$gt":if(Comparators.gt(val,maxVal,true)){return[0,-1]}if(Comparators.gt(minVal,val,false)){return[min,max]}break;case"$gte":if(Comparators.gt(val,maxVal,false)){return[0,-1]}if(Comparators.gt(minVal,val,true)){return[min,max]}break;case"$lt":if(Comparators.lt(val,minVal,true)){return[0,-1]}if(Comparators.lt(maxVal,val,false)){return[min,max]}break;case"$lte":if(Comparators.lt(val,minVal,false)){return[0,-1]}if(Comparators.lt(maxVal,val,true)){return[min,max]}break;case"$between":if(Comparators.gt(val[0],maxVal,false)){return[0,-1]}if(Comparators.lt(val[1],minVal,false)){return[0,-1]}lbound=this.calculateRangeStart(prop,val[0],false,usingDotNotation);ubound=this.calculateRangeEnd(prop,val[1],usingDotNotation);if(lbound<0)lbound++;if(ubound>max)ubound--;if(!Comparators.gt(Utils.getIn(rcd[index[lbound]],prop,usingDotNotation),val[0],true))lbound++;if(!Comparators.lt(Utils.getIn(rcd[index[ubound]],prop,usingDotNotation),val[1],true))ubound--;if(ubounddeepProperty(this.data[i],field,deep)){min=deepProperty(this.data[i],field,deep);result.index=this.data[i].$loki}}else{min=deepProperty(this.data[i],field,deep);result.index=this.data[i].$loki}}result.value=min;return result};Collection.prototype.extractNumerical=function(field){return this.extract(field).map(parseBase10).filter(Number).filter(function(n){return!isNaN(n)})};Collection.prototype.avg=function(field){return average(this.extractNumerical(field))};Collection.prototype.stdDev=function(field){return standardDeviation(this.extractNumerical(field))};Collection.prototype.mode=function(field){var dict={},data=this.extract(field);data.forEach(function(obj){if(dict[obj]){dict[obj]+=1}else{dict[obj]=1}});var max,prop,mode;for(prop in dict){if(max){if(max0){root=root[pieces.shift()]}return root}function binarySearch(array,item,fun){var lo=0,hi=array.length,compared,mid;while(lo>1;compared=fun.apply(null,[item,array[mid]]);if(compared===0){return{found:true,index:mid}}else if(compared<0){hi=mid}else{lo=mid+1}}return{found:false,index:hi}}function BSonSort(fun){return function(array,item){return binarySearch(array,item,fun)}}function KeyValueStore(){}KeyValueStore.prototype={keys:[],values:[],sort:function(a,b){return ab?1:0},setSort:function(fun){this.bs=new BSonSort(fun)},bs:function(){return new BSonSort(this.sort)},set:function(key,value){var pos=this.bs(this.keys,key);if(pos.found){this.values[pos.index]=value}else{this.keys.splice(pos.index,0,key);this.values.splice(pos.index,0,value)}},get:function(key){return this.values[binarySearch(this.keys,key,this.sort).index]}};function UniqueIndex(uniqueField){this.field=uniqueField;this.keyMap=Object.create(null);this.lokiMap=Object.create(null)}UniqueIndex.prototype.keyMap={};UniqueIndex.prototype.lokiMap={};UniqueIndex.prototype.set=function(obj){var fieldValue=obj[this.field];if(fieldValue!==null&&typeof fieldValue!=="undefined"){if(this.keyMap[fieldValue]){throw new Error("Duplicate key for property "+this.field+": "+fieldValue)}else{this.keyMap[fieldValue]=obj;this.lokiMap[obj.$loki]=fieldValue}}};UniqueIndex.prototype.get=function(key){return this.keyMap[key]};UniqueIndex.prototype.byId=function(id){return this.keyMap[this.lokiMap[id]]};UniqueIndex.prototype.update=function(obj,doc){if(this.lokiMap[obj.$loki]!==doc[this.field]){var old=this.lokiMap[obj.$loki];this.set(doc);this.keyMap[old]=undefined}else{this.keyMap[obj[this.field]]=doc}};UniqueIndex.prototype.remove=function(key){var obj=this.keyMap[key];if(obj!==null&&typeof obj!=="undefined"){this.keyMap[key]=undefined;this.lokiMap[obj.$loki]=undefined}else{throw new Error("Key is not in unique index: "+this.field)}};UniqueIndex.prototype.clear=function(){this.keyMap=Object.create(null);this.lokiMap=Object.create(null)};function ExactIndex(exactField){this.index=Object.create(null);this.field=exactField}ExactIndex.prototype={set:function add(key,val){if(this.index[key]){this.index[key].push(val)}else{this.index[key]=[val]}},remove:function remove(key,val){var idxSet=this.index[key];for(var i in idxSet){if(idxSet[i]==val){idxSet.splice(i,1)}}if(idxSet.length<1){this.index[key]=undefined}},get:function get(key){return this.index[key]},clear:function clear(key){this.index={}}};function SortedIndex(sortedField){this.field=sortedField}SortedIndex.prototype={keys:[],values:[],sort:function(a,b){return ab?1:0},bs:function(){return new BSonSort(this.sort)},setSort:function(fun){this.bs=new BSonSort(fun)},set:function(key,value){var pos=binarySearch(this.keys,key,this.sort);if(pos.found){this.values[pos.index].push(value)}else{this.keys.splice(pos.index,0,key);this.values.splice(pos.index,0,[value])}},get:function(key){var bsr=binarySearch(this.keys,key,this.sort);if(bsr.found){return this.values[bsr.index]}else{return[]}},getLt:function(key){var bsr=binarySearch(this.keys,key,this.sort);var pos=bsr.index;if(bsr.found)pos--;return this.getAll(key,0,pos)},getGt:function(key){var bsr=binarySearch(this.keys,key,this.sort);var pos=bsr.index;if(bsr.found)pos++;return this.getAll(key,pos,this.keys.length)},getAll:function(key,start,end){var results=[];for(var i=start;i=cdlen)doneWithPartition=true}if(pageLen>=this.options.pageSize)doneWithPage=true;if(!doneWithPage||doneWithPartition){pageBuilder+=this.options.delimiter;pageLen+=delimlen}if(doneWithPartition||doneWithPage){this.adapter.saveDatabase(keyname,pageBuilder,pageSaveCallback);return}}};function LokiFsAdapter(){try{this.fs=require("fs")}catch(e){this.fs=null}}LokiFsAdapter.prototype.loadDatabase=function loadDatabase(dbname,callback){var self=this;this.fs.stat(dbname,function(err,stats){if(!err&&stats.isFile()){self.fs.readFile(dbname,{encoding:"utf8"},function readFileCallback(err,data){if(err){callback(new Error(err))}else{callback(data)}})}else{callback(null)}})};LokiFsAdapter.prototype.saveDatabase=function saveDatabase(dbname,dbstring,callback){var self=this;var tmpdbname=dbname+"~";this.fs.writeFile(tmpdbname,dbstring,function writeFileCallback(err){if(err){callback(new Error(err))}else{self.fs.rename(tmpdbname,dbname,callback)}})};LokiFsAdapter.prototype.deleteDatabase=function deleteDatabase(dbname,callback){this.fs.unlink(dbname,function deleteDatabaseCallback(err){if(err){callback(new Error(err))}else{callback()}})};function LokiLocalStorageAdapter(){}LokiLocalStorageAdapter.prototype.loadDatabase=function loadDatabase(dbname,callback){if(localStorageAvailable()){callback(localStorage.getItem(dbname))}else{callback(new Error("localStorage is not available"))}};LokiLocalStorageAdapter.prototype.saveDatabase=function saveDatabase(dbname,dbstring,callback){if(localStorageAvailable()){localStorage.setItem(dbname,dbstring);callback(null)}else{callback(new Error("localStorage is not available"))}};LokiLocalStorageAdapter.prototype.deleteDatabase=function deleteDatabase(dbname,callback){if(localStorageAvailable()){localStorage.removeItem(dbname);callback(null)}else{callback(new Error("localStorage is not available"))}};Loki.prototype.throttledSaveDrain=function(callback,options){var self=this;var now=(new Date).getTime();if(!this.throttledSaves){callback(true)}options=options||{};if(!options.hasOwnProperty("recursiveWait")){options.recursiveWait=true}if(!options.hasOwnProperty("recursiveWaitLimit")){options.recursiveWaitLimit=false}if(!options.hasOwnProperty("recursiveWaitLimitDuration")){options.recursiveWaitLimitDuration=2e3}if(!options.hasOwnProperty("started")){options.started=(new Date).getTime()}if(this.throttledSaves&&this.throttledSavePending){if(options.recursiveWait){this.throttledCallbacks.push(function(){if(self.throttledSavePending){if(options.recursiveWaitLimit&&now-options.started>options.recursiveWaitLimitDuration){callback(false);return}self.throttledSaveDrain(callback,options);return}else{callback(true);return}})}else{this.throttledCallbacks.push(callback);return}}else{callback(true)}};Loki.prototype.loadDatabaseInternal=function(options,callback){var cFun=callback||function(err,data){if(err){throw err}},self=this;if(this.persistenceAdapter!==null){this.persistenceAdapter.loadDatabase(this.filename,function loadDatabaseCallback(dbString){if(typeof dbString==="string"){var parseSuccess=false;try{self.loadJSON(dbString,options||{});parseSuccess=true}catch(err){cFun(err)}if(parseSuccess){cFun(null);self.emit("loaded","database "+self.filename+" loaded")}}else{if(!dbString){cFun(null);self.emit("loaded","empty database "+self.filename+" loaded");return}if(dbString instanceof Error){cFun(dbString);return}if(typeof dbString==="object"){self.loadJSONObject(dbString,options||{});cFun(null);self.emit("loaded","database "+self.filename+" loaded");return}cFun("unexpected adapter response : "+dbString)}})}else{cFun(new Error("persistenceAdapter not configured"))}};Loki.prototype.loadDatabase=function(options,callback){var self=this;if(!this.throttledSaves){this.loadDatabaseInternal(options,callback);return}this.throttledSaveDrain(function(success){if(success){self.throttledSavePending=true;self.loadDatabaseInternal(options,function(err){if(self.throttledCallbacks.length===0){self.throttledSavePending=false}else{self.saveDatabase()}if(typeof callback==="function"){callback(err)}});return}else{if(typeof callback==="function"){callback(new Error("Unable to pause save throttling long enough to read database"))}}},options)};Loki.prototype.saveDatabaseInternal=function(callback){var cFun=callback||function(err){if(err){throw err}return};var self=this;if(!this.persistenceAdapter){cFun(new Error("persistenceAdapter not configured"));return}if(this.persistenceAdapter.mode==="incremental"){var cachedDirty;this.ignoreAutosave=true;this.persistenceAdapter.saveDatabase(this.filename,function getLokiCopy(){self.ignoreAutosave=false;if(cachedDirty){cFun(new Error("adapter error - getLokiCopy called more than once"));return}var lokiCopy=self.copy({removeNonSerializable:true});cachedDirty=self.collections.map(function(collection){return[collection.dirty,collection.dirtyIds]});self.collections.forEach(function(col){col.dirty=false;col.dirtyIds=[]});return lokiCopy},function exportDatabaseCallback(err){self.ignoreAutosave=false;if(err&&cachedDirty){self.collections.forEach(function(col,i){var cached=cachedDirty[i];col.dirty=col.dirty||cached[0];col.dirtyIds=col.dirtyIds.concat(cached[1])})}cFun(err)})}else if(this.persistenceAdapter.mode==="reference"&&typeof this.persistenceAdapter.exportDatabase==="function"){this.persistenceAdapter.exportDatabase(this.filename,this.copy({removeNonSerializable:true}),function exportDatabaseCallback(err){self.autosaveClearFlags();cFun(err)})}else{this.autosaveClearFlags();this.persistenceAdapter.saveDatabase(this.filename,this.serialize(),function saveDatabasecallback(err){cFun(err)})}};Loki.prototype.saveDatabase=function(callback){if(!this.throttledSaves){this.saveDatabaseInternal(callback);return}if(this.throttledSavePending){this.throttledCallbacks.push(callback);return}var localCallbacks=this.throttledCallbacks;this.throttledCallbacks=[];localCallbacks.unshift(callback);this.throttledSavePending=true;var self=this;this.saveDatabaseInternal(function(err){self.throttledSavePending=false;localCallbacks.forEach(function(pcb){if(typeof pcb==="function"){setTimeout(function(){pcb(err)},1)}});if(self.throttledCallbacks.length>0){self.saveDatabase()}})};Loki.prototype.save=Loki.prototype.saveDatabase;Loki.prototype.deleteDatabase=function(options,callback){var cFun=callback||function(err,data){if(err){throw err}};if(typeof options==="function"&&!callback){cFun=options}if(this.persistenceAdapter!==null){this.persistenceAdapter.deleteDatabase(this.filename,function deleteDatabaseCallback(err){cFun(err)})}else{cFun(new Error("persistenceAdapter not configured"))}};Loki.prototype.autosaveDirty=function(){for(var idx=0;idx0){this.filteredrows=[]}this.filterInitialized=false;return this};Resultset.prototype.toJSON=function(){var copy=this.copy();copy.collection=null;return copy};Resultset.prototype.limit=function(qty){if(!this.filterInitialized&&this.filteredrows.length===0){this.filteredrows=this.collection.prepareFullDocIndex()}var rscopy=new Resultset(this.collection);rscopy.filteredrows=this.filteredrows.slice(0,qty);rscopy.filterInitialized=true;return rscopy};Resultset.prototype.offset=function(pos){if(!this.filterInitialized&&this.filteredrows.length===0){this.filteredrows=this.collection.prepareFullDocIndex()}var rscopy=new Resultset(this.collection);rscopy.filteredrows=this.filteredrows.slice(pos);rscopy.filterInitialized=true;return rscopy};Resultset.prototype.copy=function(){var result=new Resultset(this.collection);if(this.filteredrows.length>0){result.filteredrows=this.filteredrows.slice()}result.filterInitialized=this.filterInitialized;return result};Resultset.prototype.branch=Resultset.prototype.copy;Resultset.prototype.transform=function(transform,parameters){var idx,step,rs=this;if(typeof transform==="string"){if(this.collection.transforms.hasOwnProperty(transform)){transform=this.collection.transforms[transform]}}if(typeof transform!=="object"||!Array.isArray(transform)){throw new Error("Invalid transform")}if(typeof parameters!=="undefined"){transform=Utils.resolveTransformParams(transform,parameters)}for(idx=0;idxobj2[propname])return 1;if(obj1[propname]1){return this.find({$and:filters},firstOnly)}}if(!property||queryObject==="getAll"){if(firstOnly){if(this.filterInitialized){this.filteredrows=this.filteredrows.slice(0,1)}else{this.filteredrows=this.collection.data.length>0?[0]:[];this.filterInitialized=true}}return this}if(property==="$and"||property==="$or"){this[property](queryObjectOp);if(firstOnly&&this.filteredrows.length>1){this.filteredrows=this.filteredrows.slice(0,1)}return this}if(queryObjectOp===null||(typeof queryObjectOp!=="object"||queryObjectOp instanceof Date)){operator="$eq";value=queryObjectOp}else if(typeof queryObjectOp==="object"){for(key in queryObjectOp){if(hasOwnProperty.call(queryObjectOp,key)){operator=key;value=queryObjectOp[key];break}}}else{throw new Error("Do not know what you want to do.")}if(operator==="$regex"||typeof value==="object"){value=precompileQuery(operator,value)}var usingDotNotation=property.indexOf(".")!==-1;var doIndexCheck=!this.filterInitialized;if(doIndexCheck&&this.collection.binaryIndices[property]&&indexedOps[operator]){if(this.collection.adaptiveBinaryIndices!==true){this.collection.ensureIndex(property)}searchByIndex=true;index=this.collection.binaryIndices[property]}if(!searchByIndex&&operator==="$in"&&Array.isArray(value)&&typeof Set!=="undefined"){value=new Set(value);operator="$inSet"}var fun=LokiOps[operator];var t=this.collection.data;var i=0,len=0;var filter,rowIdx=0,record;if(this.filterInitialized){filter=this.filteredrows;len=filter.length;if(usingDotNotation){property=property.split(".");for(i=0;i0;this.filterPipeline=[];if(wasFrozen){Object.freeze(this.filterPipeline)}this.sortFunction=null;this.sortCriteria=null;this.sortCriteriaSimple=null;this.sortDirty=false;if(options.queueSortPhase===true){this.queueSortPhase()}if(filterChanged){this.emit("filter")}};DynamicView.prototype.applySort=function(comparefun){this.sortFunction=comparefun;this.sortCriteria=null;this.sortCriteriaSimple=null;this.queueSortPhase();this.emit("sort");return this};DynamicView.prototype.applySimpleSort=function(propname,options){this.sortCriteriaSimple={propname:propname,options:options||false};if(!this.collection.disableFreeze){deepFreeze(this.sortCriteriaSimple)}this.sortCriteria=null;this.sortFunction=null;this.queueSortPhase();this.emit("sort");return this};DynamicView.prototype.applySortCriteria=function(criteria){this.sortCriteria=criteria;if(!this.collection.disableFreeze){deepFreeze(this.sortCriteria)}this.sortCriteriaSimple=null;this.sortFunction=null;this.queueSortPhase();this.emit("sort");return this};DynamicView.prototype.startTransaction=function(){this.cachedresultset=this.resultset.copy();return this};DynamicView.prototype.commit=function(){this.cachedresultset=null;return this};DynamicView.prototype.rollback=function(){this.resultset=this.cachedresultset;if(this.options.persistent){this.resultdata=this.resultset.data();this.emit("rebuild",this)}return this};DynamicView.prototype._indexOfFilterWithId=function(uid){if(typeof uid==="string"||typeof uid==="number"){for(var idx=0,len=this.filterPipeline.length;idx=0){var wasFrozen=Object.isFrozen(this.filterPipeline);if(wasFrozen){this.filterPipeline=this.filterPipeline.slice()}this.filterPipeline[idx]=filter;if(wasFrozen){freeze(filter);Object.freeze(this.filterPipeline)}return this.reapplyFilters()}this.cachedresultset=null;if(this.options.persistent){this.resultdata=[];this.resultsdirty=true}this._addFilter(filter);if(this.sortFunction||this.sortCriteria||this.sortCriteriaSimple){this.queueSortPhase()}else{this.queueRebuildEvent()}this.emit("filter");return this};DynamicView.prototype.applyFind=function(query,uid){this.applyFilter({type:"find",val:query,uid:uid});return this};DynamicView.prototype.applyWhere=function(fun,uid){this.applyFilter({type:"where",val:fun,uid:uid});return this};DynamicView.prototype.removeFilter=function(uid){var idx=this._indexOfFilterWithId(uid);if(idx<0){throw new Error("Dynamic view does not contain a filter with ID: "+uid)}var wasFrozen=Object.isFrozen(this.filterPipeline);if(wasFrozen){this.filterPipeline=this.filterPipeline.slice()}this.filterPipeline.splice(idx,1);if(wasFrozen){Object.freeze(this.filterPipeline)}this.reapplyFilters();return this};DynamicView.prototype.count=function(){if(this.resultsdirty){this.resultdata=this.resultset.data()}return this.resultset.count()};DynamicView.prototype.data=function(options){if(this.sortDirty||this.resultsdirty){this.performSortPhase({suppressRebuildEvent:true})}return this.options.persistent?this.resultdata:this.resultset.data(options)};DynamicView.prototype.queueRebuildEvent=function(){if(this.rebuildPending){return}this.rebuildPending=true;var self=this;setTimeout(function(){if(self.rebuildPending){self.rebuildPending=false;self.emit("rebuild",self)}},this.options.minRebuildInterval)};DynamicView.prototype.queueSortPhase=function(){if(this.sortDirty){return}this.sortDirty=true;var self=this;if(this.options.sortPriority==="active"){setTimeout(function(){self.performSortPhase()},this.options.minRebuildInterval)}else{this.queueRebuildEvent()}};DynamicView.prototype.performSortPhase=function(options){if(!this.sortDirty&&!this.resultsdirty){return}options=options||{};if(this.sortDirty){if(this.sortFunction){this.resultset.sort(this.sortFunction)}else if(this.sortCriteria){this.resultset.compoundsort(this.sortCriteria)}else if(this.sortCriteriaSimple){this.resultset.simplesort(this.sortCriteriaSimple.propname,this.sortCriteriaSimple.options)}this.sortDirty=false}if(this.options.persistent){this.resultdata=this.resultset.data();this.resultsdirty=false}if(!options.suppressRebuildEvent){this.emit("rebuild",this)}};DynamicView.prototype.evaluateDocument=function(objIndex,isNew){if(!this.resultset.filterInitialized){if(this.options.persistent){this.resultdata=this.resultset.data()}if(this.sortFunction||this.sortCriteria||this.sortCriteriaSimple){this.queueSortPhase()}else{this.queueRebuildEvent()}return}var ofr=this.resultset.filteredrows;var oldPos=isNew?-1:ofr.indexOf(+objIndex);var oldlen=ofr.length;var evalResultset=new Resultset(this.collection);evalResultset.filteredrows=[objIndex];evalResultset.filterInitialized=true;var filter;for(var idx=0,len=this.filterPipeline.length;idx0){this.resultset.filteredrows=this.resultset.filteredrows.filter(function(di,idx){return!fxo[idx]});if(this.options.persistent){this.resultdata=this.resultdata.filter(function(obj,idx){return!fxo[idx]})}if(this.sortFunction||this.sortCriteria||this.sortCriteriaSimple){this.queueSortPhase()}else{this.queueRebuildEvent()}}var filt=function(idx){return function(di){return di=0||propertyName=="$loki"||propertyName=="meta"){delta[propertyName]=newObject[propertyName]}else{var propertyDelta=getObjectDelta(oldObject[propertyName],newObject[propertyName]);if(typeof propertyDelta!=="undefined"&&propertyDelta!={}){delta[propertyName]=propertyDelta}}}}return Object.keys(delta).length===0?undefined:delta}else{return oldObject===newObject?undefined:newObject}}this.getObjectDelta=getObjectDelta;function flushChanges(){self.changes=[]}this.getChanges=function(){return self.changes};this.flushChanges=flushChanges;this.setChangesApi=function(enabled){self.disableChangesApi=!enabled;if(!enabled){self.disableDeltaChangesApi=false}};this.on("delete",function deleteCallback(obj){if(!self.disableChangesApi){self.createChange(self.name,"R",obj)}});this.on("warning",function(warning){self.lokiConsoleWrapper.warn(warning)});flushChanges()}Collection.prototype=new LokiEventEmitter;Collection.prototype.contructor=Collection;Collection.prototype.createChange=function(name,op,obj,old){this.changes.push({name:name,operation:op,obj:op=="U"&&!this.disableDeltaChangesApi?this.getChangeDelta(obj,old):JSON.parse(JSON.stringify(obj))})};Collection.prototype.insertMeta=function(obj){var len,idx;if(this.disableMeta||!obj){return}if(Array.isArray(obj)){len=obj.length;for(idx=0;idx1){options.randomSamplingFactor=.1}var valid=true,idx,iter,pos,len,biv;if(!this.binaryIndices.hasOwnProperty(property)){throw new Error("called checkIndex on property without an index: "+property)}if(!this.adaptiveBinaryIndices){this.ensureIndex(property)}biv=this.binaryIndices[property].values;len=biv.length;if(len!==this.data.length){if(options.repair){this.ensureIndex(property,true)}return false}if(len===0){return true}var usingDotNotation=property.indexOf(".")!==-1;if(len===1){valid=biv[0]===0}else{if(options.randomSampling){if(!LokiOps.$lte(Utils.getIn(this.data[biv[0]],property,usingDotNotation),Utils.getIn(this.data[biv[1]],property,usingDotNotation))){valid=false}if(!LokiOps.$lte(Utils.getIn(this.data[biv[len-2]],property,usingDotNotation),Utils.getIn(this.data[biv[len-1]],property,usingDotNotation))){valid=false}if(valid){iter=Math.floor((len-1)*options.randomSamplingFactor);for(idx=0;idx0;if(adaptiveBatchOverride){this.adaptiveBinaryIndices=false}try{this.emit("pre-insert",doc);for(var i=0,len=doc.length;i0;if(adaptiveBatchOverride){this.adaptiveBinaryIndices=false}try{for(k=0;k0;var doc,self=this;try{this.startTransaction();this.ensureId();for(idx=0;idx0||bic>0||uic>0){if(dlen>0){for(didx=0;didx1){for(idx=0;idx>1;id=typeof id==="number"?id:parseInt(id,10);if(isNaN(id)){throw new TypeError("Passed id is not an integer")}while(data[min]>1;if(data[mid]sortedPositions[rmidx];rmidx++){shift++}bi.values[idx]-=shift}return}}idxPos=this.getBinaryIndexPosition(dataPosition,binaryIndexName);if(idxPos===null){return null}bi.values.splice(idxPos,1);if(removedFromIndexOnly===true){return}len=bi.values.length;for(idx=0;idxdataPosition){bi.values[idx]--}}};Collection.prototype.calculateRangeStart=function(prop,val,adaptive,usingDotNotation){var rcd=this.data;var index=this.binaryIndices[prop].values;var min=0;var max=index.length-1;var mid=0;if(index.length===0){return-1}var minVal=Utils.getIn(rcd[index[min]],prop,usingDotNotation);var maxVal=Utils.getIn(rcd[index[max]],prop,usingDotNotation);while(min>1;if(Comparators.lt(Utils.getIn(rcd[index[mid]],prop,usingDotNotation),val,false)){min=mid+1}else{max=mid}}var lbound=min;if(Comparators.aeq(val,Utils.getIn(rcd[index[lbound]],prop,usingDotNotation))){return lbound}if(Comparators.lt(val,Utils.getIn(rcd[index[lbound]],prop,usingDotNotation),false)){return adaptive?lbound:lbound-1}return adaptive?lbound+1:lbound};Collection.prototype.calculateRangeEnd=function(prop,val,usingDotNotation){var rcd=this.data;var index=this.binaryIndices[prop].values;var min=0;var max=index.length-1;var mid=0;if(index.length===0){return-1}var minVal=Utils.getIn(rcd[index[min]],prop,usingDotNotation);var maxVal=Utils.getIn(rcd[index[max]],prop,usingDotNotation);while(min>1;if(Comparators.lt(val,Utils.getIn(rcd[index[mid]],prop,usingDotNotation),false)){max=mid}else{min=mid+1}}var ubound=max;if(Comparators.aeq(val,Utils.getIn(rcd[index[ubound]],prop,usingDotNotation))){return ubound}if(Comparators.gt(val,Utils.getIn(rcd[index[ubound]],prop,usingDotNotation),false)){return ubound+1}if(Comparators.aeq(val,Utils.getIn(rcd[index[ubound-1]],prop,usingDotNotation))){return ubound-1}return ubound};Collection.prototype.calculateRange=function(op,prop,val){var rcd=this.data;var index=this.binaryIndices[prop].values;var min=0;var max=index.length-1;var mid=0;var lbound,lval;var ubound,uval;if(rcd.length===0){return[0,-1]}var usingDotNotation=prop.indexOf(".")!==-1;var minVal=Utils.getIn(rcd[index[min]],prop,usingDotNotation);var maxVal=Utils.getIn(rcd[index[max]],prop,usingDotNotation);switch(op){case"$eq":case"$aeq":if(Comparators.lt(val,minVal,false)||Comparators.gt(val,maxVal,false)){return[0,-1]}break;case"$dteq":if(Comparators.lt(val,minVal,false)||Comparators.gt(val,maxVal,false)){return[0,-1]}break;case"$gt":if(Comparators.gt(val,maxVal,true)){return[0,-1]}if(Comparators.gt(minVal,val,false)){return[min,max]}break;case"$gte":if(Comparators.gt(val,maxVal,false)){return[0,-1]}if(Comparators.gt(minVal,val,true)){return[min,max]}break;case"$lt":if(Comparators.lt(val,minVal,true)){return[0,-1]}if(Comparators.lt(maxVal,val,false)){return[min,max]}break;case"$lte":if(Comparators.lt(val,minVal,false)){return[0,-1]}if(Comparators.lt(maxVal,val,true)){return[min,max]}break;case"$between":if(Comparators.gt(val[0],maxVal,false)){return[0,-1]}if(Comparators.lt(val[1],minVal,false)){return[0,-1]}lbound=this.calculateRangeStart(prop,val[0],false,usingDotNotation);ubound=this.calculateRangeEnd(prop,val[1],usingDotNotation);if(lbound<0)lbound++;if(ubound>max)ubound--;if(!Comparators.gt(Utils.getIn(rcd[index[lbound]],prop,usingDotNotation),val[0],true))lbound++;if(!Comparators.lt(Utils.getIn(rcd[index[ubound]],prop,usingDotNotation),val[1],true))ubound--;if(ubounddeepProperty(this.data[i],field,deep)){min=deepProperty(this.data[i],field,deep);result.index=this.data[i].$loki}}else{min=deepProperty(this.data[i],field,deep);result.index=this.data[i].$loki}}result.value=min;return result};Collection.prototype.extractNumerical=function(field){return this.extract(field).map(parseBase10).filter(Number).filter(function(n){return!isNaN(n)})};Collection.prototype.avg=function(field){return average(this.extractNumerical(field))};Collection.prototype.stdDev=function(field){return standardDeviation(this.extractNumerical(field))};Collection.prototype.mode=function(field){var dict={},data=this.extract(field);data.forEach(function(obj){if(dict[obj]){dict[obj]+=1}else{dict[obj]=1}});var max,prop,mode;for(prop in dict){if(max){if(max0){root=root[pieces.shift()]}return root}function binarySearch(array,item,fun){var lo=0,hi=array.length,compared,mid;while(lo>1;compared=fun.apply(null,[item,array[mid]]);if(compared===0){return{found:true,index:mid}}else if(compared<0){hi=mid}else{lo=mid+1}}return{found:false,index:hi}}function BSonSort(fun){return function(array,item){return binarySearch(array,item,fun)}}function KeyValueStore(){}KeyValueStore.prototype={keys:[],values:[],sort:function(a,b){return ab?1:0},setSort:function(fun){this.bs=new BSonSort(fun)},bs:function(){return new BSonSort(this.sort)},set:function(key,value){var pos=this.bs(this.keys,key);if(pos.found){this.values[pos.index]=value}else{this.keys.splice(pos.index,0,key);this.values.splice(pos.index,0,value)}},get:function(key){return this.values[binarySearch(this.keys,key,this.sort).index]}};function UniqueIndex(uniqueField){this.field=uniqueField;this.keyMap=Object.create(null);this.lokiMap=Object.create(null)}UniqueIndex.prototype.keyMap={};UniqueIndex.prototype.lokiMap={};UniqueIndex.prototype.set=function(obj){var fieldValue=obj[this.field];if(fieldValue!==null&&typeof fieldValue!=="undefined"){if(this.keyMap[fieldValue]){throw new Error("Duplicate key for property "+this.field+": "+fieldValue)}else{this.keyMap[fieldValue]=obj;this.lokiMap[obj.$loki]=fieldValue}}};UniqueIndex.prototype.get=function(key){return this.keyMap[key]};UniqueIndex.prototype.byId=function(id){return this.keyMap[this.lokiMap[id]]};UniqueIndex.prototype.update=function(obj,doc){if(this.lokiMap[obj.$loki]!==doc[this.field]){var old=this.lokiMap[obj.$loki];this.set(doc);this.keyMap[old]=undefined}else{this.keyMap[obj[this.field]]=doc}};UniqueIndex.prototype.remove=function(key){var obj=this.keyMap[key];if(obj!==null&&typeof obj!=="undefined"){this.keyMap[key]=undefined;this.lokiMap[obj.$loki]=undefined}else{throw new Error("Key is not in unique index: "+this.field)}};UniqueIndex.prototype.clear=function(){this.keyMap=Object.create(null);this.lokiMap=Object.create(null)};function ExactIndex(exactField){this.index=Object.create(null);this.field=exactField}ExactIndex.prototype={set:function add(key,val){if(this.index[key]){this.index[key].push(val)}else{this.index[key]=[val]}},remove:function remove(key,val){var idxSet=this.index[key];for(var i in idxSet){if(idxSet[i]==val){idxSet.splice(i,1)}}if(idxSet.length<1){this.index[key]=undefined}},get:function get(key){return this.index[key]},clear:function clear(key){this.index={}}};function SortedIndex(sortedField){this.field=sortedField}SortedIndex.prototype={keys:[],values:[],sort:function(a,b){return ab?1:0},bs:function(){return new BSonSort(this.sort)},setSort:function(fun){this.bs=new BSonSort(fun)},set:function(key,value){var pos=binarySearch(this.keys,key,this.sort);if(pos.found){this.values[pos.index].push(value)}else{this.keys.splice(pos.index,0,key);this.values.splice(pos.index,0,[value])}},get:function(key){var bsr=binarySearch(this.keys,key,this.sort);if(bsr.found){return this.values[bsr.index]}else{return[]}},getLt:function(key){var bsr=binarySearch(this.keys,key,this.sort);var pos=bsr.index;if(bsr.found)pos--;return this.getAll(key,0,pos)},getGt:function(key){var bsr=binarySearch(this.keys,key,this.sort);var pos=bsr.index;if(bsr.found)pos++;return this.getAll(key,pos,this.keys.length)},getAll:function(key,start,end){var results=[];for(var i=start;i= 0.6" } }, - "after": { + "node_modules/after": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", "dev": true }, - "ajv": { + "node_modules/ajv": { "version": "5.5.2", "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "dev": true, - "requires": { + "dependencies": { "co": "^4.6.0", "fast-deep-equal": "^1.0.0", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.3.0" } }, - "align-text": { + "node_modules/align-text": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", "dev": true, - "requires": { + "dependencies": { "kind-of": "^3.0.2", "longest": "^1.0.1", "repeat-string": "^1.5.2" + }, + "engines": { + "node": ">=0.10.0" } }, - "amdefine": { + "node_modules/amdefine": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.4.2" + } }, - "ansi-regex": { + "node_modules/ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "ansi-styles": { + "node_modules/ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "anymatch": { + "node_modules/anymatch": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", "dev": true, - "requires": { + "dependencies": { "micromatch": "^2.1.5", "normalize-path": "^2.0.0" } }, - "argparse": { + "node_modules/argparse": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", "dev": true, - "requires": { + "dependencies": { "sprintf-js": "~1.0.2" } }, - "arr-diff": { + "node_modules/arr-diff": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", "dev": true, - "requires": { + "dependencies": { "arr-flatten": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "arr-flatten": { + "node_modules/arr-flatten": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "array-find-index": { + "node_modules/array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "array-slice": { + "node_modules/array-slice": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "array-unique": { + "node_modules/array-unique": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "arraybuffer.slice": { + "node_modules/arraybuffer.slice": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz", "integrity": "sha1-8zshWfBTKj8xB6JywMz70a0peco=", "dev": true }, - "asn1": { + "node_modules/asn1": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", "dev": true }, - "assert-plus": { + "node_modules/assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.8" + } }, - "async": { + "node_modules/async": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", "dev": true }, - "async-each": { + "node_modules/async-each": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", "dev": true }, - "asynckit": { + "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", "dev": true }, - "aws-sign2": { + "node_modules/aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true + "dev": true, + "engines": { + "node": "*" + } }, - "aws4": { + "node_modules/aws4": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=", "dev": true }, - "babylon": { + "node_modules/babylon": { "version": "7.0.0-beta.19", "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.19.tgz", "integrity": "sha512-Vg0C9s/REX6/WIXN37UKpv5ZhRi6A4pjHlpkE34+8/a6c2W1Q692n3hmc+SZG5lKRnaExLUbxtJ1SVT+KaCQ/A==", - "dev": true + "dev": true, + "bin": { + "babylon": "bin/babylon.js" + }, + "engines": { + "node": ">=4.2.0" + } }, - "backo2": { + "node_modules/backo2": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", "dev": true }, - "balanced-match": { + "node_modules/balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, - "base64-arraybuffer": { + "node_modules/base64-arraybuffer": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.6.0" + } }, - "base64id": { + "node_modules/base64id": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.4.0" + } }, - "bcrypt-pbkdf": { + "node_modules/bcrypt-pbkdf": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", "dev": true, "optional": true, - "requires": { + "dependencies": { "tweetnacl": "^0.14.3" } }, - "better-assert": { + "node_modules/better-assert": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", "dev": true, - "requires": { + "dependencies": { "callsite": "1.0.0" + }, + "engines": { + "node": "*" } }, - "binary-extensions": { + "node_modules/binary-extensions": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz", "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "bl": { + "node_modules/bl": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/bl/-/bl-1.0.3.tgz", "integrity": "sha1-/FQhoo/UImA2w7OJGmaiW8ZNIm4=", "dev": true, - "requires": { + "dependencies": { "readable-stream": "~2.0.5" - }, + } + }, + "node_modules/bl/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", + "dev": true, "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "readable-stream": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", - "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", - "string_decoder": "~0.10.x", - "util-deprecate": "~1.0.1" - } - } - } - }, - "blob": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/blob": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=", "dev": true }, - "bluebird": { + "node_modules/bluebird": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==", "dev": true }, - "body-parser": { + "node_modules/body-parser": { "version": "1.18.2", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", "dev": true, - "requires": { + "dependencies": { "bytes": "3.0.0", "content-type": "~1.0.4", "debug": "2.6.9", @@ -281,569 +356,643 @@ "qs": "6.5.1", "raw-body": "2.3.2", "type-is": "~1.6.15" + }, + "engines": { + "node": ">= 0.8" } }, - "boom": { + "node_modules/boom": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", + "deprecated": "This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).", "dev": true, - "requires": { + "dependencies": { "hoek": "4.x.x" + }, + "engines": { + "node": ">=4.0.0" } }, - "brace-expansion": { + "node_modules/brace-expansion": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", "dev": true, - "requires": { + "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, - "braces": { + "node_modules/braces": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", "dev": true, - "requires": { + "dependencies": { "expand-range": "^1.8.1", "preserve": "^0.2.0", "repeat-element": "^1.1.2" + }, + "engines": { + "node": ">=0.10.0" } }, - "builtin-modules": { + "node_modules/builtin-modules": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "bytes": { + "node_modules/bytes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.8" + } }, - "callsite": { + "node_modules/callsite": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", - "dev": true + "dev": true, + "engines": { + "node": "*" + } }, - "camelcase": { + "node_modules/camelcase": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "camelcase-keys": { + "node_modules/camelcase-keys": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", "dev": true, - "requires": { + "dependencies": { "camelcase": "^2.0.0", "map-obj": "^1.0.0" }, - "dependencies": { - "camelcase": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", - "dev": true - } + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/camelcase-keys/node_modules/camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, - "caseless": { + "node_modules/caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", "dev": true }, - "catharsis": { + "node_modules/catharsis": { "version": "0.8.9", "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.9.tgz", "integrity": "sha1-mMyJDKZS3S7w5ws3klMQ/56Q/Is=", "dev": true, - "requires": { + "dependencies": { "underscore-contrib": "~0.3.0" + }, + "engines": { + "node": ">= 0.10" } }, - "center-align": { + "node_modules/center-align": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", "dev": true, - "requires": { + "dependencies": { "align-text": "^0.1.3", "lazy-cache": "^1.0.3" + }, + "engines": { + "node": ">=0.10.0" } }, - "chalk": { + "node_modules/chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, - "requires": { + "dependencies": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", "has-ansi": "^2.0.0", "strip-ansi": "^3.0.0", "supports-color": "^2.0.0" }, - "dependencies": { - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } + "engines": { + "node": ">=0.10.0" } }, - "chokidar": { + "node_modules/chalk/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/chokidar": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", + "deprecated": "Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.", "dev": true, - "requires": { + "dependencies": { "anymatch": "^1.3.0", "async-each": "^1.0.0", - "fsevents": "^1.0.0", "glob-parent": "^2.0.0", "inherits": "^2.0.1", "is-binary-path": "^1.0.0", "is-glob": "^2.0.0", "path-is-absolute": "^1.0.0", "readdirp": "^2.0.0" + }, + "optionalDependencies": { + "fsevents": "^1.0.0" } }, - "cli": { + "node_modules/cli": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", "integrity": "sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ=", "dev": true, - "requires": { + "dependencies": { "exit": "0.1.2", "glob": "^7.1.1" }, + "engines": { + "node": ">=0.2.5" + } + }, + "node_modules/cli/node_modules/glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, "dependencies": { - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" } }, - "cliui": { + "node_modules/cliui": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", "dev": true, - "requires": { + "dependencies": { "center-align": "^0.1.1", "right-align": "^0.1.1", "wordwrap": "0.0.2" - }, - "dependencies": { - "wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", - "dev": true - } } }, - "co": { + "node_modules/cliui/node_modules/wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true + "dev": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } }, - "colors": { + "node_modules/colors": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.1.90" + } }, - "combine-lists": { + "node_modules/combine-lists": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/combine-lists/-/combine-lists-1.0.1.tgz", "integrity": "sha1-RYwH4J4NkA/Ci3Cj/sLazR0st/Y=", "dev": true, - "requires": { - "lodash": "^4.5.0" - }, "dependencies": { - "lodash": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", - "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", - "dev": true - } + "lodash": "^4.5.0" } }, - "combined-stream": { + "node_modules/combine-lists/node_modules/lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + }, + "node_modules/combined-stream": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", "dev": true, - "requires": { + "dependencies": { "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" } }, - "commander": { + "node_modules/commander": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz", "integrity": "sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM=", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.6.x" + } }, - "component-bind": { + "node_modules/component-bind": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=", "dev": true }, - "component-emitter": { + "node_modules/component-emitter": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz", "integrity": "sha1-KWWU8nU9qmOZbSrwjRWpURbJrsM=", "dev": true }, - "component-inherit": { + "node_modules/component-inherit": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=", "dev": true }, - "concat-map": { + "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, - "concat-stream": { + "node_modules/concat-stream": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", "dev": true, - "requires": { + "engines": [ + "node >= 0.8" + ], + "dependencies": { "inherits": "^2.0.3", "readable-stream": "^2.2.2", "typedarray": "^0.0.6" - }, + } + }, + "node_modules/concat-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "node_modules/concat-stream/node_modules/readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.0.3", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/concat-stream/node_modules/string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "readable-stream": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", - "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.0.3", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "connect": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/connect": { "version": "3.6.5", "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.5.tgz", "integrity": "sha1-+43ee6B2OHfQ7J352sC0tA5yx9o=", "dev": true, - "requires": { + "dependencies": { "debug": "2.6.9", "finalhandler": "1.0.6", "parseurl": "~1.3.2", "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" } }, - "console-browserify": { + "node_modules/console-browserify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", "dev": true, - "requires": { + "dependencies": { "date-now": "^0.1.4" } }, - "content-type": { + "node_modules/content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.6" + } }, - "cookie": { + "node_modules/cookie": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", - "dev": true - }, - "core-js": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.3.tgz", - "integrity": "sha1-isw4NFgk8W2DZbfJtCWRaOjtYD4=", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.6" + } }, - "core-util-is": { + "node_modules/core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true }, - "cryptiles": { + "node_modules/cryptiles": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", + "deprecated": "This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).", "dev": true, - "requires": { + "dependencies": { "boom": "5.x.x" }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/cryptiles/node_modules/boom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", + "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", + "deprecated": "This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).", + "dev": true, "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "dev": true, - "requires": { - "hoek": "4.x.x" - } - } + "hoek": "4.x.x" + }, + "engines": { + "node": ">=4.0.0" } }, - "currently-unhandled": { + "node_modules/currently-unhandled": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", "dev": true, - "requires": { + "dependencies": { "array-find-index": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "custom-event": { + "node_modules/custom-event": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", "dev": true }, - "dashdash": { + "node_modules/dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "dev": true, - "requires": { + "dependencies": { "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" } }, - "date-now": { + "node_modules/date-now": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", "dev": true }, - "dateformat": { + "node_modules/dateformat": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=", "dev": true, - "requires": { + "dependencies": { "get-stdin": "^4.0.1", "meow": "^3.3.0" + }, + "bin": { + "dateformat": "bin/cli.js" + }, + "engines": { + "node": "*" } }, - "debug": { + "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "requires": { + "dependencies": { "ms": "2.0.0" } }, - "decamelize": { + "node_modules/decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "deep-is": { + "node_modules/deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, - "delayed-stream": { + "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.4.0" + } }, - "depd": { + "node_modules/depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.6" + } }, - "di": { + "node_modules/di": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", "dev": true }, - "diff": { + "node_modules/diff": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.3.1" + } }, - "dom-serialize": { + "node_modules/dom-serialize": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", "dev": true, - "requires": { + "dependencies": { "custom-event": "~1.0.0", "ent": "~2.2.0", "extend": "^3.0.0", "void-elements": "^2.0.0" } }, - "dom-serializer": { + "node_modules/dom-serializer": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", "dev": true, - "requires": { + "dependencies": { "domelementtype": "~1.1.1", "entities": "~1.1.1" - }, - "dependencies": { - "domelementtype": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", - "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", - "dev": true - }, - "entities": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", - "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=", - "dev": true - } } }, - "domelementtype": { + "node_modules/dom-serializer/node_modules/domelementtype": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", + "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", + "dev": true + }, + "node_modules/dom-serializer/node_modules/entities": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", + "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=", + "dev": true + }, + "node_modules/domelementtype": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=", + "deprecated": "update to domelementtype@1.3.1", "dev": true }, - "domhandler": { + "node_modules/domhandler": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", "dev": true, - "requires": { + "dependencies": { "domelementtype": "1" } }, - "domutils": { + "node_modules/domutils": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", "dev": true, - "requires": { + "dependencies": { "dom-serializer": "0", "domelementtype": "1" } }, - "ecc-jsbn": { + "node_modules/ecc-jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", "dev": true, "optional": true, - "requires": { + "dependencies": { "jsbn": "~0.1.0" } }, - "ee-first": { + "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", "dev": true }, - "encodeurl": { + "node_modules/encodeurl": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz", "integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA=", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.8" + } }, - "engine.io": { + "node_modules/engine.io": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-1.8.3.tgz", "integrity": "sha1-jef5eJXSDTm4X4ju7nd7K9QrE9Q=", "dev": true, - "requires": { + "dependencies": { "accepts": "1.3.3", "base64id": "1.0.0", "cookie": "0.3.1", "debug": "2.3.3", "engine.io-parser": "1.3.2", "ws": "1.1.2" - }, - "dependencies": { - "debug": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", - "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", - "dev": true, - "requires": { - "ms": "0.7.2" - } - }, - "ms": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", - "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", - "dev": true - } - } - }, - "engine.io-client": { + } + }, + "node_modules/engine.io-client": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.8.3.tgz", "integrity": "sha1-F5jtk0USRkU9TG9jXXogH+lA1as=", "dev": true, - "requires": { + "dependencies": { "component-emitter": "1.2.1", "component-inherit": "0.0.3", "debug": "2.3.3", @@ -856,37 +1005,35 @@ "ws": "1.1.2", "xmlhttprequest-ssl": "1.5.3", "yeast": "0.1.2" - }, + } + }, + "node_modules/engine.io-client/node_modules/component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "node_modules/engine.io-client/node_modules/debug": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", + "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", + "dev": true, "dependencies": { - "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", - "dev": true - }, - "debug": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", - "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", - "dev": true, - "requires": { - "ms": "0.7.2" - } - }, - "ms": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", - "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", - "dev": true - } - } - }, - "engine.io-parser": { + "ms": "0.7.2" + } + }, + "node_modules/engine.io-client/node_modules/ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", + "dev": true + }, + "node_modules/engine.io-parser": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.3.2.tgz", "integrity": "sha1-k3sHnwAH0Ik+xW1GyyILjLQ1Igo=", "dev": true, - "requires": { + "dependencies": { "after": "0.8.2", "arraybuffer.slice": "0.0.6", "base64-arraybuffer": "0.1.5", @@ -895,252 +1042,331 @@ "wtf-8": "1.0.0" } }, - "ent": { + "node_modules/engine.io/node_modules/debug": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", + "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", + "dev": true, + "dependencies": { + "ms": "0.7.2" + } + }, + "node_modules/engine.io/node_modules/ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", + "dev": true + }, + "node_modules/ent": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", "dev": true }, - "entities": { + "node_modules/entities": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=", "dev": true }, - "error-ex": { + "node_modules/error-ex": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", "dev": true, - "requires": { + "dependencies": { "is-arrayish": "^0.2.1" } }, - "es6-promise": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.2.tgz", - "integrity": "sha512-LSas5vsuA6Q4nEdf9wokY5/AJYXry98i0IzXsv49rYsgDGDNDPbqAYR1Pe23iFxygfbGZNR/5VrHXBCh2BhvUQ==", + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", "dev": true }, - "escape-html": { + "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", "dev": true }, - "escape-string-regexp": { + "node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.8.0" + } }, - "escodegen": { + "node_modules/escodegen": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", "dev": true, - "requires": { + "dependencies": { "esprima": "^2.7.1", "estraverse": "^1.9.1", "esutils": "^2.0.2", - "optionator": "^0.8.1", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=0.12.0" + }, + "optionalDependencies": { "source-map": "~0.2.0" } }, - "esprima": { + "node_modules/esprima": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", - "dev": true + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=0.10.0" + } }, - "estraverse": { + "node_modules/estraverse": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "esutils": { + "node_modules/esutils": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "eventemitter3": { + "node_modules/eventemitter3": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz", "integrity": "sha1-HIaZHYFq0eUEdQ5zh0Ik7PO+xQg=", "dev": true }, - "exit": { + "node_modules/exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.8.0" + } }, - "expand-braces": { + "node_modules/expand-braces": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/expand-braces/-/expand-braces-0.1.2.tgz", "integrity": "sha1-SIsdHSRRyz06axks/AMPRMWFX+o=", "dev": true, - "requires": { + "dependencies": { "array-slice": "^0.2.3", "array-unique": "^0.2.1", "braces": "^0.1.2" }, - "dependencies": { - "braces": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-0.1.5.tgz", - "integrity": "sha1-wIVxEIUpHYt1/ddOqw+FlygHEeY=", - "dev": true, - "requires": { - "expand-range": "^0.1.0" - } - }, - "expand-range": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-0.1.1.tgz", - "integrity": "sha1-TLjtoJk8pW+k9B/ELzy7TMrf8EQ=", - "dev": true, - "requires": { - "is-number": "^0.1.1", - "repeat-string": "^0.2.2" - } - }, - "is-number": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-0.1.1.tgz", - "integrity": "sha1-aaevEWlj1HIG7JvZtIoUIW8eOAY=", - "dev": true - }, - "repeat-string": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-0.2.2.tgz", - "integrity": "sha1-x6jTI2BoNiBZp+RlH8aITosftK4=", - "dev": true - } - } - }, - "expand-brackets": { + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-braces/node_modules/braces": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-0.1.5.tgz", + "integrity": "sha1-wIVxEIUpHYt1/ddOqw+FlygHEeY=", + "dev": true, + "dependencies": { + "expand-range": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-braces/node_modules/expand-range": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-0.1.1.tgz", + "integrity": "sha1-TLjtoJk8pW+k9B/ELzy7TMrf8EQ=", + "dev": true, + "dependencies": { + "is-number": "^0.1.1", + "repeat-string": "^0.2.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-braces/node_modules/is-number": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-0.1.1.tgz", + "integrity": "sha1-aaevEWlj1HIG7JvZtIoUIW8eOAY=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-braces/node_modules/repeat-string": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-0.2.2.tgz", + "integrity": "sha1-x6jTI2BoNiBZp+RlH8aITosftK4=", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/expand-brackets": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", "dev": true, - "requires": { + "dependencies": { "is-posix-bracket": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "expand-range": { + "node_modules/expand-range": { "version": "1.8.2", "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", "dev": true, - "requires": { + "dependencies": { "fill-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "extend": { + "node_modules/extend": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", "dev": true }, - "extglob": { + "node_modules/extglob": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", "dev": true, - "requires": { + "dependencies": { "is-extglob": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "extract-zip": { + "node_modules/extract-zip": { "version": "1.6.6", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.6.tgz", "integrity": "sha1-EpDt6NINCHK0Kf0/NRyhKOxe+Fw=", "dev": true, - "requires": { + "dependencies": { "concat-stream": "1.6.0", "debug": "2.6.9", "mkdirp": "0.5.0", "yauzl": "2.4.1" }, + "bin": { + "extract-zip": "cli.js" + } + }, + "node_modules/extract-zip/node_modules/minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "node_modules/extract-zip/node_modules/mkdirp": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz", + "integrity": "sha1-HXMHam35hs2TROFecfzAWkyavxI=", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "dev": true, "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - }, - "mkdirp": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz", - "integrity": "sha1-HXMHam35hs2TROFecfzAWkyavxI=", - "dev": true, - "requires": { - "minimist": "0.0.8" - } - } - } - }, - "extsprintf": { + "minimist": "0.0.8" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true + "dev": true, + "engines": [ + "node >=0.6.0" + ] }, - "fast-deep-equal": { + "node_modules/fast-deep-equal": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=", "dev": true }, - "fast-json-stable-stringify": { + "node_modules/fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", "dev": true }, - "fast-levenshtein": { + "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, - "fd-slicer": { + "node_modules/fd-slicer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", "dev": true, - "requires": { + "dependencies": { "pend": "~1.2.0" } }, - "filename-regex": { + "node_modules/filename-regex": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "fill-range": { + "node_modules/fill-range": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", "dev": true, - "requires": { + "dependencies": { "is-number": "^2.1.0", "isobject": "^2.0.0", "randomatic": "^1.1.3", "repeat-element": "^1.1.2", "repeat-string": "^1.5.2" + }, + "engines": { + "node": ">=0.10.0" } }, - "finalhandler": { + "node_modules/finalhandler": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.6.tgz", "integrity": "sha1-AHrqM9Gk0+QgF/YkhIrVjSEvgU8=", "dev": true, - "requires": { + "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.1", "escape-html": "~1.0.3", @@ -1149,1215 +1375,1592 @@ "statuses": "~1.3.1", "unpipe": "~1.0.0" }, - "dependencies": { - "statuses": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", - "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=", - "dev": true - } + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=", + "dev": true, + "engines": { + "node": ">= 0.6" } }, - "find-up": { + "node_modules/find-up": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "dev": true, - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" + "dependencies": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "dev": true, + "dependencies": { + "for-in": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", + "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.5", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/fs-extra": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", + "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0" + } + }, + "node_modules/fs-extra/node_modules/klaw": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.9" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/fsevents": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.3.tgz", + "integrity": "sha512-WIr7iDkdmdbxu/Gh6eKEZJL6KPE74/5MEsf2whTOFNxbIoIixogroLdKYqB6FDav4Wavh/lZdzzd3b2KxIXC5Q==", + "bundleDependencies": [ + "node-pre-gyp" + ], + "deprecated": "The v1 package contains DANGEROUS / INSECURE binaries. Upgrade to safe fsevents v2", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "nan": "^2.3.0", + "node-pre-gyp": "^0.6.39" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fsevents/node_modules/abbrev": { + "version": "1.1.0", + "integrity": "sha512-c92Vmq5hfBgXyoUaHqF8P5+7THGjvxAlB64tm3PiFSAcDww34ndmrlSOd3AUaBZoutDwX0dHz9nUUFoD1jEw0Q==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/ajv": { + "version": "4.11.8", + "integrity": "sha512-I/bSHSNEcFFqXLf91nchoNB9D1Kie3QKcWdchYUaoIg1+1bdWDkdfdlvdIOJbi9U8xR0y+MWc5D+won9v95WlQ==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "co": "^4.6.0", + "json-stable-stringify": "^1.0.1" + } + }, + "node_modules/fsevents/node_modules/ansi-regex": { + "version": "2.1.1", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "inBundle": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fsevents/node_modules/aproba": { + "version": "1.1.1", + "integrity": "sha512-wddRlyVZ7n0ZClzsf0Aqf5vGke7/X8QT0GElKYr8qAuE80tlqbvKf4hlrDE0/zqI8Z6j4HjIIaB9gZ484kjjsw==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/are-we-there-yet": { + "version": "1.1.4", + "integrity": "sha512-QbMPI8teYlZBIBqDgmIWfDKO149dGtQV2ium8WniCaARFFRd1e+IES1LA4sSGcVTFdVL628+163WUbxev7R/aQ==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "node_modules/fsevents/node_modules/asn1": { + "version": "0.2.3", + "integrity": "sha512-6i37w/+EhlWlGUJff3T/Q8u1RGmP5wgbiwYnOnbOqvtrPxT63/sYFyP9RcpxtxGymtfA075IvmOnL7ycNOWl3w==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/assert-plus": { + "version": "0.2.0", + "integrity": "sha512-u1L0ZLywRziOVjUhRxI0Qg9G+4RnFB9H/Rq40YWn0dieDgO7vAYeJz6jKAO6t/aruzlDFLAPkQTT87e+f8Imaw==", + "dev": true, + "inBundle": true, + "optional": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/fsevents/node_modules/asynckit": { + "version": "0.4.0", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/aws-sign2": { + "version": "0.6.0", + "integrity": "sha512-JnJpAS0p9RmixkOvW2XwDxxzs1bd4/VAGIl6Q0EC5YOo+p+hqIhtDhn/nmFnB/xUNXbLkpE2mOjgVIBRKD4xYw==", + "dev": true, + "inBundle": true, + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/fsevents/node_modules/aws4": { + "version": "1.6.0", + "integrity": "sha512-tkleq4Df8UWu/7xf/tfbo7t2vDa07bcONGnKhl0QXKQsh3fJ0yJ1M5wzpy8BtBSENQw/9VTsthMhLG+yXHfStQ==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/balanced-match": { + "version": "0.4.2", + "integrity": "sha512-STw03mQKnGUYtoNjmowo4F2cRmIIxYEGiMsjjwla/u5P1lxadj/05WkNaFjNiKTgJkj8KiXbgAiRTmcQRwQNtg==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/bcrypt-pbkdf": { + "version": "1.0.1", + "integrity": "sha512-vY4sOrSlpwNZXsinfJ0HpbSkFft4nhSVLeUrQ4j2ydGmBOiVY83aMJStJATBy0C3+XdaYa990kIA1qkC2mUq6g==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/fsevents/node_modules/block-stream": { + "version": "0.0.9", + "integrity": "sha512-OorbnJVPII4DuUKbjARAe8u8EfqOmkEEaSFIyoQ7OjTHn6kafxWl0wLgoZ2rXaYd7MyLcDaU4TmhfxtwgcccMQ==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "inherits": "~2.0.0" + }, + "engines": { + "node": "0.4 || >=0.5.8" + } + }, + "node_modules/fsevents/node_modules/boom": { + "version": "2.10.1", + "integrity": "sha512-KbiZEa9/vofNcVJXGwdWWn25reQ3V3dHBWbS07FTF3/TOehLnm9GEhJV4T6ZvGPkShRpmUqYwnaCrkj0mRnP6Q==", + "deprecated": "This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "hoek": "2.x.x" + }, + "engines": { + "node": ">=0.10.40" + } + }, + "node_modules/fsevents/node_modules/brace-expansion": { + "version": "1.1.7", + "integrity": "sha512-ebXXDR1wKKxJNfTM872trAU5hpKduCkTN37ipoxsh5yibWq8FfxiobiHuVlPFkspSSNhrxbPHbM4kGyDGdJ5mg==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "balanced-match": "^0.4.1", + "concat-map": "0.0.1" + } + }, + "node_modules/fsevents/node_modules/buffer-shims": { + "version": "1.0.0", + "integrity": "sha512-Zy8ZXMyxIT6RMTeY7OP/bDndfj6bwCan7SS98CEndS6deHwWPpseeHlwarNcBim+etXnF9HBc1non5JgDaJU1g==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/caseless": { + "version": "0.12.0", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/co": { + "version": "4.6.0", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "inBundle": true, + "optional": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/fsevents/node_modules/code-point-at": { + "version": "1.1.0", + "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", + "dev": true, + "inBundle": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fsevents/node_modules/combined-stream": { + "version": "1.0.5", + "integrity": "sha512-JgSRe4l4UzPwpJuxfcPWEK1SCrL4dxNjp1uqrQLMop3QZUVo+hDU8w9BJKA4JPbulTWI+UzrI2UA3tK12yQ6bg==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fsevents/node_modules/concat-map": { + "version": "0.0.1", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/console-control-strings": { + "version": "1.1.0", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/core-util-is": { + "version": "1.0.2", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/cryptiles": { + "version": "2.0.5", + "integrity": "sha512-FFN5KwpvvQTTS5hWPxrU8/QE4kQUc6uwZcrnlMBN82t1MgAtq8mnoDwINBly9Tdr02seeIIhtdF+UH1feBYGog==", + "deprecated": "This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "boom": "2.x.x" + }, + "engines": { + "node": ">=0.10.40" + } + }, + "node_modules/fsevents/node_modules/dashdash": { + "version": "1.14.1", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/fsevents/node_modules/dashdash/node_modules/assert-plus": { + "version": "1.0.0", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true, + "inBundle": true, + "optional": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/fsevents/node_modules/debug": { + "version": "2.6.8", + "integrity": "sha512-E22fsyWPt/lr4/UgQLt/pXqerGMDsanhbnmqIS3VAXuDi1v3IpiwXe2oncEIondHSBuPDWRoK/pMjlvi8FuOXQ==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/fsevents/node_modules/deep-extend": { + "version": "0.4.2", + "integrity": "sha512-cQ0iXSEKi3JRNhjUsLWvQ+MVPxLVqpwCd0cFsWbJxlCim2TlCo1JvN5WaPdPvSpUdEnkJ/X+mPGcq5RJ68EK8g==", + "dev": true, + "inBundle": true, + "optional": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.12.0" + } + }, + "node_modules/fsevents/node_modules/delayed-stream": { + "version": "1.0.0", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "inBundle": true, + "optional": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/fsevents/node_modules/delegates": { + "version": "1.0.0", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/detect-libc": { + "version": "1.0.2", + "integrity": "sha512-YexetqP2dQZlFZoGoE/Ab7ZWxIhExaRwEhluPEqegGJzKIVvVtVinvILxAh/WrzDoNIZ19XU3E+J0tEXPE5MAw==", + "dev": true, + "inBundle": true, + "optional": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/fsevents/node_modules/ecc-jsbn": { + "version": "0.1.1", + "integrity": "sha512-8Pvg9QY16SYajEL9W1Lk+9yM7XCK/MOq2wibslLZYAAEEkbAIO6mLkW+GFYbvvw8qTuDFzFMg40rS9IxkNCWPg==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "jsbn": "~0.1.0" + } + }, + "node_modules/fsevents/node_modules/extend": { + "version": "3.0.1", + "integrity": "sha512-u1aUSYGdAQxyguoP919qsgj24krDCtaO/DJFNPwFmojMmKp14gtCTVsc8lQSqRDFrwAch+mxMWC8/6ZJPz5Hpw==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/extsprintf": { + "version": "1.0.2", + "integrity": "sha512-g21Br4ELmVaKCVSUSSTXecKG+MiLcHFoby5RPPUmfZdhQTontXUOPf0QK/TvreRjgItRiyO928zxR4TCrnuwmA==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/forever-agent": { + "version": "0.6.1", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "dev": true, + "inBundle": true, + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/fsevents/node_modules/form-data": { + "version": "2.1.4", + "integrity": "sha512-8HWGSLAPr+AG0hBpsqi5Ob8HrLStN/LWeqhpFl14d7FJgHK48TmgLoALPz69XSUR65YJzDfLUX/BM8+MLJLghQ==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.5", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/fsevents/node_modules/fs.realpath": { + "version": "1.0.0", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/fstream": { + "version": "1.0.11", + "integrity": "sha512-2Xg8XA70uvyriqd1J6T/6V74WeQWHCn65hTSAWcZgKCOCo7nN6hoqgFrYPLJ9Yzbryrp/VIruHXsDyZIqZ1SvQ==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + }, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/fsevents/node_modules/fstream-ignore": { + "version": "1.0.5", + "integrity": "sha512-VVRuOs41VUqptEGiR0N5ZoWEcfGvbGRqLINyZAhHRnF3DH5wrqjNkYr3VbRoZnI41BZgO7zIVdiobc13TVI1ow==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "fstream": "^1.0.0", + "inherits": "2", + "minimatch": "^3.0.0" + } + }, + "node_modules/fsevents/node_modules/gauge": { + "version": "2.7.4", + "integrity": "sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "node_modules/fsevents/node_modules/getpass": { + "version": "0.1.7", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/fsevents/node_modules/getpass/node_modules/assert-plus": { + "version": "1.0.0", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true, + "inBundle": true, + "optional": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/fsevents/node_modules/glob": { + "version": "7.1.2", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/fsevents/node_modules/graceful-fs": { + "version": "4.1.11", + "integrity": "sha512-9x6DLUuW+ROFdMTII9ec9t/FK8va6kYcC8/LggumssLM8kNv7IdFl3VrNUqgir2tJuBVxBga1QBoRziZacO5Zg==", + "dev": true, + "inBundle": true, + "optional": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/fsevents/node_modules/har-schema": { + "version": "1.0.5", + "integrity": "sha512-f8xf2GOR6Rgwc9FPTLNzgwB+JQ2/zMauYXSWmX5YV5acex6VomT0ocSuwR7BfXo5MpHi+jL+saaux2fwsGJDKQ==", + "dev": true, + "inBundle": true, + "optional": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/fsevents/node_modules/har-validator": { + "version": "4.2.1", + "integrity": "sha512-5Gbp6RAftMYYV3UEI4c4Vv3+a4dQ7taVyvHt+/L6kRt+f4HX1GweAk5UDWN0SvdVnRBzGQ6OG89pGaD9uSFnVw==", + "deprecated": "this library is no longer supported", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "ajv": "^4.9.1", + "har-schema": "^1.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/fsevents/node_modules/has-unicode": { + "version": "2.0.1", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/hawk": { + "version": "3.1.3", + "integrity": "sha512-X8xbmTc1cbPXcQV4WkLcRMALuyoxhfpFATmyuCxJPOAvrDS4DNnsTAOmKUxMTOWU6TzrTOkxPKwIx5ZOpJVSrg==", + "deprecated": "This module moved to @hapi/hawk. Please make sure to switch over as this distribution is no longer supported and may contain bugs and critical security issues.", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "boom": "2.x.x", + "cryptiles": "2.x.x", + "hoek": "2.x.x", + "sntp": "1.x.x" + }, + "engines": { + "node": ">=0.10.32" + } + }, + "node_modules/fsevents/node_modules/hoek": { + "version": "2.16.3", + "integrity": "sha512-V6Yw1rIcYV/4JsnggjBU0l4Kr+EXhpwqXRusENU1Xx6ro00IHPHYNynCuBTOZAPlr3AAmLvchH9I7N/VUdvOwQ==", + "deprecated": "This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).", + "dev": true, + "inBundle": true, + "optional": true, + "engines": { + "node": ">=0.10.40" + } + }, + "node_modules/fsevents/node_modules/http-signature": { + "version": "1.1.1", + "integrity": "sha512-iUn0NcRULlDGtqNLN1Jxmzayk8ogm7NToldASyZBpM2qggbphjXzNOiw3piN8tgz+e/DRs6X5gAzFwTI6BCRcg==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "assert-plus": "^0.2.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/fsevents/node_modules/inflight": { + "version": "1.0.6", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/fsevents/node_modules/inherits": { + "version": "2.0.3", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/ini": { + "version": "1.3.4", + "integrity": "sha512-VUA7WAWNCWfm6/8f9kAb8Y6iGBWnmCfgFS5dTrv2C38LLm1KUmpY388mCVCJCsMKQomvOQ1oW8/edXdChd9ZXQ==", + "deprecated": "Please update to ini >=1.3.6 to avoid a prototype pollution issue", + "dev": true, + "inBundle": true, + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/fsevents/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fsevents/node_modules/is-typedarray": { + "version": "1.0.0", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/isarray": { + "version": "1.0.0", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/isstream": { + "version": "0.1.2", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/jodid25519": { + "version": "1.0.2", + "integrity": "sha512-b2Zna/wGIyTzi0Gemg27JYUaRyTyBETw5GnqyVQMr71uojOYMrgkD2+Px3bG2ZFi7/zTUXJSDoGoBOhMixq7tg==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "jsbn": "~0.1.0" + } + }, + "node_modules/fsevents/node_modules/jsbn": { + "version": "0.1.1", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/json-schema": { + "version": "0.2.3", + "integrity": "sha512-a3xHnILGMtk+hDOqNwHzF6e2fNbiMrXZvxKQiEv2MlgQP+pjIOzqAmKYD2mDpXYE/44M7g+n9p2bKkYWDUcXCQ==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/json-stable-stringify": { + "version": "1.0.1", + "integrity": "sha512-i/J297TW6xyj7sDFa7AmBPkQvLIxWr2kKPWI26tXydnZrzVAocNqn5DMNT1Mzk0vit1V5UkRM7C1KdVNp7Lmcg==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "jsonify": "~0.0.0" + } + }, + "node_modules/fsevents/node_modules/json-stringify-safe": { + "version": "5.0.1", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/jsonify": { + "version": "0.0.0", + "integrity": "sha512-trvBk1ki43VZptdBI5rIlG4YOzyeH/WefQt5rj1grasPn4iiZWKet8nkgc4GlsAylaztn0qZfUYOiTsASJFdNA==", + "dev": true, + "inBundle": true, + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/fsevents/node_modules/jsprim": { + "version": "1.4.0", + "integrity": "sha512-OyKQuabgqUi2RUPauBrfZNoCb0KNoulf1DqQ07rUW2vzauzXAq/uUe7oDstV/2RavaxGn7NfcI/F2hrBk38Fbg==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "inBundle": true, + "optional": true, + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.0.2", + "json-schema": "0.2.3", + "verror": "1.3.6" + } + }, + "node_modules/fsevents/node_modules/jsprim/node_modules/assert-plus": { + "version": "1.0.0", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true, + "inBundle": true, + "optional": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/fsevents/node_modules/mime-db": { + "version": "1.27.0", + "integrity": "sha512-DNhC90PjVkQJpLVP+ct0lmKPQWAHFy+67X8IBOx+mda/I9vsrdJO/zoyEJdQdLsofi/l8GAG+IsfB0XCPLyLHg==", + "dev": true, + "inBundle": true, + "optional": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fsevents/node_modules/mime-types": { + "version": "2.1.15", + "integrity": "sha512-PjleM8evsL+OvsuE6EXom+8QAcSYALjmw+vYFqH8I+/+wNlewVgbM7/O1wcdCVL/ta8SC6l6BEK7A0/mZywpfg==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "mime-db": "~1.27.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fsevents/node_modules/minimatch": { + "version": "3.0.4", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/fsevents/node_modules/minimist": { + "version": "0.0.8", + "integrity": "sha512-miQKw5Hv4NS1Psg2517mV4e4dYNaO3++hjAvLOAzKqZ61rH8NS1SK+vbfBWZ5PY/Me/bEWhUwqMghEW5Fb9T7Q==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/mkdirp": { + "version": "0.5.1", + "integrity": "sha512-SknJC52obPfGQPnjIkXbmA6+5H15E+fR+E4iR2oQ3zzCLbd7/ONua69R/Gw7AgkTLsRG+r5fzksYwWe1AgTyWA==", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "minimist": "0.0.8" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/fsevents/node_modules/ms": { + "version": "2.0.0", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/node-pre-gyp": { + "version": "0.6.39", + "integrity": "sha512-OsJV74qxnvz/AMGgcfZoDaeDXKD3oY3QVIbBmwszTFkRisTSXbMQyn4UWzUMOtA5SVhrBZOTp0wcoSBgfMfMmQ==", + "deprecated": "Please upgrade to @mapbox/node-pre-gyp: the non-scoped node-pre-gyp package is deprecated and only the @mapbox scoped package will recieve updates in the future", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "detect-libc": "^1.0.2", + "hawk": "3.1.3", + "mkdirp": "^0.5.1", + "nopt": "^4.0.1", + "npmlog": "^4.0.2", + "rc": "^1.1.7", + "request": "2.81.0", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^2.2.1", + "tar-pack": "^3.4.0" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/fsevents/node_modules/nopt": { + "version": "4.0.1", + "integrity": "sha512-+5XZFpQZEY0cg5JaxLwGxDlKNKYxuXwGt8/Oi3UXm5/4ymrJve9d2CURituxv3rSrVCGZj4m1U1JlHTdcKt2Ng==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "abbrev": "1", + "osenv": "^0.1.4" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/fsevents/node_modules/npmlog": { + "version": "4.1.0", + "integrity": "sha512-ocolIkZYZt8UveuiDS0yAkkIjid1o7lPG8cYm05yNYzBn8ykQtaiPMEGp8fY9tKdDgm8okpdKzkvu1y9hUYugA==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "node_modules/fsevents/node_modules/number-is-nan": { + "version": "1.0.1", + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", + "dev": true, + "inBundle": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fsevents/node_modules/oauth-sign": { + "version": "0.8.2", + "integrity": "sha512-VlF07iu3VV3+BTXj43Nmp6Irt/G7j/NgEctUS6IweH1RGhURjjCc2NWtzXFPXXWWfc7hgbXQdtiQu2LGp6MxUg==", + "dev": true, + "inBundle": true, + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/fsevents/node_modules/object-assign": { + "version": "4.1.1", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "inBundle": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fsevents/node_modules/once": { + "version": "1.4.0", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/fsevents/node_modules/os-homedir": { + "version": "1.0.2", + "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", + "dev": true, + "inBundle": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fsevents/node_modules/os-tmpdir": { + "version": "1.0.2", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "inBundle": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fsevents/node_modules/osenv": { + "version": "0.1.4", + "integrity": "sha512-W6FhbLxEWdiyX2/fCl2YBZUJOYWaCHJa+jJwUVMX0iFYJmwyd0uzKx4NxFdj3xo9C0pumQ6G/fvd1MbNhsqQbQ==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "node_modules/fsevents/node_modules/path-is-absolute": { + "version": "1.0.1", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "inBundle": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fsevents/node_modules/performance-now": { + "version": "0.2.0", + "integrity": "sha512-YHk5ez1hmMR5LOkb9iJkLKqoBlL7WD5M8ljC75ZfzXriuBIVNuecaXuU7e+hOwyqf24Wxhh7Vxgt7Hnw9288Tg==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/process-nextick-args": { + "version": "1.0.7", + "integrity": "sha512-yN0WQmuCX63LP/TMvAg31nvT6m4vDqJEiiv2CAZqWOGNWutc9DfDk1NPYYmKUFmaVM2UwDowH4u5AHWYP/jxKw==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/punycode": { + "version": "1.4.1", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/qs": { + "version": "6.4.0", + "integrity": "sha512-Qs6dfgR5OksK/PSxl1kGxiZgEQe8RqJMB9wZqVlKQfU+zzV+HY77pWJnoJENACKDQByWdpr8ZPIh1TBi4lpiSQ==", + "dev": true, + "inBundle": true, + "optional": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/fsevents/node_modules/rc": { + "version": "1.2.1", + "integrity": "sha512-5kLVpOvFh6zdjGL2+UmCXd/nonPuxsRjM0LktPM6CtpFYOrZSd9rF4tveeMtql3HU6AsAovgqR8k9HQOSfXLMQ==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "deep-extend": "~0.4.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "index.js" + } + }, + "node_modules/fsevents/node_modules/rc/node_modules/minimist": { + "version": "1.2.0", + "integrity": "sha512-7Wl+Jz+IGWuSdgsQEJ4JunV0si/iMhg42MnQQG6h1R6TNeVenp4U9x5CC5v/gYqz/fENLQITAWXidNtVL0NNbw==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/readable-stream": { + "version": "2.2.9", + "integrity": "sha512-iuxqX7b7FYt08AriYECxUsK9KTXE3A/FenxIa3IPmvANHxaTP/wGIwwf+IidvvIDk/MsCp/oEV6A8CXo4SDcCg==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "buffer-shims": "~1.0.0", + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~1.0.0", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/fsevents/node_modules/request": { + "version": "2.81.0", + "integrity": "sha512-IZnsR7voF0miGSu29EXPRgPTuEsI/+aibNSBbN1pplrfartF5wDYGADz3iD9vmBVf2r00rckWZf8BtS5kk7Niw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "aws-sign2": "~0.6.0", + "aws4": "^1.2.1", + "caseless": "~0.12.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.0", + "forever-agent": "~0.6.1", + "form-data": "~2.1.1", + "har-validator": "~4.2.1", + "hawk": "~3.1.3", + "http-signature": "~1.1.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.7", + "oauth-sign": "~0.8.1", + "performance-now": "^0.2.0", + "qs": "~6.4.0", + "safe-buffer": "^5.0.1", + "stringstream": "~0.0.4", + "tough-cookie": "~2.3.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.0.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/fsevents/node_modules/rimraf": { + "version": "2.6.1", + "integrity": "sha512-5QIcndZ8am2WyseL6lln/utl51SwRBQs/at+zi1UnhsnPyZcAID+g0PZrKdb+kJn2fo/CwgyJweR8sP36Jer5g==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "glob": "^7.0.5" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/fsevents/node_modules/safe-buffer": { + "version": "5.0.1", + "integrity": "sha512-cr7dZWLwOeaFBLTIuZeYdkfO7UzGIKhjYENJFAxUOMKWGaWDm2nJM2rzxNRm5Owu0DH3ApwNo6kx5idXZfb/Iw==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/semver": { + "version": "5.3.0", + "integrity": "sha512-mfmm3/H9+67MCVix1h+IXTpDwL6710LyHuk7+cWC9T1mE0qz4iHhh6r4hU2wrIT9iTsAAC2XQRvfblL028cpLw==", + "dev": true, + "inBundle": true, + "optional": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/fsevents/node_modules/set-blocking": { + "version": "2.0.0", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/signal-exit": { + "version": "3.0.2", + "integrity": "sha512-meQNNykwecVxdu1RlYMKpQx4+wefIYpmxi6gexo/KAbwquJrBUrBmKYJrE8KFkVQAAVWEnwNdu21PgrD77J3xA==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/sntp": { + "version": "1.0.9", + "integrity": "sha512-7bgVOAnPj3XjrKY577S+puCKGCRlUrcrEdsMeRXlg9Ghf5df/xNi6sONUa43WrHUd3TjJBF7O04jYoiY0FVa0A==", + "deprecated": "This module moved to @hapi/sntp. Please make sure to switch over as this distribution is no longer supported and may contain bugs and critical security issues.", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "hoek": "2.x.x" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fsevents/node_modules/sshpk": { + "version": "1.13.0", + "integrity": "sha512-4pjoCmB+Vta6odJ3nrT2zf223+xW6mOJfYtHGX7n5CZUAVm6GhuHLbKeai3c0XoWCu6ZNyPo3Nf71CaUbgck2g==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "dashdash": "^1.12.0", + "getpass": "^0.1.1" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + }, + "optionalDependencies": { + "bcrypt-pbkdf": "^1.0.0", + "ecc-jsbn": "~0.1.1", + "jodid25519": "^1.0.0", + "jsbn": "~0.1.0", + "tweetnacl": "~0.14.0" + } + }, + "node_modules/fsevents/node_modules/sshpk/node_modules/assert-plus": { + "version": "1.0.0", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true, + "inBundle": true, + "optional": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/fsevents/node_modules/string_decoder": { + "version": "1.0.1", + "integrity": "sha512-Ma/XSGC8lfDvw75eLjgg/a1nWDButtedmpbbNxH5Ruyr0IhqNXOKbG468VtPosrjhRgNOvgonmY54ZnGMdgJjw==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/fsevents/node_modules/string-width": { + "version": "1.0.2", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fsevents/node_modules/stringstream": { + "version": "0.0.5", + "integrity": "sha512-QUQ1kThMjLRt4jA8lsn9lyIkE9bKafE7LDOL/nBBUY9Tfv2i3x1NAsVHG0uMCusFOWeeI6COhY/F20+avxRWSw==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/strip-ansi": { + "version": "3.0.1", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fsevents/node_modules/strip-json-comments": { + "version": "2.0.1", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "inBundle": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fsevents/node_modules/tar": { + "version": "2.2.1", + "integrity": "sha512-2Tw2uNtZqQTSHTIMbKHKFeAPmKcljrNKqKiIN7pu3V/CxYqRgS8DLXvMkFRrbtXlg6mTOQcuTX7DMj18Xi0dtg==", + "deprecated": "This version of tar is no longer supported, and will not receive security updates. Please upgrade asap.", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "block-stream": "*", + "fstream": "^1.0.2", + "inherits": "2" + } + }, + "node_modules/fsevents/node_modules/tar-pack": { + "version": "3.4.0", + "integrity": "sha512-mggElLHZCDZK1J8rHZqdqJ09zY9F8aW7CgbhHjXZKCfgVU6TqUPhM6okl3z8bRWfOoJBBRKoIOrwPbahCHV64w==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "debug": "^2.2.0", + "fstream": "^1.0.10", + "fstream-ignore": "^1.0.5", + "once": "^1.3.3", + "readable-stream": "^2.1.4", + "rimraf": "^2.5.1", + "tar": "^2.2.1", + "uid-number": "^0.0.6" + } + }, + "node_modules/fsevents/node_modules/tough-cookie": { + "version": "2.3.2", + "integrity": "sha512-42UXjmzk88F7URyg9wDV/dlQ7hXtl/SDV6xIMVdDq82cnDGQDyg8mI8xGBPOwpEfbhvrja6cJ8H1wr0xxykBKA==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "punycode": "^1.4.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/fsevents/node_modules/tunnel-agent": { + "version": "0.6.0", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "inBundle": true, + "optional": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/fsevents/node_modules/tweetnacl": { + "version": "0.14.5", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/fsevents/node_modules/uid-number": { + "version": "0.0.6", + "integrity": "sha512-c461FXIljswCuscZn67xq9PpszkPT6RjheWFQTgCyabJrTUozElanb0YEqv2UGgk247YpcJkFBuSGNvBlpXM9w==", + "dev": true, + "inBundle": true, + "optional": true, + "engines": { + "node": "*" } }, - "for-in": { + "node_modules/fsevents/node_modules/util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "for-own": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", - "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true, - "requires": { - "for-in": "^1.0.1" - } - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true + "inBundle": true, + "optional": true }, - "form-data": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", - "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", + "node_modules/fsevents/node_modules/uuid": { + "version": "3.0.1", + "integrity": "sha512-tyhM7iisckwwmyHVFcjTzISz/R1ss/bRudNgHFYsgeu7j4JbhRvjE+Hbcpr9y5xh+b+HxeFjuToDT4i9kQNrtA==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.5", - "mime-types": "^2.1.12" + "inBundle": true, + "optional": true, + "bin": { + "uuid": "bin/uuid" } }, - "fs-extra": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", - "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", + "node_modules/fsevents/node_modules/verror": { + "version": "1.3.6", + "integrity": "sha512-i8GFYwImt5D5B8CPpi2jrDTy/faq4OEW+NkOTLSKcIdPfdYJvWv3VZddDKl0ByvBe6cJ2s5Mm2XDtv5c2pj/Eg==", "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "klaw": "^1.0.0" - }, + "engines": [ + "node >=0.6.0" + ], + "inBundle": true, + "optional": true, "dependencies": { - "klaw": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", - "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.9" - } - } + "extsprintf": "1.0.2" } }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.3.tgz", - "integrity": "sha512-WIr7iDkdmdbxu/Gh6eKEZJL6KPE74/5MEsf2whTOFNxbIoIixogroLdKYqB6FDav4Wavh/lZdzzd3b2KxIXC5Q==", + "node_modules/fsevents/node_modules/wide-align": { + "version": "1.1.2", + "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", "dev": true, + "inBundle": true, "optional": true, - "requires": { - "nan": "^2.3.0", - "node-pre-gyp": "^0.6.39" - }, "dependencies": { - "abbrev": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "ajv": { - "version": "4.11.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "co": "^4.6.0", - "json-stable-stringify": "^1.0.1" - } - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "aproba": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "asn1": { - "version": "0.2.3", - "bundled": true, - "dev": true, - "optional": true - }, - "assert-plus": { - "version": "0.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "asynckit": { - "version": "0.4.0", - "bundled": true, - "dev": true, - "optional": true - }, - "aws-sign2": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "aws4": { - "version": "1.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "balanced-match": { - "version": "0.4.2", - "bundled": true, - "dev": true, - "optional": true - }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "block-stream": { - "version": "0.0.9", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "inherits": "~2.0.0" - } - }, - "boom": { - "version": "2.10.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "hoek": "2.x.x" - } - }, - "brace-expansion": { - "version": "1.1.7", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "balanced-match": "^0.4.1", - "concat-map": "0.0.1" - } - }, - "buffer-shims": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "caseless": { - "version": "0.12.0", - "bundled": true, - "dev": true, - "optional": true - }, - "co": { - "version": "4.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "combined-stream": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "cryptiles": { - "version": "2.0.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "boom": "2.x.x" - } - }, - "dashdash": { - "version": "1.14.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "^1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "debug": { - "version": "2.6.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ms": "2.0.0" - } - }, - "deep-extend": { - "version": "0.4.2", - "bundled": true, - "dev": true, - "optional": true - }, - "delayed-stream": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "ecc-jsbn": { - "version": "0.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "jsbn": "~0.1.0" - } - }, - "extend": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "extsprintf": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "forever-agent": { - "version": "0.6.1", - "bundled": true, - "dev": true, - "optional": true - }, - "form-data": { - "version": "2.1.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.5", - "mime-types": "^2.1.12" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "fstream": { - "version": "1.0.11", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" - } - }, - "fstream-ignore": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "fstream": "^1.0.0", - "inherits": "2", - "minimatch": "^3.0.0" - } - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "getpass": { - "version": "0.1.7", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "^1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "glob": { - "version": "7.1.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "graceful-fs": { - "version": "4.1.11", - "bundled": true, - "dev": true, - "optional": true - }, - "har-schema": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "optional": true - }, - "har-validator": { - "version": "4.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ajv": "^4.9.1", - "har-schema": "^1.0.5" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "hawk": { - "version": "3.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "boom": "2.x.x", - "cryptiles": "2.x.x", - "hoek": "2.x.x", - "sntp": "1.x.x" - } - }, - "hoek": { - "version": "2.16.3", - "bundled": true, - "dev": true, - "optional": true - }, - "http-signature": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "^0.2.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "ini": { - "version": "1.3.4", - "bundled": true, - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "is-typedarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "isstream": { - "version": "0.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "jodid25519": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "jsbn": "~0.1.0" - } - }, - "jsbn": { - "version": "0.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "json-schema": { - "version": "0.2.3", - "bundled": true, - "dev": true, - "optional": true - }, - "json-stable-stringify": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "jsonify": "~0.0.0" - } - }, - "json-stringify-safe": { - "version": "5.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "jsonify": { - "version": "0.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "jsprim": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.0.2", - "json-schema": "0.2.3", - "verror": "1.3.6" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "mime-db": { - "version": "1.27.0", - "bundled": true, - "dev": true, - "optional": true - }, - "mime-types": { - "version": "2.1.15", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "mime-db": "~1.27.0" - } - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "dev": true, - "optional": true - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "node-pre-gyp": { - "version": "0.6.39", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "hawk": "3.1.3", - "mkdirp": "^0.5.1", - "nopt": "^4.0.1", - "npmlog": "^4.0.2", - "rc": "^1.1.7", - "request": "2.81.0", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^2.2.1", - "tar-pack": "^3.4.0" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npmlog": { - "version": "4.1.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "oauth-sign": { - "version": "0.8.2", - "bundled": true, - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "performance-now": { - "version": "0.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "1.0.7", - "bundled": true, - "dev": true, - "optional": true - }, - "punycode": { - "version": "1.4.1", - "bundled": true, - "dev": true, - "optional": true - }, - "qs": { - "version": "6.4.0", - "bundled": true, - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "deep-extend": "~0.4.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.2.9", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "buffer-shims": "~1.0.0", - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", - "string_decoder": "~1.0.0", - "util-deprecate": "~1.0.1" - } - }, - "request": { - "version": "2.81.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aws-sign2": "~0.6.0", - "aws4": "^1.2.1", - "caseless": "~0.12.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.0", - "forever-agent": "~0.6.1", - "form-data": "~2.1.1", - "har-validator": "~4.2.1", - "hawk": "~3.1.3", - "http-signature": "~1.1.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.7", - "oauth-sign": "~0.8.1", - "performance-now": "^0.2.0", - "qs": "~6.4.0", - "safe-buffer": "^5.0.1", - "stringstream": "~0.0.4", - "tough-cookie": "~2.3.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.0.0" - } - }, - "rimraf": { - "version": "2.6.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "glob": "^7.0.5" - } - }, - "safe-buffer": { - "version": "5.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "semver": { - "version": "5.3.0", - "bundled": true, - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "sntp": { - "version": "1.0.9", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "hoek": "2.x.x" - } - }, - "sshpk": { - "version": "1.13.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jodid25519": "^1.0.0", - "jsbn": "~0.1.0", - "tweetnacl": "~0.14.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "stringstream": { - "version": "0.0.5", - "bundled": true, - "dev": true, - "optional": true - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "tar": { - "version": "2.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "block-stream": "*", - "fstream": "^1.0.2", - "inherits": "2" - } - }, - "tar-pack": { - "version": "3.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "debug": "^2.2.0", - "fstream": "^1.0.10", - "fstream-ignore": "^1.0.5", - "once": "^1.3.3", - "readable-stream": "^2.1.4", - "rimraf": "^2.5.1", - "tar": "^2.2.1", - "uid-number": "^0.0.6" - } - }, - "tough-cookie": { - "version": "2.3.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "punycode": "^1.4.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "bundled": true, - "dev": true, - "optional": true - }, - "uid-number": { - "version": "0.0.6", - "bundled": true, - "dev": true, - "optional": true - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "uuid": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "verror": { - "version": "1.3.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "extsprintf": "1.0.2" - } - }, - "wide-align": { - "version": "1.1.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "string-width": "^1.0.2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "generate-function": { + "string-width": "^1.0.2" + } + }, + "node_modules/fsevents/node_modules/wrappy": { + "version": "1.0.2", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "inBundle": true, + "optional": true + }, + "node_modules/generate-function": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", "dev": true }, - "generate-object-property": { + "node_modules/generate-object-property": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", "dev": true, - "requires": { + "dependencies": { "is-property": "^1.0.0" } }, - "get-stdin": { + "node_modules/get-stdin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "getpass": { + "node_modules/getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "dev": true, - "requires": { + "dependencies": { "assert-plus": "^1.0.0" } }, - "glob": { + "node_modules/glob": { "version": "5.0.15", "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", "dev": true, - "requires": { + "dependencies": { "inflight": "^1.0.4", "inherits": "2", "minimatch": "2 || 3", "once": "^1.3.0", "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" } }, - "glob-base": { + "node_modules/glob-base": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", "dev": true, - "requires": { + "dependencies": { "glob-parent": "^2.0.0", "is-glob": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "glob-parent": { + "node_modules/glob-parent": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", "dev": true, - "requires": { + "dependencies": { "is-glob": "^2.0.0" } }, - "graceful-fs": { + "node_modules/graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.4.0" + } }, - "growl": { + "node_modules/growl": { "version": "1.9.2", "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", "dev": true }, - "handlebars": { + "node_modules/handlebars": { "version": "4.0.11", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz", "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", "dev": true, - "requires": { + "dependencies": { "async": "^1.4.0", "optimist": "^0.6.1", - "source-map": "^0.4.4", - "uglify-js": "^2.6" + "source-map": "^0.4.4" + }, + "bin": { + "handlebars": "bin/handlebars" }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^2.6" + } + }, + "node_modules/handlebars/node_modules/source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, "dependencies": { - "source-map": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", - "dev": true, - "requires": { - "amdefine": ">=0.0.4" - } - } + "amdefine": ">=0.0.4" + }, + "engines": { + "node": ">=0.8.0" } }, - "har-schema": { + "node_modules/har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true + "dev": true, + "engines": { + "node": ">=4" + } }, - "har-validator": { + "node_modules/har-validator": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "deprecated": "this library is no longer supported", "dev": true, - "requires": { + "dependencies": { "ajv": "^5.1.0", "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=4" } }, - "has-ansi": { + "node_modules/has-ansi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, - "requires": { + "dependencies": { "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "has-binary": { + "node_modules/has-binary": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/has-binary/-/has-binary-0.1.7.tgz", "integrity": "sha1-aOYesWIQyVRaClzOBqhzkS/h5ow=", "dev": true, - "requires": { + "dependencies": { "isarray": "0.0.1" } }, - "has-cors": { + "node_modules/has-cors": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=", "dev": true }, - "has-flag": { + "node_modules/has-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "hasha": { + "node_modules/hasha": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/hasha/-/hasha-2.2.0.tgz", "integrity": "sha1-eNfL/B5tZjA/55g3NlmEUXsvbuE=", "dev": true, - "requires": { + "dependencies": { "is-stream": "^1.0.1", "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "hawk": { + "node_modules/hawk": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", + "deprecated": "This module moved to @hapi/hawk. Please make sure to switch over as this distribution is no longer supported and may contain bugs and critical security issues.", "dev": true, - "requires": { + "dependencies": { "boom": "4.x.x", "cryptiles": "3.x.x", "hoek": "4.x.x", "sntp": "2.x.x" + }, + "engines": { + "node": ">=4.5.0" } }, - "hoek": { + "node_modules/hoek": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz", "integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ==", - "dev": true + "deprecated": "This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).", + "dev": true, + "engines": { + "node": ">=4.0.0" + } }, - "hosted-git-info": { + "node_modules/hosted-git-info": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==", "dev": true }, - "htmlparser2": { + "node_modules/htmlparser2": { "version": "3.8.3", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", "dev": true, - "requires": { + "dependencies": { "domelementtype": "1", "domhandler": "2.3", "domutils": "1.5", @@ -2365,263 +2968,322 @@ "readable-stream": "1.1" } }, - "http-errors": { + "node_modules/http-errors": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", "dev": true, - "requires": { + "dependencies": { "depd": "1.1.1", "inherits": "2.0.3", "setprototypeof": "1.0.3", "statuses": ">= 1.3.1 < 2" }, - "dependencies": { - "depd": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", - "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=", - "dev": true - } + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-errors/node_modules/depd": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", + "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=", + "dev": true, + "engines": { + "node": ">= 0.6" } }, - "http-proxy": { + "node_modules/http-proxy": { "version": "1.16.2", "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.16.2.tgz", "integrity": "sha1-Bt/ykpUr9k2+hHH6nfcwZtTzd0I=", "dev": true, - "requires": { + "dependencies": { "eventemitter3": "1.x.x", "requires-port": "1.x.x" + }, + "engines": { + "node": ">=0.10.0" } }, - "http-signature": { + "node_modules/http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "dev": true, - "requires": { + "dependencies": { "assert-plus": "^1.0.0", "jsprim": "^1.2.2", "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" } }, - "iconv-lite": { + "node_modules/iconv-lite": { "version": "0.4.19", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "indent-string": { + "node_modules/indent-string": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", "dev": true, - "requires": { + "dependencies": { "repeating": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "indexof": { + "node_modules/indexof": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", "dev": true }, - "inflight": { + "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, - "requires": { + "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, - "inherits": { + "node_modules/inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, - "is-arrayish": { + "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, - "is-binary-path": { + "node_modules/is-binary-path": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", "dev": true, - "requires": { + "dependencies": { "binary-extensions": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "is-buffer": { + "node_modules/is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, - "is-builtin-module": { + "node_modules/is-builtin-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "dev": true, - "requires": { + "dependencies": { "builtin-modules": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "is-dotfile": { + "node_modules/is-dotfile": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "is-equal-shallow": { + "node_modules/is-equal-shallow": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", "dev": true, - "requires": { + "dependencies": { "is-primitive": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "is-extendable": { + "node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "is-extglob": { + "node_modules/is-extglob": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "is-finite": { + "node_modules/is-finite": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", "dev": true, - "requires": { + "dependencies": { "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "is-glob": { + "node_modules/is-glob": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", "dev": true, - "requires": { + "dependencies": { "is-extglob": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "is-my-json-valid": { + "node_modules/is-my-json-valid": { "version": "2.17.1", "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.17.1.tgz", "integrity": "sha512-Q2khNw+oBlWuaYvEEHtKSw/pCxD2L5Rc1C+UQme9X6JdRDh7m5D7HkozA0qa3DUkQ6VzCnEm8mVIQPyIRkI5sQ==", + "deprecated": "catastrophic backtracking in regexes could potentially lead to REDOS attack, upgrade to 2.17.2 as soon as possible", "dev": true, - "requires": { + "dependencies": { "generate-function": "^2.0.0", "generate-object-property": "^1.1.0", "jsonpointer": "^4.0.0", "xtend": "^4.0.0" } }, - "is-number": { + "node_modules/is-number": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", "dev": true, - "requires": { + "dependencies": { "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" } }, - "is-posix-bracket": { + "node_modules/is-posix-bracket": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "is-primitive": { + "node_modules/is-primitive": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "is-property": { + "node_modules/is-property": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", "dev": true }, - "is-stream": { + "node_modules/is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "is-typedarray": { + "node_modules/is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "dev": true }, - "is-utf8": { + "node_modules/is-utf8": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", "dev": true }, - "isarray": { + "node_modules/isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", "dev": true }, - "isbinaryfile": { + "node_modules/isbinaryfile": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.2.tgz", "integrity": "sha1-Sj6XTsDLqQBNP8bN5yCeppNopiE=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.6.0" + } }, - "isexe": { + "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "isobject": { + "node_modules/isobject": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", "dev": true, - "requires": { + "dependencies": { "isarray": "1.0.0" }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - } + "engines": { + "node": ">=0.10.0" } }, - "isstream": { + "node_modules/isobject/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "node_modules/isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", "dev": true }, - "istanbul": { + "node_modules/istanbul": { "version": "0.4.5", "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", + "deprecated": "This module is no longer maintained, try this instead:\n npm i nyc\nVisit https://istanbul.js.org/integrations for other alternatives.", "dev": true, - "requires": { + "dependencies": { "abbrev": "1.0.x", "async": "1.x", "escodegen": "1.8.x", @@ -2636,105 +3298,129 @@ "supports-color": "^3.1.0", "which": "^1.1.1", "wordwrap": "^1.0.0" + }, + "bin": { + "istanbul": "lib/cli.js" } }, - "jade": { + "node_modules/jade": { "version": "0.26.3", "resolved": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz", "integrity": "sha1-jxDXl32NefL2/4YqgbBRPMslaGw=", + "deprecated": "Jade has been renamed to pug, please install the latest version of pug instead of jade", "dev": true, - "requires": { + "dependencies": { "commander": "0.6.1", "mkdirp": "0.3.0" }, - "dependencies": { - "commander": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", - "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=", - "dev": true - }, - "mkdirp": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", - "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=", - "dev": true - } + "bin": { + "jade": "bin/jade" + } + }, + "node_modules/jade/node_modules/commander": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", + "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=", + "dev": true, + "engines": { + "node": ">= 0.4.x" + } + }, + "node_modules/jade/node_modules/mkdirp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", + "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "dev": true, + "engines": { + "node": "*" } }, - "jasmine": { + "node_modules/jasmine": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.9.0.tgz", "integrity": "sha1-dlcfklyHg0CefGFTVy5aY0HPk+s=", "dev": true, - "requires": { + "dependencies": { "exit": "^0.1.2", "glob": "^7.0.6", "jasmine-core": "~2.9.0" }, - "dependencies": { - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } + "bin": { + "jasmine": "bin/jasmine.js" } }, - "jasmine-core": { + "node_modules/jasmine-core": { "version": "2.9.1", "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.9.1.tgz", "integrity": "sha1-trvB2OZSUNVvWIhGFwXr7uuI8i8=", "dev": true }, - "js-yaml": { + "node_modules/jasmine/node_modules/glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/js-yaml": { "version": "3.10.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz", "integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==", "dev": true, - "requires": { + "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, - "dependencies": { - "esprima": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", - "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", - "dev": true - } + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/js-yaml/node_modules/esprima": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", + "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" } }, - "js2xmlparser": { + "node_modules/js2xmlparser": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-3.0.0.tgz", "integrity": "sha1-P7YOqgicVED5MZ9RdgzNB+JJlzM=", "dev": true, - "requires": { + "dependencies": { "xmlcreate": "^1.0.1" } }, - "jsbn": { + "node_modules/jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", "dev": true, "optional": true }, - "jsdoc": { + "node_modules/jsdoc": { "version": "3.5.5", "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.5.5.tgz", "integrity": "sha512-6PxB65TAU4WO0Wzyr/4/YhlGovXl0EVYfpKbpSroSj0qBxT4/xod/l40Opkm38dRHRdQgdeY836M0uVnJQG7kg==", "dev": true, - "requires": { + "dependencies": { "babylon": "7.0.0-beta.19", "bluebird": "~3.5.0", "catharsis": "~0.8.9", @@ -2747,14 +3433,20 @@ "strip-json-comments": "~2.0.1", "taffydb": "2.6.2", "underscore": "~1.8.3" + }, + "bin": { + "jsdoc": "jsdoc.js" + }, + "engines": { + "node": ">=4.2.0" } }, - "jshint": { + "node_modules/jshint": { "version": "2.9.5", "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.9.5.tgz", "integrity": "sha1-HnJSkVzmgbQIJ+4UJIxG006apiw=", "dev": true, - "requires": { + "dependencies": { "cli": "~1.0.0", "console-browserify": "1.1.x", "exit": "0.1.x", @@ -2764,72 +3456,86 @@ "shelljs": "0.3.x", "strip-json-comments": "1.0.x" }, - "dependencies": { - "strip-json-comments": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", - "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", - "dev": true - } + "bin": { + "jshint": "bin/jshint" + } + }, + "node_modules/jshint/node_modules/strip-json-comments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", + "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", + "dev": true, + "bin": { + "strip-json-comments": "cli.js" + }, + "engines": { + "node": ">=0.8.0" } }, - "json-schema": { + "node_modules/json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", "dev": true }, - "json-schema-traverse": { + "node_modules/json-schema-traverse": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", "dev": true }, - "json-stringify-safe": { + "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", "dev": true }, - "json3": { + "node_modules/json3": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", + "deprecated": "Please use the native JSON object instead of JSON 3", "dev": true }, - "jsonfile": { + "node_modules/jsonfile": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", "dev": true, - "requires": { + "optionalDependencies": { "graceful-fs": "^4.1.6" } }, - "jsonpointer": { + "node_modules/jsonpointer": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "jsprim": { + "node_modules/jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", "dev": true, - "requires": { + "engines": [ + "node >=0.6.0" + ], + "dependencies": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", "json-schema": "0.2.3", "verror": "1.10.0" } }, - "karma": { + "node_modules/karma": { "version": "1.7.1", "resolved": "https://registry.npmjs.org/karma/-/karma-1.7.1.tgz", "integrity": "sha512-k5pBjHDhmkdaUccnC7gE3mBzZjcxyxYsYVaqiL2G5AqlfLyBO5nw2VdNK+O16cveEPd/gIOWULH7gkiYYwVNHg==", "dev": true, - "requires": { + "dependencies": { "bluebird": "^3.3.0", "body-parser": "^1.16.1", "chokidar": "^1.4.1", @@ -2858,241 +3564,315 @@ "tmp": "0.0.31", "useragent": "^2.1.12" }, + "bin": { + "karma": "bin/karma" + }, + "engines": { + "node": "0.10 || 0.12 || 4 || 5 || 6 || 7 || 8" + } + }, + "node_modules/karma-chrome-launcher": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.2.0.tgz", + "integrity": "sha512-rE9RkUPI7I9mAxByQWkGJFXfFD6lE4gC5nPuZdobf/QdTEJI6EU4yIay/cfU/xV4ZxlM5JiTv7zWYgA64NpS5Q==", + "dev": true, "dependencies": { - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "lodash": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", - "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "karma-cli": { + "which": "^1.2.1" + } + }, + "node_modules/karma-cli": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/karma-cli/-/karma-cli-1.0.1.tgz", "integrity": "sha1-rmw8WKMTodALRRZMRVubhs4X+WA=", "dev": true, - "requires": { + "dependencies": { "resolve": "^1.1.6" + }, + "bin": { + "karma": "bin/karma" + }, + "engines": { + "node": "0.10 || 0.12 || 4 || 5 || 6" } }, - "karma-coverage": { + "node_modules/karma-coverage": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/karma-coverage/-/karma-coverage-1.1.1.tgz", "integrity": "sha1-Wv+LOc9plNwi3kyENix2ABtjfPY=", "dev": true, - "requires": { + "dependencies": { "dateformat": "^1.0.6", "istanbul": "^0.4.0", "lodash": "^3.8.0", "minimatch": "^3.0.0", "source-map": "^0.5.1" - }, - "dependencies": { - "lodash": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", - "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } } }, - "karma-jasmine": { + "node_modules/karma-coverage/node_modules/lodash": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", + "dev": true + }, + "node_modules/karma-coverage/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/karma-jasmine": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-1.1.1.tgz", "integrity": "sha1-b+hA51oRYAydkehLM8RY4cRqNSk=", - "dev": true + "dev": true, + "peerDependencies": { + "jasmine-core": "*", + "karma": "*" + } }, - "karma-phantomjs-launcher": { + "node_modules/karma-phantomjs-launcher": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/karma-phantomjs-launcher/-/karma-phantomjs-launcher-1.0.4.tgz", "integrity": "sha1-0jyjSAG9qYY60xjju0vUBisTrNI=", + "deprecated": "PhantomJS development have stopped, use puppeteer or similar", "dev": true, - "requires": { + "dependencies": { "lodash": "^4.0.1", "phantomjs-prebuilt": "^2.1.7" }, + "peerDependencies": { + "karma": ">=0.9" + } + }, + "node_modules/karma-phantomjs-launcher/node_modules/lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + }, + "node_modules/karma-phantomjs-launcher/node_modules/phantomjs-prebuilt": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.16.tgz", + "integrity": "sha1-79ISpKOWbTZHaE6ouniFSb4q7+8=", + "deprecated": "this package is now deprecated", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "es6-promise": "^4.0.3", + "extract-zip": "^1.6.5", + "fs-extra": "^1.0.0", + "hasha": "^2.2.0", + "kew": "^0.7.0", + "progress": "^1.1.8", + "request": "^2.81.0", + "request-progress": "^2.0.1", + "which": "^1.2.10" + }, + "bin": { + "phantomjs": "bin/phantomjs" + } + }, + "node_modules/karma/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true + }, + "node_modules/karma/node_modules/glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, "dependencies": { - "lodash": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", - "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", - "dev": true - }, - "phantomjs-prebuilt": { - "version": "2.1.16", - "resolved": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.16.tgz", - "integrity": "sha1-79ISpKOWbTZHaE6ouniFSb4q7+8=", - "dev": true, - "requires": { - "es6-promise": "^4.0.3", - "extract-zip": "^1.6.5", - "fs-extra": "^1.0.0", - "hasha": "^2.2.0", - "kew": "^0.7.0", - "progress": "^1.1.8", - "request": "^2.81.0", - "request-progress": "^2.0.1", - "which": "^1.2.10" - } - } - } - }, - "kew": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/karma/node_modules/lodash": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", + "dev": true + }, + "node_modules/karma/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kew": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz", "integrity": "sha1-edk9LTM2PW/dKXCzNdkUGtWR15s=", "dev": true }, - "kind-of": { + "node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, - "requires": { + "dependencies": { "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" } }, - "klaw": { + "node_modules/klaw": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/klaw/-/klaw-2.0.0.tgz", "integrity": "sha1-WcEo4Nxc5BAgEVEZTuucv4WGUPY=", "dev": true, - "requires": { + "dependencies": { "graceful-fs": "^4.1.9" } }, - "lazy-cache": { + "node_modules/lazy-cache": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "levn": { + "node_modules/levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", "dev": true, - "requires": { + "dependencies": { "prelude-ls": "~1.1.2", "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" } }, - "load-json-file": { + "node_modules/load-json-file": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, - "requires": { + "dependencies": { "graceful-fs": "^4.1.2", "parse-json": "^2.2.0", "pify": "^2.0.0", "pinkie-promise": "^2.0.0", "strip-bom": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "lodash": { + "node_modules/lodash": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.7.0.tgz", "integrity": "sha1-Nni9irmVBXwHreg27S7wh9qBHUU=", "dev": true }, - "log4js": { + "node_modules/log4js": { "version": "0.6.38", "resolved": "https://registry.npmjs.org/log4js/-/log4js-0.6.38.tgz", "integrity": "sha1-LElBFmldb7JUgJQ9P8hy5mKlIv0=", + "deprecated": "0.x is no longer supported. Please upgrade to 6.x or higher.", "dev": true, - "requires": { + "dependencies": { "readable-stream": "~1.0.2", "semver": "~4.3.3" }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/log4js/node_modules/readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, "dependencies": { - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - } + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" } }, - "longest": { + "node_modules/longest": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "loud-rejection": { + "node_modules/loud-rejection": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", "dev": true, - "requires": { + "dependencies": { "currently-unhandled": "^0.4.1", "signal-exit": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "lru-cache": { + "node_modules/lru-cache": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.2.4.tgz", "integrity": "sha1-bGWGGb7PFAMdDQtZSxYELOTcBj0=", "dev": true }, - "map-obj": { + "node_modules/map-obj": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "marked": { + "node_modules/marked": { "version": "0.3.12", "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.12.tgz", "integrity": "sha512-k4NaW+vS7ytQn6MgJn3fYpQt20/mOgYM5Ft9BYMfQJDz2QT6yEeS9XJ8k2Nw8JTeWK/znPPW2n3UJGzyYEiMoA==", - "dev": true + "dev": true, + "bin": { + "marked": "bin/marked" + } }, - "media-typer": { + "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.6" + } }, - "meow": { + "node_modules/meow": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", "dev": true, - "requires": { + "dependencies": { "camelcase-keys": "^2.0.0", "decamelize": "^1.1.2", "loud-rejection": "^1.0.0", @@ -3104,21 +3884,22 @@ "redent": "^1.0.0", "trim-newlines": "^1.0.0" }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } + "engines": { + "node": ">=0.10.0" } }, - "micromatch": { + "node_modules/meow/node_modules/minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "node_modules/micromatch": { "version": "2.3.11", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", "dev": true, - "requires": { + "dependencies": { "arr-diff": "^2.0.0", "array-unique": "^0.2.1", "braces": "^1.8.2", @@ -3132,67 +3913,87 @@ "object.omit": "^2.0.0", "parse-glob": "^3.0.4", "regex-cache": "^0.4.2" + }, + "engines": { + "node": ">=0.10.0" } }, - "mime": { + "node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } }, - "mime-db": { + "node_modules/mime-db": { "version": "1.30.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.6" + } }, - "mime-types": { + "node_modules/mime-types": { "version": "2.1.17", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", "dev": true, - "requires": { + "dependencies": { "mime-db": "~1.30.0" + }, + "engines": { + "node": ">= 0.6" } }, - "minimatch": { + "node_modules/minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, - "requires": { + "dependencies": { "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, - "minimist": { + "node_modules/minimist": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", "dev": true }, - "mkdirp": { + "node_modules/mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", "dev": true, - "requires": { + "dependencies": { "minimist": "0.0.8" }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - } + "bin": { + "mkdirp": "bin/cmd.js" } }, - "mocha": { + "node_modules/mkdirp/node_modules/minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "node_modules/mocha": { "version": "2.5.3", "resolved": "https://registry.npmjs.org/mocha/-/mocha-2.5.3.tgz", "integrity": "sha1-FhvlvetJZ3HrmzV0UFC2IrWu/Fg=", "dev": true, - "requires": { + "dependencies": { "commander": "2.3.0", "debug": "2.2.0", "diff": "1.4.0", @@ -3204,299 +4005,374 @@ "supports-color": "1.2.0", "to-iso-string": "0.0.2" }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 0.8.x" + } + }, + "node_modules/mocha/node_modules/debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true, + "dependencies": { + "ms": "0.7.1" + } + }, + "node_modules/mocha/node_modules/escape-string-regexp": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", + "integrity": "sha1-Tbwv5nTnGUnK8/smlc5/LcHZqNE=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/mocha/node_modules/glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", + "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", + "dev": true, + "dependencies": { + "inherits": "2", + "minimatch": "0.3" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", + "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", + "deprecated": "Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue", + "dev": true, "dependencies": { - "debug": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", - "dev": true, - "requires": { - "ms": "0.7.1" - } - }, - "escape-string-regexp": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", - "integrity": "sha1-Tbwv5nTnGUnK8/smlc5/LcHZqNE=", - "dev": true - }, - "glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", - "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", - "dev": true, - "requires": { - "inherits": "2", - "minimatch": "0.3" - } - }, - "minimatch": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", - "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", - "dev": true, - "requires": { - "lru-cache": "2", - "sigmund": "~1.0.0" - } - }, - "ms": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", - "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", - "dev": true - }, - "supports-color": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz", - "integrity": "sha1-/x7R5hFp0Gs88tWI4YixjYhH4X4=", - "dev": true - } - } - }, - "ms": { + "lru-cache": "2", + "sigmund": "~1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz", + "integrity": "sha1-/x7R5hFp0Gs88tWI4YixjYhH4X4=", + "dev": true, + "bin": { + "supports-color": "cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, - "nan": { + "node_modules/nan": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==", "dev": true, "optional": true }, - "negotiator": { + "node_modules/negotiator": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.6" + } }, - "nopt": { + "node_modules/nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", "dev": true, - "requires": { + "dependencies": { "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" } }, - "normalize-package-data": { + "node_modules/normalize-package-data": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", "dev": true, - "requires": { + "dependencies": { "hosted-git-info": "^2.1.4", "is-builtin-module": "^1.0.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" } }, - "normalize-path": { + "node_modules/normalize-path": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", "dev": true, - "requires": { + "dependencies": { "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "number-is-nan": { + "node_modules/number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "oauth-sign": { + "node_modules/oauth-sign": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", - "dev": true + "dev": true, + "engines": { + "node": "*" + } }, - "object-assign": { + "node_modules/object-assign": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz", "integrity": "sha1-ejs9DpgGPUP0wD8uiubNUahog6A=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "object-component": { + "node_modules/object-component": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=", "dev": true }, - "object.omit": { + "node_modules/object.omit": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", "dev": true, - "requires": { + "dependencies": { "for-own": "^0.1.4", "is-extendable": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "on-finished": { + "node_modules/on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", "dev": true, - "requires": { + "dependencies": { "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" } }, - "once": { + "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, - "requires": { + "dependencies": { "wrappy": "1" } }, - "optimist": { + "node_modules/optimist": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", "dev": true, - "requires": { + "dependencies": { "minimist": "~0.0.1", "wordwrap": "~0.0.2" - }, - "dependencies": { - "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", - "dev": true - } } }, - "optionator": { + "node_modules/optimist/node_modules/wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/optionator": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", "dev": true, - "requires": { + "dependencies": { "deep-is": "~0.1.3", "fast-levenshtein": "~2.0.4", "levn": "~0.3.0", "prelude-ls": "~1.1.2", "type-check": "~0.3.2", "wordwrap": "~1.0.0" + }, + "engines": { + "node": ">= 0.8.0" } }, - "options": { + "node_modules/options": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.4.0" + } }, - "os-tmpdir": { + "node_modules/os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "parse-glob": { + "node_modules/parse-glob": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", "dev": true, - "requires": { + "dependencies": { "glob-base": "^0.3.0", "is-dotfile": "^1.0.0", "is-extglob": "^1.0.0", "is-glob": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "parse-json": { + "node_modules/parse-json": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "dev": true, - "requires": { + "dependencies": { "error-ex": "^1.2.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "parsejson": { + "node_modules/parsejson": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/parsejson/-/parsejson-0.0.3.tgz", "integrity": "sha1-q343WfIJ7OmUN5c/fQ8fZK4OZKs=", "dev": true, - "requires": { + "dependencies": { "better-assert": "~1.0.0" } }, - "parseqs": { + "node_modules/parseqs": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", "dev": true, - "requires": { + "dependencies": { "better-assert": "~1.0.0" } }, - "parseuri": { + "node_modules/parseuri": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", "dev": true, - "requires": { + "dependencies": { "better-assert": "~1.0.0" } }, - "parseurl": { + "node_modules/parseurl": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.8" + } }, - "path-exists": { + "node_modules/path-exists": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", "dev": true, - "requires": { + "dependencies": { "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "path-is-absolute": { + "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "path-type": { + "node_modules/path-type": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", "dev": true, - "requires": { + "dependencies": { "graceful-fs": "^4.1.2", "pify": "^2.0.0", "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "pend": { + "node_modules/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", "dev": true }, - "performance-now": { + "node_modules/performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "dev": true }, - "phantomjs": { - "version": "1.9.20", - "resolved": "https://registry.npmjs.org/phantomjs/-/phantomjs-1.9.20.tgz", - "integrity": "sha1-RCSsog4U0lXAsIia9va4lz2hDg0=", + "node_modules/phantomjs": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/phantomjs/-/phantomjs-2.1.7.tgz", + "integrity": "sha512-hw9ShqlOOeBD7qXTB7HAPJzqscG15AUymngJFRJt4gex3MVdBykWrGV1Js21CsnZ35A6/x3KFbHxZd3xu6boBA==", + "deprecated": "Package renamed to phantomjs-prebuilt. Please update 'phantomjs' package references to 'phantomjs-prebuilt'", "dev": true, - "requires": { + "hasInstallScript": true, + "dependencies": { "extract-zip": "~1.5.0", "fs-extra": "~0.26.4", "hasha": "^2.2.0", @@ -3506,525 +4382,659 @@ "request-progress": "~2.0.1", "which": "~1.2.2" }, + "bin": { + "phantomjs": "bin/phantomjs" + } + }, + "node_modules/phantomjs/node_modules/assert-plus": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/phantomjs/node_modules/async": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz", + "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==", + "dev": true, + "dependencies": { + "lodash": "^4.14.0" + } + }, + "node_modules/phantomjs/node_modules/aws-sign2": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/phantomjs/node_modules/boom": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "deprecated": "This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).", + "dev": true, + "dependencies": { + "hoek": "2.x.x" + }, + "engines": { + "node": ">=0.10.40" + } + }, + "node_modules/phantomjs/node_modules/caseless": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", + "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=", + "dev": true + }, + "node_modules/phantomjs/node_modules/commander": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz", + "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==", + "dev": true + }, + "node_modules/phantomjs/node_modules/concat-stream": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.0.tgz", + "integrity": "sha1-U/fUPFHF5D+ByP3QMyHGMb5o1hE=", + "dev": true, + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "inherits": "~2.0.1", + "readable-stream": "~2.0.0", + "typedarray": "~0.0.5" + } + }, + "node_modules/phantomjs/node_modules/cryptiles": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "deprecated": "This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).", + "dev": true, + "dependencies": { + "boom": "2.x.x" + }, + "engines": { + "node": ">=0.10.40" + } + }, + "node_modules/phantomjs/node_modules/debug": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz", + "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/phantomjs/node_modules/extract-zip": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.5.0.tgz", + "integrity": "sha1-ksz22B73Cp+kwXRxFMzvbYaIpsQ=", + "dev": true, + "dependencies": { + "concat-stream": "1.5.0", + "debug": "0.7.4", + "mkdirp": "0.5.0", + "yauzl": "2.4.1" + }, + "bin": { + "extract-zip": "cli.js" + } + }, + "node_modules/phantomjs/node_modules/form-data": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.1.tgz", + "integrity": "sha1-rjFduaSQf6BlUCMEpm13M0de43w=", + "dev": true, + "dependencies": { + "async": "^2.0.1", + "combined-stream": "^1.0.5", + "mime-types": "^2.1.11" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/phantomjs/node_modules/fs-extra": { + "version": "0.26.7", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.26.7.tgz", + "integrity": "sha1-muH92UiXeY7at20JGM9C0MMYT6k=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, + "node_modules/phantomjs/node_modules/har-validator": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", + "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", + "deprecated": "this library is no longer supported", + "dev": true, + "dependencies": { + "chalk": "^1.1.1", + "commander": "^2.9.0", + "is-my-json-valid": "^2.12.4", + "pinkie-promise": "^2.0.0" + }, + "bin": { + "har-validator": "bin/har-validator" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/phantomjs/node_modules/hawk": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "deprecated": "This module moved to @hapi/hawk. Please make sure to switch over as this distribution is no longer supported and may contain bugs and critical security issues.", + "dev": true, + "dependencies": { + "boom": "2.x.x", + "cryptiles": "2.x.x", + "hoek": "2.x.x", + "sntp": "1.x.x" + }, + "engines": { + "node": ">=0.10.32" + } + }, + "node_modules/phantomjs/node_modules/hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", + "deprecated": "This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).", + "dev": true, + "engines": { + "node": ">=0.10.40" + } + }, + "node_modules/phantomjs/node_modules/http-signature": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "dev": true, + "dependencies": { + "assert-plus": "^0.2.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/phantomjs/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "node_modules/phantomjs/node_modules/klaw": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.9" + } + }, + "node_modules/phantomjs/node_modules/lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + }, + "node_modules/phantomjs/node_modules/minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "node_modules/phantomjs/node_modules/mkdirp": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz", + "integrity": "sha1-HXMHam35hs2TROFecfzAWkyavxI=", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "dev": true, + "dependencies": { + "minimist": "0.0.8" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/phantomjs/node_modules/node-uuid": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", + "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=", + "deprecated": "Use uuid module instead", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/phantomjs/node_modules/qs": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-5.2.1.tgz", + "integrity": "sha1-gB/uAw4LlFDWOFrcSKTMVbRK7fw=", + "dev": true, + "engines": ">=0.10.40" + }, + "node_modules/phantomjs/node_modules/readable-stream": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/phantomjs/node_modules/request": { + "version": "2.67.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.67.0.tgz", + "integrity": "sha1-ivdHgOK/EeoK6aqWXBHxGv0nJ0I=", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dev": true, + "dependencies": { + "aws-sign2": "~0.6.0", + "bl": "~1.0.0", + "caseless": "~0.11.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.0", + "forever-agent": "~0.6.1", + "form-data": "~1.0.0-rc3", + "har-validator": "~2.0.2", + "hawk": "~3.1.0", + "http-signature": "~1.1.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.7", + "node-uuid": "~1.4.7", + "oauth-sign": "~0.8.0", + "qs": "~5.2.0", + "stringstream": "~0.0.4", + "tough-cookie": "~2.2.0", + "tunnel-agent": "~0.4.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/phantomjs/node_modules/sntp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "deprecated": "This module moved to @hapi/sntp. Please make sure to switch over as this distribution is no longer supported and may contain bugs and critical security issues.", + "dev": true, + "dependencies": { + "hoek": "2.x.x" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/phantomjs/node_modules/tough-cookie": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.2.tgz", + "integrity": "sha1-yDoYMPTl7wuT7yo0iOck+N4Basc=", + "deprecated": "ReDoS vulnerability parsing Set-Cookie https://nodesecurity.io/advisories/130", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/phantomjs/node_modules/tunnel-agent": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", + "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/phantomjs/node_modules/which": { + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", + "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", + "dev": true, "dependencies": { - "assert-plus": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", - "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", - "dev": true - }, - "async": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz", - "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==", - "dev": true, - "requires": { - "lodash": "^4.14.0" - } - }, - "aws-sign2": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", - "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", - "dev": true - }, - "boom": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", - "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", - "dev": true, - "requires": { - "hoek": "2.x.x" - } - }, - "caseless": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", - "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=", - "dev": true - }, - "commander": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz", - "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==", - "dev": true - }, - "concat-stream": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.0.tgz", - "integrity": "sha1-U/fUPFHF5D+ByP3QMyHGMb5o1hE=", - "dev": true, - "requires": { - "inherits": "~2.0.1", - "readable-stream": "~2.0.0", - "typedarray": "~0.0.5" - } - }, - "cryptiles": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", - "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", - "dev": true, - "requires": { - "boom": "2.x.x" - } - }, - "debug": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz", - "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=", - "dev": true - }, - "extract-zip": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.5.0.tgz", - "integrity": "sha1-ksz22B73Cp+kwXRxFMzvbYaIpsQ=", - "dev": true, - "requires": { - "concat-stream": "1.5.0", - "debug": "0.7.4", - "mkdirp": "0.5.0", - "yauzl": "2.4.1" - } - }, - "form-data": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.1.tgz", - "integrity": "sha1-rjFduaSQf6BlUCMEpm13M0de43w=", - "dev": true, - "requires": { - "async": "^2.0.1", - "combined-stream": "^1.0.5", - "mime-types": "^2.1.11" - } - }, - "fs-extra": { - "version": "0.26.7", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.26.7.tgz", - "integrity": "sha1-muH92UiXeY7at20JGM9C0MMYT6k=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "klaw": "^1.0.0", - "path-is-absolute": "^1.0.0", - "rimraf": "^2.2.8" - } - }, - "har-validator": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", - "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", - "dev": true, - "requires": { - "chalk": "^1.1.1", - "commander": "^2.9.0", - "is-my-json-valid": "^2.12.4", - "pinkie-promise": "^2.0.0" - } - }, - "hawk": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", - "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", - "dev": true, - "requires": { - "boom": "2.x.x", - "cryptiles": "2.x.x", - "hoek": "2.x.x", - "sntp": "1.x.x" - } - }, - "hoek": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", - "dev": true - }, - "http-signature": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", - "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", - "dev": true, - "requires": { - "assert-plus": "^0.2.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "klaw": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", - "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.9" - } - }, - "lodash": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", - "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", - "dev": true - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - }, - "mkdirp": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz", - "integrity": "sha1-HXMHam35hs2TROFecfzAWkyavxI=", - "dev": true, - "requires": { - "minimist": "0.0.8" - } - }, - "node-uuid": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", - "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=", - "dev": true - }, - "qs": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-5.2.1.tgz", - "integrity": "sha1-gB/uAw4LlFDWOFrcSKTMVbRK7fw=", - "dev": true - }, - "readable-stream": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", - "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", - "string_decoder": "~0.10.x", - "util-deprecate": "~1.0.1" - } - }, - "request": { - "version": "2.67.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.67.0.tgz", - "integrity": "sha1-ivdHgOK/EeoK6aqWXBHxGv0nJ0I=", - "dev": true, - "requires": { - "aws-sign2": "~0.6.0", - "bl": "~1.0.0", - "caseless": "~0.11.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.0", - "forever-agent": "~0.6.1", - "form-data": "~1.0.0-rc3", - "har-validator": "~2.0.2", - "hawk": "~3.1.0", - "http-signature": "~1.1.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.7", - "node-uuid": "~1.4.7", - "oauth-sign": "~0.8.0", - "qs": "~5.2.0", - "stringstream": "~0.0.4", - "tough-cookie": "~2.2.0", - "tunnel-agent": "~0.4.1" - } - }, - "sntp": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", - "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", - "dev": true, - "requires": { - "hoek": "2.x.x" - } - }, - "tough-cookie": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.2.tgz", - "integrity": "sha1-yDoYMPTl7wuT7yo0iOck+N4Basc=", - "dev": true - }, - "tunnel-agent": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", - "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", - "dev": true - }, - "which": { - "version": "1.2.14", - "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", - "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "pify": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "pinkie": { + "node_modules/pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "pinkie-promise": { + "node_modules/pinkie-promise": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "dev": true, - "requires": { + "dependencies": { "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "prelude-ls": { + "node_modules/prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.8.0" + } }, - "preserve": { + "node_modules/preserve": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "process-nextick-args": { + "node_modules/process-nextick-args": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", "dev": true }, - "progress": { + "node_modules/progress": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.4.0" + } }, - "punycode": { + "node_modules/punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", "dev": true }, - "qjobs": { + "node_modules/qjobs": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.1.5.tgz", "integrity": "sha1-ZZ3p8s+NzCehSBJ28gU3cnI4LnM=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.9" + } }, - "qs": { + "node_modules/qs": { "version": "6.5.1", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.6" + } }, - "randomatic": { + "node_modules/randomatic": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", "dev": true, - "requires": { + "dependencies": { "is-number": "^3.0.0", "kind-of": "^4.0.0" }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/randomatic/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/randomatic/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/randomatic/node_modules/kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, "dependencies": { - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "range-parser": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/range-parser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.6" + } }, - "raw-body": { + "node_modules/raw-body": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", "dev": true, - "requires": { + "dependencies": { "bytes": "3.0.0", "http-errors": "1.6.2", "iconv-lite": "0.4.19", "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" } }, - "read-pkg": { + "node_modules/read-pkg": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", "dev": true, - "requires": { + "dependencies": { "load-json-file": "^1.0.0", "normalize-package-data": "^2.3.2", "path-type": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "read-pkg-up": { + "node_modules/read-pkg-up": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", "dev": true, - "requires": { + "dependencies": { "find-up": "^1.0.0", "read-pkg": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "readable-stream": { + "node_modules/readable-stream": { "version": "1.1.14", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "dev": true, - "requires": { + "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", "isarray": "0.0.1", "string_decoder": "~0.10.x" } }, - "readdirp": { + "node_modules/readdirp": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", "dev": true, - "requires": { + "dependencies": { "graceful-fs": "^4.1.2", "minimatch": "^3.0.2", "readable-stream": "^2.0.2", "set-immediate-shim": "^1.0.1" }, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/readdirp/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "node_modules/readdirp/node_modules/readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.0.3", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readdirp/node_modules/string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "readable-stream": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", - "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.0.3", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "redent": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/redent": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", "dev": true, - "requires": { + "dependencies": { "indent-string": "^2.1.0", "strip-indent": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "regex-cache": { + "node_modules/regex-cache": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", "dev": true, - "requires": { + "dependencies": { "is-equal-shallow": "^0.1.3" + }, + "engines": { + "node": ">=0.10.0" } }, - "remove-trailing-separator": { + "node_modules/remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", "dev": true }, - "repeat-element": { + "node_modules/repeat-element": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "repeat-string": { + "node_modules/repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10" + } }, - "repeating": { + "node_modules/repeating": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", "dev": true, - "requires": { + "dependencies": { "is-finite": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "request": { + "node_modules/request": { "version": "2.83.0", "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", "dev": true, - "requires": { + "dependencies": { "aws-sign2": "~0.7.0", "aws4": "^1.6.0", "caseless": "~0.12.0", @@ -4047,172 +5057,196 @@ "tough-cookie": "~2.3.3", "tunnel-agent": "^0.6.0", "uuid": "^3.1.0" + }, + "engines": { + "node": ">= 4" } }, - "request-progress": { + "node_modules/request-progress": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-2.0.1.tgz", "integrity": "sha1-XTa7V5YcZzqlt4jbyBQf3yO0Tgg=", "dev": true, - "requires": { + "dependencies": { "throttleit": "^1.0.0" } }, - "requires-port": { + "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", "dev": true }, - "requizzle": { + "node_modules/requizzle": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.1.tgz", "integrity": "sha1-aUPDUwxNmn5G8c3dUcFY/GcM294=", "dev": true, - "requires": { - "underscore": "~1.6.0" - }, "dependencies": { - "underscore": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", - "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=", - "dev": true - } + "underscore": "~1.6.0" } }, - "resolve": { + "node_modules/requizzle/node_modules/underscore": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=", + "dev": true + }, + "node_modules/resolve": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", "dev": true }, - "right-align": { + "node_modules/right-align": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", "dev": true, - "requires": { + "dependencies": { "align-text": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "rimraf": { + "node_modules/rimraf": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, - "requires": { + "dependencies": { "glob": "^7.0.5" }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, "dependencies": { - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" } }, - "safe-buffer": { + "node_modules/safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", "dev": true }, - "semver": { + "node_modules/semver": { "version": "4.3.6", "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=", - "dev": true + "dev": true, + "bin": { + "semver": "bin/semver" + } }, - "set-immediate-shim": { + "node_modules/set-immediate-shim": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "setprototypeof": { + "node_modules/setprototypeof": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=", "dev": true }, - "shelljs": { + "node_modules/shelljs": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", - "dev": true + "dev": true, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=0.8.0" + } }, - "should": { + "node_modules/should": { "version": "4.6.5", "resolved": "https://registry.npmjs.org/should/-/should-4.6.5.tgz", "integrity": "sha1-DRI0bbvRsCj59Lt6nVRzZPw2qH8=", "dev": true, - "requires": { + "dependencies": { "should-equal": "0.3.1", "should-format": "0.0.7", "should-type": "0.0.4" } }, - "should-equal": { + "node_modules/should-equal": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-0.3.1.tgz", "integrity": "sha1-vY6pemdI45+tR2o75v1y68LnK/A=", "dev": true, - "requires": { + "dependencies": { "should-type": "0.0.4" } }, - "should-format": { + "node_modules/should-format": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/should-format/-/should-format-0.0.7.tgz", "integrity": "sha1-Hi74a9kdqcLgQSM1tWq6vZov3hI=", "dev": true, - "requires": { + "dependencies": { "should-type": "0.0.4" } }, - "should-type": { + "node_modules/should-type": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/should-type/-/should-type-0.0.4.tgz", "integrity": "sha1-ATKgVBemEmhmQmrPEW8e1WI6XNA=", "dev": true }, - "sigmund": { + "node_modules/sigmund": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", "dev": true }, - "signal-exit": { + "node_modules/signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, - "sntp": { + "node_modules/sntp": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", + "deprecated": "This module moved to @hapi/sntp. Please make sure to switch over as this distribution is no longer supported and may contain bugs and critical security issues.", "dev": true, - "requires": { + "dependencies": { "hoek": "4.x.x" + }, + "engines": { + "node": ">=4.0.0" } }, - "socket.io": { + "node_modules/socket.io": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-1.7.3.tgz", "integrity": "sha1-uK+cq6AJSeVo42nxMn6pvp6iRhs=", "dev": true, - "requires": { + "dependencies": { "debug": "2.3.3", "engine.io": "1.8.3", "has-binary": "0.1.7", @@ -4220,58 +5254,39 @@ "socket.io-adapter": "0.5.0", "socket.io-client": "1.7.3", "socket.io-parser": "2.3.1" - }, - "dependencies": { - "debug": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", - "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", - "dev": true, - "requires": { - "ms": "0.7.2" - } - }, - "ms": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", - "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", - "dev": true - } - } - }, - "socket.io-adapter": { + } + }, + "node_modules/socket.io-adapter": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz", "integrity": "sha1-y21LuL7IHhB4uZZ3+c7QBGBmu4s=", "dev": true, - "requires": { + "dependencies": { "debug": "2.3.3", "socket.io-parser": "2.3.1" - }, + } + }, + "node_modules/socket.io-adapter/node_modules/debug": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", + "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", + "dev": true, "dependencies": { - "debug": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", - "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", - "dev": true, - "requires": { - "ms": "0.7.2" - } - }, - "ms": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", - "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", - "dev": true - } - } - }, - "socket.io-client": { + "ms": "0.7.2" + } + }, + "node_modules/socket.io-adapter/node_modules/ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", + "dev": true + }, + "node_modules/socket.io-client": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.7.3.tgz", "integrity": "sha1-sw6GqhDV7zVGYBwJzeR2Xjgdo3c=", "dev": true, - "requires": { + "dependencies": { "backo2": "1.0.2", "component-bind": "1.0.0", "component-emitter": "1.2.1", @@ -4283,461 +5298,573 @@ "parseuri": "0.0.5", "socket.io-parser": "2.3.1", "to-array": "0.1.4" - }, + } + }, + "node_modules/socket.io-client/node_modules/component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "node_modules/socket.io-client/node_modules/debug": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", + "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", + "dev": true, "dependencies": { - "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", - "dev": true - }, - "debug": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", - "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", - "dev": true, - "requires": { - "ms": "0.7.2" - } - }, - "ms": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", - "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", - "dev": true - } - } - }, - "socket.io-parser": { + "ms": "0.7.2" + } + }, + "node_modules/socket.io-client/node_modules/ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", + "dev": true + }, + "node_modules/socket.io-parser": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.3.1.tgz", "integrity": "sha1-3VMgJRA85Clpcya+/WQAX8/ltKA=", "dev": true, - "requires": { + "dependencies": { "component-emitter": "1.1.2", "debug": "2.2.0", "isarray": "0.0.1", "json3": "3.3.2" - }, + } + }, + "node_modules/socket.io-parser/node_modules/debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true, + "dependencies": { + "ms": "0.7.1" + } + }, + "node_modules/socket.io-parser/node_modules/ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true + }, + "node_modules/socket.io/node_modules/debug": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", + "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", + "dev": true, "dependencies": { - "debug": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", - "dev": true, - "requires": { - "ms": "0.7.1" - } - }, - "ms": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", - "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", - "dev": true - } - } - }, - "source-map": { + "ms": "0.7.2" + } + }, + "node_modules/socket.io/node_modules/ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", + "dev": true + }, + "node_modules/source-map": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", "dev": true, "optional": true, - "requires": { + "dependencies": { "amdefine": ">=0.0.4" + }, + "engines": { + "node": ">=0.8.0" } }, - "spdx-correct": { + "node_modules/spdx-correct": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", "dev": true, - "requires": { + "dependencies": { "spdx-license-ids": "^1.0.2" } }, - "spdx-expression-parse": { + "node_modules/spdx-expression-parse": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=", "dev": true }, - "spdx-license-ids": { + "node_modules/spdx-license-ids": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=", "dev": true }, - "sprintf-js": { + "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, - "sshpk": { + "node_modules/sshpk": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", "dev": true, - "requires": { + "dependencies": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", "dashdash": "^1.12.0", + "getpass": "^0.1.1" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + }, + "optionalDependencies": { + "bcrypt-pbkdf": "^1.0.0", "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", "jsbn": "~0.1.0", "tweetnacl": "~0.14.0" } }, - "statuses": { + "node_modules/statuses": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.6" + } }, - "string_decoder": { + "node_modules/string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", "dev": true }, - "stringstream": { + "node_modules/stringstream": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", "dev": true }, - "strip-ansi": { + "node_modules/strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, - "requires": { + "dependencies": { "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "strip-bom": { + "node_modules/strip-bom": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", "dev": true, - "requires": { + "dependencies": { "is-utf8": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "strip-indent": { + "node_modules/strip-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", "dev": true, - "requires": { + "dependencies": { "get-stdin": "^4.0.1" + }, + "bin": { + "strip-indent": "cli.js" + }, + "engines": { + "node": ">=0.10.0" } }, - "strip-json-comments": { + "node_modules/strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "supports-color": { + "node_modules/supports-color": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", "dev": true, - "requires": { + "dependencies": { "has-flag": "^1.0.0" + }, + "engines": { + "node": ">=0.8.0" } }, - "taffydb": { + "node_modules/taffydb": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz", "integrity": "sha1-fLy2S1oUG2ou/CxdLGe04VCyomg=", "dev": true }, - "throttleit": { + "node_modules/throttleit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=", "dev": true }, - "tmp": { + "node_modules/tmp": { "version": "0.0.31", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.31.tgz", "integrity": "sha1-jzirlDjhcxXl29izZX6L+yd65Kc=", "dev": true, - "requires": { + "dependencies": { "os-tmpdir": "~1.0.1" + }, + "engines": { + "node": ">=0.4.0" } }, - "to-array": { + "node_modules/to-array": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=", "dev": true }, - "to-iso-string": { + "node_modules/to-iso-string": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/to-iso-string/-/to-iso-string-0.0.2.tgz", "integrity": "sha1-TcGeZk38y+Jb2NtQiwDG2hWCVdE=", + "deprecated": "to-iso-string has been deprecated, use @segment/to-iso-string instead.", "dev": true }, - "tough-cookie": { + "node_modules/tough-cookie": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", "dev": true, - "requires": { + "dependencies": { "punycode": "^1.4.1" + }, + "engines": { + "node": ">=0.8" } }, - "trim-newlines": { + "node_modules/trim-newlines": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "tunnel-agent": { + "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "dev": true, - "requires": { + "dependencies": { "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" } }, - "tweetnacl": { + "node_modules/tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", "dev": true, "optional": true }, - "type-check": { + "node_modules/type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", "dev": true, - "requires": { + "dependencies": { "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" } }, - "type-is": { + "node_modules/type-is": { "version": "1.6.15", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=", "dev": true, - "requires": { + "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.15" + }, + "engines": { + "node": ">= 0.6" } }, - "typedarray": { + "node_modules/typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, - "uglify-js": { + "node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uglify-js": { "version": "2.8.29", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", "dev": true, - "requires": { + "dependencies": { "source-map": "~0.5.1", - "uglify-to-browserify": "~1.0.0", "yargs": "~3.10.0" }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + }, + "optionalDependencies": { + "uglify-to-browserify": "~1.0.0" + } + }, + "node_modules/uglify-js/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, - "uglify-to-browserify": { + "node_modules/uglify-to-browserify": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", "dev": true, "optional": true }, - "ultron": { + "node_modules/ultron": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=", "dev": true }, - "underscore": { + "node_modules/underscore": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=", "dev": true }, - "underscore-contrib": { + "node_modules/underscore-contrib": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/underscore-contrib/-/underscore-contrib-0.3.0.tgz", "integrity": "sha1-ZltmwkeD+PorGMn4y7Dix9SMJsc=", "dev": true, - "requires": { - "underscore": "1.6.0" - }, "dependencies": { - "underscore": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", - "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=", - "dev": true - } + "underscore": "1.6.0" } }, - "unpipe": { + "node_modules/underscore-contrib/node_modules/underscore": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=", + "dev": true + }, + "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.8" + } }, - "useragent": { + "node_modules/useragent": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.2.1.tgz", "integrity": "sha1-z1k+9PLRdYdei7ZY6pLhik/QbY4=", "dev": true, - "requires": { + "dependencies": { "lru-cache": "2.2.x", "tmp": "0.0.x" } }, - "util-deprecate": { + "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, - "utils-merge": { + "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.4.0" + } }, - "uuid": { + "node_modules/uuid": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==", - "dev": true + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } }, - "validate-npm-package-license": { + "node_modules/validate-npm-package-license": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", "dev": true, - "requires": { + "dependencies": { "spdx-correct": "~1.0.0", "spdx-expression-parse": "~1.0.0" } }, - "verror": { + "node_modules/verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "dev": true, - "requires": { + "engines": [ + "node >=0.6.0" + ], + "dependencies": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" } }, - "void-elements": { + "node_modules/void-elements": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "which": { + "node_modules/which": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", "dev": true, - "requires": { + "dependencies": { "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" } }, - "window-size": { + "node_modules/window-size": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.8.0" + } }, - "wordwrap": { + "node_modules/wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", "dev": true }, - "wrappy": { + "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, - "ws": { + "node_modules/ws": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.2.tgz", "integrity": "sha1-iiRPoFJAHgjJiGz0SoUYnh/UBn8=", "dev": true, - "requires": { + "dependencies": { "options": ">=0.0.5", "ultron": "1.0.x" } }, - "wtf-8": { + "node_modules/wtf-8": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wtf-8/-/wtf-8-1.0.0.tgz", "integrity": "sha1-OS2LotDxw00e4tYw8V0O+2jhBIo=", "dev": true }, - "xmlcreate": { + "node_modules/xmlcreate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-1.0.2.tgz", "integrity": "sha1-+mv3YqYKQT+z3Y9LA8WyaSONMI8=", "dev": true }, - "xmlhttprequest-ssl": { + "node_modules/xmlhttprequest-ssl": { "version": "1.5.3", "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz", "integrity": "sha1-GFqIjATspGw+QHDZn3tJ3jUomS0=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.4.0" + } }, - "xtend": { + "node_modules/xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", - "dev": true + "dev": true, + "engines": { + "node": ">=0.4" + } }, - "yargs": { + "node_modules/yargs": { "version": "3.10.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", "dev": true, - "requires": { + "dependencies": { "camelcase": "^1.0.2", "cliui": "^2.1.0", "decamelize": "^1.0.0", "window-size": "0.1.0" } }, - "yauzl": { + "node_modules/yauzl": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz", "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=", "dev": true, - "requires": { + "dependencies": { "fd-slicer": "~1.0.1" } }, - "yeast": { + "node_modules/yeast": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", diff --git a/package.json b/package.json index 10a27f18..de24339e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { - "name": "lokijs", - "version": "1.5.12", + "name": "pantiko-lokijs", + "version": "1.5.12-pantiko-0.2", "description": "Fast document oriented javascript in-memory database", "homepage": "https://techfort.github.io/LokiJS/", "main": "src/lokijs.js", @@ -27,8 +27,9 @@ "test:node": "istanbul cover --dir coverage/nodejs node_modules/jasmine/bin/jasmine.js", "pretest": "npm run lint", "test": "npm run test:browser && npm run test:node", + "compile": "npx tsc --project tsconfig.json", "build:lokijs": "uglifyjs src/lokijs.js > build/lokijs.min.js", - "build:indexedAdapter": "uglifyjs src/loki-indexed-adapter.js > build/loki-indexed-adapter.min.js", + "build:indexedAdapter": "npm run compile && uglifyjs src/loki-indexed-adapter.js > build/loki-indexed-adapter.min.js", "build": "npm run build:lokijs && npm run build:indexedAdapter", "postbuild": "karma start karma.build.conf.js --single-run", "prepublish": "npm run build", @@ -48,21 +49,22 @@ "bugs": { "url": "https://github.com/techfort/LokiJS/issues" }, - "dependencies": {}, "devDependencies": { "istanbul": "^0.4.4", "jasmine": "^2.4.1", "jsdoc": "^3.5.5", "jshint": "^2.9.2", "karma": "^1.1.2", + "karma-chrome-launcher": "^3.2.0", "karma-cli": "^1.0.1", "karma-coverage": "^1.1.1", "karma-jasmine": "^1.0.2", "karma-phantomjs-launcher": "^1.0.1", "mocha": "^2.5.3", - "phantomjs": "^1.9.20", + "phantomjs": "^2.1.1", "rimraf": "^2.5.4", "should": "^4.6.5", + "typescript": "^5.3.3", "uglify-js": "^2.7.0" } } diff --git a/spec/browser/incrementalIdb-encodeChunkString.spec.js b/spec/browser/incrementalIdb-encodeChunkString.spec.js new file mode 100644 index 00000000..14d72a92 --- /dev/null +++ b/spec/browser/incrementalIdb-encodeChunkString.spec.js @@ -0,0 +1,239 @@ +// noinspection JSVoidFunctionReturnValueUsed + +function deleteDb(dbName) { + return new Promise(function(resolve, reject) { + const deleteDbRequest = indexedDB.deleteDatabase(dbName); + deleteDbRequest.addEventListener('error', function (e) { + console.log('delete error', e); + reject(e); + }); + deleteDbRequest.addEventListener('blocked', function (e) { + console.log('delete blocked', e); + reject(e); + }); + deleteDbRequest.addEventListener('upgradeneeded', function (e) { + console.log('delete upgradeneeded', e); + reject(e); + }); + deleteDbRequest.addEventListener('success', function (e) { + // console.log('delete success', e); + resolve(e); + }); + }) +} + + +function getAllLokiObjects(dbName) { + return new Promise(function(resolve, reject) { + const openReq = indexedDB.open(dbName) + openReq.onerror = function(event) { + reject({type: 'onerror', event: event}); + } + openReq.onupgradeneeded = function(event) { + reject({type: 'onupgradeneeded', event: event}); + } + openReq.onsuccess = function() { + const db = openReq.result; + const storeName = db.objectStoreNames[0]; + const queryReq = db.transaction(storeName).objectStore(storeName).getAll(); + queryReq.onsuccess = function(event){ + resolve(event.target.result) + }; + queryReq.onerror = function(event){ + reject({type: 'getAll.onerror', event: event}) + }; + } + }); +} + +const expectedModifiedAllObjects = function(dbName, loki, chunk, metadata) { + if (loki === undefined) loki = "loki" + if (chunk === undefined) chunk = "chunk" + if (metadata === undefined) metadata = "metadata" + return sortByKey([ + {key:"another." + chunk + ".0", value:"[{\"a\":1,\"b\":2,\"meta\":{\"revision\":0,\"created\":9999999999999,\"version\":0},\"$loki\":1}]"}, + {key:"another." + metadata + "", value:"{\"name\":\"another\",\"data\":[],\"idIndex\":[],\"binaryIndices\":{},\"constraints\":null,\"uniqueNames\":[],\"transforms\":{},\"objType\":\"another\",\"dirty\":true,\"cachedIndex\":null,\"cachedBinaryIndex\":null,\"cachedData\":null,\"adaptiveBinaryIndices\":true,\"transactional\":false,\"cloneObjects\":false,\"cloneMethod\":\"parse-stringify\",\"asyncListeners\":false,\"disableMeta\":false,\"disableChangesApi\":true,\"disableDeltaChangesApi\":true,\"autoupdate\":false,\"serializableIndices\":true,\"disableFreeze\":true,\"ttl\":null,\"maxId\":1,\"DynamicViews\":[],\"events\":{\"insert\":[],\"update\":[],\"pre-insert\":[],\"pre-update\":[],\"close\":[],\"flushbuffer\":[],\"error\":[],\"delete\":[null],\"warning\":[null]},\"changes\":[],\"dirtyIds\":[],\"idbVersionId\":\"aaaaaaaaaa\"}"}, + {key:loki + "", value:"{\"filename\":\""+ dbName + "\",\"collections\":[{\"name\":\"testcoll\"},{\"name\":\"another\"}],\"databaseVersion\":1.5,\"engineVersion\":1.5,\"autosave\":false,\"autosaveInterval\":5000,\"autosaveHandle\":null,\"throttledSaves\":true,\"options\":{\"env\":\"NA\",\"serializationMethod\":\"normal\",\"destructureDelimiter\":\"$<\\n\"},\"persistenceAdapter\":null,\"throttledSavePending\":false,\"throttledCallbacks\":[],\"verbose\":false,\"events\":{\"init\":[null],\"loaded\":[],\"flushChanges\":[],\"close\":[],\"changes\":[],\"warning\":[]},\"ENV\":\"NA\",\"idbVersionId\":\"aaaaaaaaaa\"}"}, + {key:"testcoll." + chunk + ".0", value:"[{\"name\":\"test1\",\"val\":100,\"meta\":{\"revision\":0,\"created\":9999999999999,\"version\":0},\"$loki\":1},{\"name\":\"test2\",\"val\":101,\"meta\":{\"revision\":0,\"created\":9999999999999,\"version\":0},\"$loki\":2},{\"name\":\"test3\",\"val\":102,\"meta\":{\"revision\":0,\"created\":9999999999999,\"version\":0},\"$loki\":3}]"}, + {key:"testcoll." + metadata + "", value:"{\"name\":\"testcoll\",\"data\":[],\"idIndex\":[],\"binaryIndices\":{},\"constraints\":null,\"uniqueNames\":[],\"transforms\":{},\"objType\":\"testcoll\",\"dirty\":true,\"cachedIndex\":null,\"cachedBinaryIndex\":null,\"cachedData\":null,\"adaptiveBinaryIndices\":true,\"transactional\":false,\"cloneObjects\":false,\"cloneMethod\":\"parse-stringify\",\"asyncListeners\":false,\"disableMeta\":false,\"disableChangesApi\":true,\"disableDeltaChangesApi\":true,\"autoupdate\":false,\"serializableIndices\":true,\"disableFreeze\":true,\"ttl\":null,\"maxId\":3,\"DynamicViews\":[],\"events\":{\"insert\":[],\"update\":[],\"pre-insert\":[],\"pre-update\":[],\"close\":[],\"flushbuffer\":[],\"error\":[],\"delete\":[null],\"warning\":[null]},\"changes\":[],\"dirtyIds\":[],\"idbVersionId\":\"aaaaaaaaaa\"}"} + ]) +}; + +function sortByKey(arr) { + const newArr = arr.slice(); + return newArr.sort(function(a, b) { + if ( a.key < b.key ){ + return -1; + } + if ( a.key > b.key ){ + return 1; + } + return 0; + }) +} + +function repeatString(str, count) { + var repeatedString = ''; + for (var i = 0; i < count; i++) { + repeatedString += str; + } + return repeatedString; +} + +const cipherkey = repeatString("x", 20); +function base64Encode(s) { + if (typeof CryptoJS !== "undefined") { + return CryptoJS.Rabbit.encrypt(s, cipherkey).toString(); + } + // noinspection JSDeprecatedSymbols + return btoa(s); +} +function base64Decode(s) { + if (typeof CryptoJS !== "undefined") { + return CryptoJS.Rabbit.decrypt(s, cipherkey).toString(CryptoJS.enc.Utf8); + } + try { + // noinspection JSDeprecatedSymbols + return atob(s); + } catch (e) { + console.error('Error while base64 decoding the string', s); + throw e; + } +} + +function replaceMutableValues(allLokiObjects) { + return sortByKey(allLokiObjects.map(function(o) { + const obj = {} + for(var key in o) { + if (o.hasOwnProperty(key)) { + obj[key] = o[key]; + } + } + obj.value = o.value + .replace(/"created":\d+/g, "\"created\":9999999999999") + .replace(/"idbVersionId":"[a-z\d]+"/g, "\"idbVersionId\":\"aaaaaaaaaa\"") + return (obj) + })); +} + +function verifyLokiDatabaseIsCreatedSavedAndLoadedSuccessfully(dbName, adapter, done, additionalAssertions) { + const ddb = new loki(dbName, {adapter: adapter}); + + const coll = ddb.addCollection("testcoll"); + coll.insert({name: "test1", val: 100}); + coll.insert({name: "test2", val: 101}); + coll.insert({name: "test3", val: 102}); + + const coll2 = ddb.addCollection("another"); + coll2.insert({a: 1, b: 2}); + + ddb.saveDatabase(function (e) { + expect(e).toBeUndefined(); + + const cdb = new loki(dbName, {adapter: adapter}); + const loadFunction = function() { + new Promise(function(resolve, reject) { + expect(cdb.collections.length).toEqual(2); + expect(cdb.getCollection("testcoll").findOne({name: "test2"}).val).toEqual(101); + expect(cdb.collections[0].data.length).toEqual(3); + expect(cdb.collections[1].data.length).toEqual(1); + + additionalAssertions().then(function() { + done(); + resolve(); + }); + }) + } + cdb.loadDatabase({}, loadFunction); + }); +} + +function createDeferredPromise(promiseReturningFunction) { + // The promise is not created until this function is called + var promise = promiseReturningFunction(); + + promise.then(function(result) { + // Handle the resolved value + console.log("Resolved:", result); + }).catch(function(error) { + // Handle the error + console.error("Rejected:", error); + }); +} + +describe('IncrementalIndexedDBAdapter encode/decode chunk string functions', function () { + + afterEach(function() { + console.log('--------------------') + }) + + it('verify basic IncrementalIndexedDBAdapter adapter functionality works', function(done) { + window.__loki_incremental_idb_debug = true; + const dbName = "test.db-basic"; + deleteDb(dbName).then(function() { + const adapter = new IncrementalIndexedDBAdapter({}); + + const additionalAssertions = function() { + return new Promise(function(resolve, reject) { + getAllLokiObjects(dbName).then(function(allLokiObjects) { + expect(replaceMutableValues(allLokiObjects)).toEqual(expectedModifiedAllObjects(dbName)); + resolve(); + }); + }) + }; + + verifyLokiDatabaseIsCreatedSavedAndLoadedSuccessfully(dbName, adapter, done, additionalAssertions); + }).catch(function (e) { console.log('Error while deleting', dbName, e)}) + }); + + it('encrypt and decrypt work - identity functions', function(done) { + const dbName = "test.db.empty.encrypt.and.decrypt"; + deleteDb(dbName).then(function() { + const adapter = new IncrementalIndexedDBAdapter({ + encrypt: async function (x) { return x; }, + decrypt: async function (x) { return x; }, + }); + + const additionalAssertions = function() { + return new Promise(function(resolve, reject) { + getAllLokiObjects(dbName).then(function(allLokiObjects) { + expect(replaceMutableValues(allLokiObjects)).toEqual(expectedModifiedAllObjects(dbName, "lk_____________", "ck", "md___")); + resolve(); + }); + }) + } + + verifyLokiDatabaseIsCreatedSavedAndLoadedSuccessfully(dbName, adapter, done, additionalAssertions); + }).catch(function (e) { console.log('Error while deleting', dbName, e)}) + }); + + it('encrypt, decrypt and salt work', function(done) { + const dbName = "test.db.encode.decode"; + deleteDb(dbName).then(function() { + const adapter = new IncrementalIndexedDBAdapter({ + encrypt: async function(x) { return base64Encode(x); }, + decrypt: async function(x) { return base64Decode(x); }, + }); + + const additionalAssertions = function() { + return new Promise(function(resolve, reject) { + getAllLokiObjects(dbName).then(function(allLokiObjects) { + const allLokiObjectsDecoded = allLokiObjects.map(function(o){ + return ({ key: o.key.split(".").map(function(x) { + if (isNaN(x)) + return base64Decode(x); + else + return x + }).join("."), value: base64Decode(o.value) }) + }); + expect(replaceMutableValues(allLokiObjectsDecoded)).toEqual(expectedModifiedAllObjects(dbName, "lk_____________", "ck", "md___")); + resolve(); + }); + }) + } + + verifyLokiDatabaseIsCreatedSavedAndLoadedSuccessfully(dbName, adapter, done, additionalAssertions); + }).catch(function (e) { console.log('Error while deleting', dbName, e)}) + }); + +}) \ No newline at end of file diff --git a/spec/incrementalidb.html b/spec/incrementalidb.html index fa446422..b95da4e8 100644 --- a/spec/incrementalidb.html +++ b/spec/incrementalidb.html @@ -7,6 +7,7 @@ +

IncrementalIDB tests and benchmark

@@ -55,14 +56,14 @@

IncrementalIDB tests and benchmark

}) } -function saveAndCheckDatabaseCopyIntegrity(source) { +function saveAndCheckDatabaseCopyIntegrity(source, adapterOptions=undefined) { return new Promise(resolve => { const beforeSave = new Date() source.saveDatabase((saveError) => { const saveTime = new Date() - beforeSave expectToBe(saveError, undefined) - let copy = new loki('incremental_idb_tester', { adapter: new IncrementalIndexedDBAdapter(), verbose: true }); + let copy = new loki(source.filename, { adapter: new IncrementalIndexedDBAdapter(adapterOptions), verbose: true }); const beforeLoad = new Date() copy.loadDatabase({}, (loadError) => { const loadTime = new Date() - beforeLoad @@ -77,6 +78,7 @@

IncrementalIDB tests and benchmark

function loadLoki(loki) { return new Promise((resolve, reject) => { loki.loadDatabase({}, error => { + console.error('loki.loadDatabase({}, error => {') error ? reject(error) : resolve() }) }) @@ -94,6 +96,7 @@

IncrementalIDB tests and benchmark

domElement = divElement; indexedDB.deleteDatabase("incremental_idb_tester") + indexedDB.deleteDatabase("encryption_tester") let idbOverwriteCount = 0; let adapter = new IncrementalIndexedDBAdapter({ onDidOverwrite: () => { idbOverwriteCount += 1 } }) @@ -326,6 +329,90 @@

IncrementalIDB tests and benchmark

trace('all fuzz tests done') } + trace('==> encryption tests') + + { + const encoder = new TextEncoder(); + const decoder = new TextDecoder(); + + const iv = crypto.getRandomValues(new Uint8Array(12)); + + const key = await crypto.subtle.generateKey( + { name: "AES-GCM", length: 256 }, + true, + ["encrypt", "decrypt"] + ); + + encryptionOptions = { + encryptionMode: "web-crypto/aes", + encrypt: async function(s) { + // if changing algorithm keep at least something async here! + const data = encoder.encode(s); + const encrypted = await crypto.subtle.encrypt( + { name: "AES-GCM", iv: iv }, + key, + data + ); + + return encrypted; + }, + decrypt: async function(s) { + // if changing algorithm keep at least something async here! + const decrypted = await crypto.subtle.decrypt( + { name: "AES-GCM", iv: iv }, + key, + s + ); + console.log(decrypted) + return decoder.decode(decrypted); + } + } + + const adapterWithEncryption = new IncrementalIndexedDBAdapter({ ...encryptionOptions }) + const dbWithEncryption = new loki('encryption_tester', { adapter: adapterWithEncryption }); + + let enCol1 = dbWithEncryption.addCollection('test_collection', { + indices: ['blah'], + }) + let enCol2 = dbWithEncryption.addCollection('test_collection2', { + indices: ['blah'], + }) + + db.collections.forEach(col => { + console.time('massAdd') + const numberOfRecords = 32000 + for (let i = 0; i < numberOfRecords; i++) { + col.insert({ mass: true, i, blah: 'accumsan congue. Lorem ipsum primis in nibh vel risus. Sed vel lectus. Ut sagittis, ipsum dolor quam. nibh vel risus. Sed vel lectus. Ut sagittis, ipsum dolor quam. Ut sagittis, ipsum dolor quam. nibh vel risus. Sed vel lectus. Ut sagittis, ipsum dolor quam' }) + } + console.timeEnd('massAdd') + + // remove many contiguous records to have empty chunks + const dataToDelete = col.data.slice(200, 95) + col.remove(dataToDelete) + + // fuzz changes + const numberOfDeletions = 2500 + for (let i = 0;i { + + const encoder = new TextEncoder("utf-8"); + const decoder = new TextDecoder("utf-8"); + + // + // Configure the encryption algorithm to use + // + const iv = window.crypto.getRandomValues(new Uint8Array(12)); + const algorithm = { + iv, + name: 'AES-GCM', + }; + + // + // Generate/fetch the cryptographic key + // + function getKeyMaterial() { + let input = 'the-username' + new Date(); + let enc = new TextEncoder(); + return window.crypto.subtle.importKey( + "raw", + enc.encode(input), { + name: "PBKDF2" + }, + false, ["deriveBits", "deriveKey"] + ); + } + + let keyMaterial = await getKeyMaterial(); + let salt = window.crypto.getRandomValues(new Uint8Array(16)); + + let key = await window.crypto.subtle.deriveKey({ + "name": "PBKDF2", + salt: salt, + "iterations": 100000, + "hash": "SHA-256" + }, + keyMaterial, { + "name": "AES-GCM", + "length": 256 + }, + true, ["encrypt", "decrypt"] + ); + + + + // + // Export Key + // + const exportedKey = await window.crypto.subtle.exportKey( + 'raw', + key, + ); + + // This is where to save the exported key to the back-end server, + // and then to fetch the exported key from the back-end server. + + // + // Import Key + // + const importedKey = await window.crypto.subtle.importKey( + 'raw', + exportedKey, + "AES-GCM", + true, [ + "encrypt", + "decrypt" + ] + ); + + function ab2str(buf) { + return String.fromCharCode.apply(null, new Uint8Array(buf)); + } + + function str2ab(str) { + const buf = new ArrayBuffer(str.length); // 2 bytes for each char + const bufView = new Uint8Array(buf); + let i = 0; + const strLen = str.length; + for (; i { + try { + console.log('gonna cypher bob'); + const ciphertext = await r.encrypt('bob'); + console.log(ciphertext); + console.log(await r.decrypt(ciphertext)); + } catch (e) { console.log('err', e) } +}).catch(e => console.log('err', e)); \ No newline at end of file diff --git a/src/incremental-indexeddb-adapter.js b/src/incremental-indexeddb-adapter.js index 19d06e12..791cde6a 100644 --- a/src/incremental-indexeddb-adapter.js +++ b/src/incremental-indexeddb-adapter.js @@ -1,820 +1,1182 @@ -(function(root, factory) { - if (typeof define === "function" && define.amd) { - // AMD - define([], factory); - } else if (typeof exports === "object") { - // CommonJS - module.exports = factory(); - } else { - // Browser globals - root.IncrementalIndexedDBAdapter = factory(); - } -})(this, function() { - return (function() { - "use strict"; - - /* jshint -W030 */ - var DEBUG = typeof window !== 'undefined' && !!window.__loki_incremental_idb_debug; - - /** - * An improved Loki persistence adapter for IndexedDB (not compatible with LokiIndexedAdapter) - * Unlike LokiIndexedAdapter, the database is saved not as one big JSON blob, but split into - * small chunks with individual collection documents. When saving, only the chunks with changed - * documents (and database metadata) is saved to IndexedDB. This speeds up small incremental - * saves by an order of magnitude on large (tens of thousands of records) databases. It also - * avoids Safari 13 bug that would cause the database to balloon in size to gigabytes - * - * The `appname` argument is not provided - to distinguish between multiple app on the same - * domain, simply use a different Loki database name - * - * @example - * var adapter = new IncrementalIndexedDBAdapter(); - * - * @constructor IncrementalIndexedDBAdapter - * - * @param {object=} options Configuration options for the adapter - * @param {function} options.onversionchange Function to call on `IDBDatabase.onversionchange` event - * (most likely database deleted from another browser tab) - * @param {function} options.onFetchStart Function to call once IDB load has begun. - * Use this as an opportunity to execute code concurrently while IDB does work on a separate thread - * @param {function} options.onDidOverwrite Called when this adapter is forced to overwrite contents - * of IndexedDB. This happens if there's another open tab of the same app that's making changes. - * You might use it as an opportunity to alert user to the potential loss of data - * @param {function} options.serializeChunk Called with a chunk (array of Loki documents) before - * it's saved to IndexedDB. You can use it to manually compress on-disk representation - * for faster database loads. Hint: Hand-written conversion of objects to arrays is very - * profitable for performance. If you use this, you must also pass options.deserializeChunk. - * @param {function} options.deserializeChunk Called with a chunk serialized with options.serializeChunk - * Expects an array of Loki documents as the return value - * @param {number} options.megachunkCount Number of parallel requests for data when loading database. - * Can be tuned for a specific application - */ - function IncrementalIndexedDBAdapter(options) { - this.mode = "incremental"; - this.options = options || {}; - this.chunkSize = 100; - this.megachunkCount = this.options.megachunkCount || 20; - this.idb = null; // will be lazily loaded on first operation that needs it - this._prevLokiVersionId = null; - this._prevCollectionVersionIds = {}; - - if (!(this.megachunkCount >= 4 && this.megachunkCount % 2 === 0)) { - throw new Error('megachunkCount must be >=4 and divisible by 2'); - } +// note: initial authors don't like Typescript but just don't tell them, shhh. Thing is that it +// seems like there is very little or close to no activity on upstream repositories which is why +// I don't really expect this to be merged and is one of the reason for deciding for it. This is +// far from being pretty or good but I wanted to make minimum change as much as possible. As a +// consequence this might not be the smallest script or optimized so keep that in mind if using. +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +(function (root, factory) { + if (typeof define === "function" && define.amd) { + // AMD + define([], factory); } - - // chunkId - index of the data chunk - e.g. chunk 0 will be lokiIds 0-99 - IncrementalIndexedDBAdapter.prototype._getChunk = function(collection, chunkId) { - // 0-99, 100-199, etc. - var minId = chunkId * this.chunkSize; - var maxId = minId + this.chunkSize - 1; - - // use idIndex to find first collection.data position within the $loki range - collection.ensureId(); - var idIndex = collection.idIndex; - - var firstDataPosition = null; - - var max = idIndex.length - 1, - min = 0, - mid; - - while (idIndex[min] < idIndex[max]) { - mid = (min + max) >> 1; - - if (idIndex[mid] < minId) { - min = mid + 1; - } else { - max = mid; - } - } - - if (max === min && idIndex[min] >= minId && idIndex[min] <= maxId) { - firstDataPosition = min; - } - - if (firstDataPosition === null) { - // no elements in this chunk - return []; - } - - // find last position - // if loki IDs are contiguous (no removed elements), last position will be first + chunk - 1 - // (and we look back in case there are missing pieces) - // TODO: Binary search (not as important as first position, worst case scanario is only chunkSize steps) - var lastDataPosition = null; - for (var i = firstDataPosition + this.chunkSize - 1; i >= firstDataPosition; i--) { - if (idIndex[i] <= maxId) { - lastDataPosition = i; - break; + else if (typeof exports === "object") { + // CommonJS + module.exports = factory(); + } + else { + // Browser globals + root.IncrementalIndexedDBAdapter = factory(); + } +})(this, function () { + return (function () { + "use strict"; + /* jshint -W030 */ + var DEBUG = typeof window !== 'undefined' && !!window.__loki_incremental_idb_debug; + /** + * An improved Loki persistence adapter for IndexedDB (not compatible with LokiIndexedAdapter) + * Unlike LokiIndexedAdapter, the database is saved not as one big JSON blob, but split into + * small chunks with individual collection documents. When saving, only the chunks with changed + * documents (and database metadata) is saved to IndexedDB. This speeds up small incremental + * saves by an order of magnitude on large (tens of thousands of records) databases. It also + * avoids Safari 13 bug that would cause the database to balloon in size to gigabytes + * + * The `appname` argument is not provided - to distinguish between multiple app on the same + * domain, simply use a different Loki database name + * + * @example + * var adapter = new IncrementalIndexedDBAdapter(); + * + * @constructor IncrementalIndexedDBAdapter + * + * @param {object=} options Configuration options for the adapter + * @param {function} options.onversionchange Function to call on `IDBDatabase.onversionchange` event + * (most likely database deleted from another browser tab) + * @param {function} options.onFetchStart Function to call once IDB load has begun. + * Use this as an opportunity to execute code concurrently while IDB does work on a separate thread + * @param {function} options.onDidOverwrite Called when this adapter is forced to overwrite contents + * of IndexedDB. This happens if there's another open tab of the same app that's making changes. + * You might use it as an opportunity to alert user to the potential loss of data + * @param {function} options.serializeChunk Called with a chunk (array of Loki documents) before + * it's saved to IndexedDB. You can use it to manually compress on-disk representation + * for faster database loads. Hint: Hand-written conversion of objects to arrays is very + * profitable for performance. If you use this, you must also pass options.deserializeChunk. + * @param {function} options.deserializeChunk Called with a chunk serialized with options.serializeChunk + * Expects an array of Loki documents as the return value + * @param {number} options.megachunkCount Number of parallel requests for data when loading database. + * Can be tuned for a specific application + * @param {function} options.encrypt Called on each collection name or chunk string (after serialization), + * before saving into IDB. + * @param {function} options.decrypt Called on each collecion name or chunk string after retrieval from IDB. + */ + function IncrementalIndexedDBAdapter(options) { + const that = this; + this.mode = "incremental"; + this.options = options || {}; + this.chunkSize = 100; + this.megachunkCount = this.options.megachunkCount || 20; + this.idb = null; // will be lazily loaded on first operation that needs it + this.idbActualLokiObjectStoreName = null; // will be lazily loaded, same as .idb + this.keyResolver = null; // will be lazily loaded, same as .idb + this._prevLokiVersionId = null; + this._prevCollectionVersionIds = {}; + var shouldSetupEncryption = !!this.options.encrypt; + if (shouldSetupEncryption) { + if (shouldSetupEncryption && !this.options.decrypt) { + throw Error('encrypt was provided, but decrypt was not. You must pass both functions.'); + } + if (shouldSetupEncryption && !isFunction(this.options.encrypt)) { + throw Error('encrypt was provided, but it is not an async function!'); + } + if (shouldSetupEncryption && !isFunction(this.options.decrypt)) { + throw Error('decrypt was provided, but it is not an async function!'); + } + this.encrypt = makeExternalFunctionSafe(this.options.encrypt, function (a) { return 'Error while invoking encrypt function. Supplied args: ' + a; }); + this.decrypt = makeExternalFunctionSafe(this.options.decrypt, function (a) { return 'Error while invoking decrypt function. Is the data really encrypted? Supplied args: ' + a; }); + // not perfect and could cause problems + this.encrypt('test').then(result => { + that.encryptOutputsString = (typeof result === 'string'); + }); + this._names = { + objectStoreName: "LID", + lokiKeyName: "lk_____________", // some padding to give it roughly the same length as .ck., so that is is indistinguishable + chunk: "ck", + metadata: "md___" // padding for the same reason as lokiKeyName + }; + } + else { + this.encrypt = doNothing; + this.decrypt = doNothing; + this.encrypt('test').then(result => { + that.encryptOutputsString = (typeof result === 'string'); + }); + this._names = { + objectStoreName: "LokiIncrementalData", + lokiKeyName: "loki", + chunk: "chunk", + metadata: "metadata" + }; + } + if (!(this.megachunkCount >= 4 && this.megachunkCount % 2 === 0)) { + throw new Error('megachunkCount must be >=4 and divisible by 2'); + } } - } - - // verify - var firstElement = collection.data[firstDataPosition]; - if (!(firstElement && firstElement.$loki >= minId && firstElement.$loki <= maxId)) { - throw new Error("broken invariant firstelement"); - } - - var lastElement = collection.data[lastDataPosition]; - if (!(lastElement && lastElement.$loki >= minId && lastElement.$loki <= maxId)) { - throw new Error("broken invariant lastElement"); - } - - // this will have *up to* 'this.chunkSize' elements (might have less, because $loki ids - // will have holes when data is deleted) - var chunkData = collection.data.slice(firstDataPosition, lastDataPosition + 1); - - if (chunkData.length > this.chunkSize) { - throw new Error("broken invariant - chunk size"); - } - - return chunkData; - }; - - /** - * Incrementally saves the database to IndexedDB - * - * @example - * var idbAdapter = new IncrementalIndexedDBAdapter(); - * var db = new loki('test', { adapter: idbAdapter }); - * var coll = db.addCollection('testColl'); - * coll.insert({test: 'val'}); - * db.saveDatabase(); - * - * @param {string} dbname - the name to give the serialized database - * @param {function} getLokiCopy - returns copy of the Loki database - * @param {function} callback - (Optional) callback passed obj.success with true or false - * @memberof IncrementalIndexedDBAdapter - */ - IncrementalIndexedDBAdapter.prototype.saveDatabase = function(dbname, getLokiCopy, callback) { - var that = this; - - if (!this.idb) { - this._initializeIDB(dbname, callback, function() { - that.saveDatabase(dbname, getLokiCopy, callback); - }); - return; - } - - if (this.operationInProgress) { - throw new Error("Error while saving to database - another operation is already in progress. Please use throttledSaves=true option on Loki object"); - } - this.operationInProgress = true; - - DEBUG && console.log("saveDatabase - begin"); - DEBUG && console.time("saveDatabase"); - function finish(e) { - DEBUG && e && console.error(e); - DEBUG && console.timeEnd("saveDatabase"); - that.operationInProgress = false; - callback(e); - } - - // try..catch is required, e.g.: - // InvalidStateError: Failed to execute 'transaction' on 'IDBDatabase': The database connection is closing. - // (this may happen if another tab has called deleteDatabase) - try { - var updatePrevVersionIds = function () { - console.error('Unexpected successful tx - cannot update previous version ids'); + // chunkId - index of the data chunk - e.g. chunk 0 will be lokiIds 0-99 + IncrementalIndexedDBAdapter.prototype._getChunk = function (collection, chunkId) { + // 0-99, 100-199, etc. + var minId = chunkId * this.chunkSize; + var maxId = minId + this.chunkSize - 1; + // use idIndex to find first collection.data position within the $loki range + collection.ensureId(); + var idIndex = collection.idIndex; + var firstDataPosition = null; + var max = idIndex.length - 1, min = 0, mid; + while (idIndex[min] < idIndex[max]) { + mid = (min + max) >> 1; + if (idIndex[mid] < minId) { + min = mid + 1; + } + else { + max = mid; + } + } + if (max === min && idIndex[min] >= minId && idIndex[min] <= maxId) { + firstDataPosition = min; + } + if (firstDataPosition === null) { + // no elements in this chunk + return []; + } + // find last position + // if loki IDs are contiguous (no removed elements), last position will be first + chunk - 1 + // (and we look back in case there are missing pieces) + // TODO: Binary search (not as important as first position, worst case scanario is only chunkSize steps) + var lastDataPosition = null; + for (var i = firstDataPosition + this.chunkSize - 1; i >= firstDataPosition; i--) { + if (idIndex[i] <= maxId) { + lastDataPosition = i; + break; + } + } + // verify + var firstElement = collection.data[firstDataPosition]; + if (!(firstElement && firstElement.$loki >= minId && firstElement.$loki <= maxId)) { + throw new Error("broken invariant firstelement"); + } + if (lastDataPosition === null) { + throw new Error("Unexpected lastDataPosition"); + } + var lastElement = collection.data[lastDataPosition]; + if (!(lastElement && lastElement.$loki >= minId && lastElement.$loki <= maxId)) { + throw new Error("broken invariant lastElement"); + } + // this will have *up to* 'this.chunkSize' elements (might have less, because $loki ids + // will have holes when data is deleted) + var chunkData = collection.data.slice(firstDataPosition, lastDataPosition + 1); + if (chunkData.length > this.chunkSize) { + throw new Error("broken invariant - chunk size"); + } + return chunkData; }; - var didOverwrite = false; - - var tx = this.idb.transaction(['LokiIncrementalData'], "readwrite"); - tx.oncomplete = function() { - updatePrevVersionIds(); - finish(); - if (didOverwrite && that.options.onDidOverwrite) { - that.options.onDidOverwrite(); - } + /** + * Incrementally saves the database to IndexedDB + * + * @example + * var idbAdapter = new IncrementalIndexedDBAdapter(); + * var db = new loki('test', { adapter: idbAdapter }); + * var coll = db.addCollection('testColl'); + * coll.insert({test: 'val'}); + * db.saveDatabase(); + * + * @param {string} dbname - the name to give the serialized database + * @param {function} getLokiCopy - returns copy of the Loki database + * @param {function} callback - (Optional) callback passed obj.success with true or false + * @memberof IncrementalIndexedDBAdapter + */ + IncrementalIndexedDBAdapter.prototype.saveDatabase = function (dbname, getLokiCopy, callback) { + return __awaiter(this, void 0, void 0, function* () { + var that = this; + if (!this.idb) { + this._initializeIDB(dbname, callback, function () { + that.saveDatabase(dbname, getLokiCopy, callback); + }); + return; + } + if (this.operationInProgress) { + throw new Error("Error while saving to database - another operation is already in progress. Please use throttledSaves=true option on Loki object"); + } + this.operationInProgress = true; + DEBUG && console.log("saveDatabase - begin"); + DEBUG && console.time("saveDatabase"); + function finish(e) { + DEBUG && e && console.error(e); + DEBUG && console.timeEnd("saveDatabase"); + that.operationInProgress = false; + callback(e); + } + // try..catch is required, e.g.: + // InvalidStateError: Failed to execute 'transaction' on 'IDBDatabase': The database connection is closing. + // (this may happen if another tab has called deleteDatabase) + try { + var updatePrevVersionIds = function () { + console.error('Unexpected successful tx - cannot update previous version ids'); + }; + const initialLokiVersionId = yield that.getLokiVersionId(); + // note that initialPureLokiObject can be encrypted + const initialPureLokiObject = yield idbRequestResult(that.getPureLokiObjectRequest()); + var didOverwrite = false; + let maxChunkIds = undefined; + if (initialLokiVersionId !== that._prevLokiVersionId) { + DEBUG && console.warn('Another writer changed Loki IDB, using slow path...'); + didOverwrite = true; + // Incrementally saving changed chunks breaks down if there is more than one writer to IDB + // (multiple tabs of the same web app), leading to data corruption. To fix that, we save all + // metadata chunks (loki + collections) with a unique ID on each save and remember it. Before + // the subsequent save, we read loki from IDB to check if its version ID changed. If not, we're + // guaranteed that persisted DB is consistent with our diff. Otherwise, we fall back to the slow + // path and overwrite *all* database chunks with our version. Both reading and writing must + // happen in the same IDB transaction for this to work. + // TODO: We can optimize the slow path by fetching collection metadata chunks and comparing their + // version IDs with those last seen by us. Since any change in collection data requires a metadata + // chunk save, we're guaranteed that if the IDs match, we don't need to overwrite chukns of this collection + // NOTE: We must fetch all keys to protect against a case where another tab has wrote more + // chunks whan we did -- if so, we must delete them. + const tx = this.idb.transaction([this.idbActualLokiObjectStoreName], "readwrite"); + var store = tx.objectStore(this.idbActualLokiObjectStoreName); + const allKeys = yield idbRequestResult(store.getAllKeys()); + maxChunkIds = yield getMaxChunkIds(allKeys, that.keyResolver); + } + const incremental = !maxChunkIds; + const chunkInfo = yield that._getLokiChanges(getLokiCopy(), incremental, maxChunkIds); + var tx = that.idb.transaction([that.idbActualLokiObjectStoreName], "readwrite"); + tx.oncomplete = function () { + updatePrevVersionIds(); + finish(undefined); + if (didOverwrite && that.options.onDidOverwrite) { + that.options.onDidOverwrite(); + } + }; + tx.onerror = function (e) { + finish(e); + }; + tx.onabort = function (e) { + finish(e); + }; + var store = tx.objectStore(that.idbActualLokiObjectStoreName); + // we recheck if there was version change + try { + idbReq(that.getPureLokiObjectRequest(tx), function (e) { + const latestPureLokiObject = e.target.result; + // we compare loki object and expect that version changed if it doesn't match. Reason for this is + // that to get version itself we would potentially be required to decrypt which in turn can be async. + // This can cause transaction to stop which would prevent all of this from working. + const lokiObjectsMatch = (latestPureLokiObject === undefined && initialPureLokiObject === undefined) + || (that.encryptOutputsString && (latestPureLokiObject === null || latestPureLokiObject === void 0 ? void 0 : latestPureLokiObject.value) === (initialPureLokiObject === null || initialPureLokiObject === void 0 ? void 0 : initialPureLokiObject.value)) + || (!that.encryptOutputsString && arrayBuffersEqual(latestPureLokiObject === null || latestPureLokiObject === void 0 ? void 0 : latestPureLokiObject.value, initialPureLokiObject === null || initialPureLokiObject === void 0 ? void 0 : initialPureLokiObject.value)); + if (lokiObjectsMatch) { + that._applyDBChanges(store, chunkInfo.dbChanges); + // Update last seen version IDs, but only after the transaction is successful + updatePrevVersionIds = function () { + that._prevLokiVersionId = chunkInfo.lokiVersionId; + chunkInfo.collectionVersionIds.forEach(function (collectionInfo) { + that._prevCollectionVersionIds[collectionInfo.name] = collectionInfo.versionId; + }); + }; + tx.commit && tx.commit(); + } + else { + // something saved in between while we were preparing data (maybe multiple tabs?). + tx.abort(); + } + }, function (error) { + tx.abort(); + finish(error); + }); + } + catch (error) { + tx.abort(); + finish(error); + } + } + catch (error) { + finish(error); + } + }); }; - - tx.onerror = function(e) { - finish(e); + // gets current largest chunk ID for each collection + function getMaxChunkIds(allCiphertextKeys, keyResolver) { + return __awaiter(this, void 0, void 0, function* () { + const maxChunkIds = {}; + for (let ciphertextKey of allCiphertextKeys) { + // table.chunk.2317 + if (yield keyResolver.isChunkKey(ciphertextKey)) { + var collection = keyResolver.getCollectionNameForCiphertextChunkKey(ciphertextKey); + var chunkId = extractChunkIdFromChunkKey(ciphertextKey) || 0; + var currentMax = maxChunkIds[collection]; + if (!currentMax || chunkId > currentMax) { + maxChunkIds[collection] = chunkId; + } + } + } + return maxChunkIds; + }); + } + IncrementalIndexedDBAdapter.prototype.getPureLokiObjectRequest = function (tx = undefined) { + if (!tx) { + tx = this.idb.transaction([this.idbActualLokiObjectStoreName], "readwrite"); + } + var store = tx.objectStore(this.idbActualLokiObjectStoreName); + return store.get(this.keyResolver.actualLokiKey); }; - - tx.onabort = function(e) { - finish(e); + IncrementalIndexedDBAdapter.prototype.getLokiVersionId = function (tx = undefined) { + return __awaiter(this, void 0, void 0, function* () { + if (!tx) { + tx = this.idb.transaction([this.idbActualLokiObjectStoreName], "readwrite"); + } + var store = tx.objectStore(this.idbActualLokiObjectStoreName); + const chunk = yield idbRequestResult(store.get(this.keyResolver.actualLokiKey)); + return yield lokiChunkVersionId(chunk, this.decrypt); + }); }; - - var store = tx.objectStore('LokiIncrementalData'); - - var performSave = function (maxChunkIds) { - try { - var incremental = !maxChunkIds; - var chunkInfo = that._putInChunks(store, getLokiCopy(), incremental, maxChunkIds); - // Update last seen version IDs, but only after the transaction is successful - updatePrevVersionIds = function() { - that._prevLokiVersionId = chunkInfo.lokiVersionId; - chunkInfo.collectionVersionIds.forEach(function (collectionInfo) { - that._prevCollectionVersionIds[collectionInfo.name] = collectionInfo.versionId; - }); - }; - tx.commit && tx.commit(); - } catch (error) { - console.error('idb performSave failed: ', error); - tx.abort(); - } + function lokiChunkVersionId(chunk, decryptFn) { + return __awaiter(this, void 0, void 0, function* () { + try { + if (chunk) { + var loki = JSON.parse(yield decryptFn(chunk.value)); + return loki.idbVersionId || null; + } + else { + return null; + } + } + catch (e) { + console.error('Error while parsing loki chunk', e); + return null; + } + }); + } + IncrementalIndexedDBAdapter.prototype._getLokiChanges = function (loki, incremental, maxChunkIds) { + return __awaiter(this, void 0, void 0, function* () { + var that = this; + var collectionVersionIds = []; + var savedSize = 0; + var prepareCollection = function (collection, i) { + return __awaiter(this, void 0, void 0, function* () { + // Find dirty chunk ids + var dirtyChunks = new Set(); + incremental && collection.dirtyIds.forEach(function (lokiId) { + var chunkId = (lokiId / that.chunkSize) | 0; + dirtyChunks.add(chunkId); + }); + collection.dirtyIds = []; + const putChunks = []; + const deleteChunkNames = []; + // Serialize chunks to save + var prepareChunk = function (chunkId) { + return __awaiter(this, void 0, void 0, function* () { + var chunkData = that._getChunk(collection, chunkId); + if (that.options.serializeChunk) { + chunkData = that.options.serializeChunk(collection.name, chunkData); + } + // we must stringify now, because IDB is asynchronous, and underlying objects are mutable + // In general, it's also faster to stringify, because we need serialization anyway, and + // JSON.stringify is much better optimized than IDB's structured clone + chunkData = yield that.encrypt(JSON.stringify(chunkData)); + savedSize += that.encryptOutputsString ? chunkData.length : chunkData.byteLength; + DEBUG && incremental && console.log('Saving: ' + collection.name + ".chunk." + chunkId); + try { + putChunks.push({ + key: yield that.keyResolver.getOrGenerateCiphertextCollectionChunkKey(collection.name, chunkId), + value: chunkData, + }); + } + catch (e) { + console.error(e); + } + }); + }; + if (incremental) { + for (let dirtyChunk of dirtyChunks) { + yield prepareChunk(dirtyChunk); + } + } + else { + // add all chunks + var maxChunkId = (collection.maxId / that.chunkSize) | 0; + for (var j = 0; j <= maxChunkId; j += 1) { + yield prepareChunk(j); + } + // delete chunks with larger ids than what we have + // NOTE: we don't have to delete metadata chunks as they will be absent from loki anyway + // NOTE: failures are silently ignored, so we don't have to worry about holes + var persistedMaxChunkId = maxChunkIds[collection.name] || 0; + for (var k = maxChunkId + 1; k <= persistedMaxChunkId; k += 1) { + var deletedChunkName = yield that.keyResolver.getOrGenerateCiphertextCollectionChunkKey(collection.name, k); + deleteChunkNames.push(deletedChunkName); + DEBUG && console.warn('Deleted chunk: ' + deletedChunkName); + } + } + // save collection metadata as separate chunk (but only if changed) + if (collection.dirty || dirtyChunks.size || !incremental) { + collection.idIndex = []; // this is recreated lazily + collection.data = []; + collection.idbVersionId = randomVersionId(); + collectionVersionIds.push({ name: collection.name, versionId: collection.idbVersionId }); + var metadataChunk = yield that.encrypt(JSON.stringify(collection)); + savedSize += that.encryptOutputsString ? metadataChunk.length : metadataChunk.byteLength; + DEBUG && incremental && console.log('Saving: ' + collection.name + ".metadata"); + putChunks.push({ + key: yield that.keyResolver.getOrGenerateCiphertextCollectionMetadataKey(collection.name), + value: metadataChunk, + }); + } + // leave only names in the loki chunk + loki.collections[i] = { name: collection.name }; + return { putChunks, deleteChunkNames }; + }); + }; + const collectionsChanges = yield Promise.all(loki.collections.map((collection, index) => prepareCollection(collection, index))); + loki.idbVersionId = randomVersionId(); + var serializedMetadata = yield that.encrypt(JSON.stringify(loki)); + savedSize += that.encryptOutputsString ? serializedMetadata.length : serializedMetadata.byteLength; + DEBUG && incremental && console.log('Saving: loki'); + const lokiChunk = { key: that.keyResolver.actualLokiKey, value: serializedMetadata }; + DEBUG && console.log("expected saved size: " + savedSize); + return { + lokiVersionId: loki.idbVersionId, + collectionVersionIds: collectionVersionIds, + dbChanges: { + collectionsChanges: collectionsChanges, + lokiChunk, + }, + }; + }); }; - - // Incrementally saving changed chunks breaks down if there is more than one writer to IDB - // (multiple tabs of the same web app), leading to data corruption. To fix that, we save all - // metadata chunks (loki + collections) with a unique ID on each save and remember it. Before - // the subsequent save, we read loki from IDB to check if its version ID changed. If not, we're - // guaranteed that persisted DB is consistent with our diff. Otherwise, we fall back to the slow - // path and overwrite *all* database chunks with our version. Both reading and writing must - // happen in the same IDB transaction for this to work. - // TODO: We can optimize the slow path by fetching collection metadata chunks and comparing their - // version IDs with those last seen by us. Since any change in collection data requires a metadata - // chunk save, we're guaranteed that if the IDs match, we don't need to overwrite chukns of this collection - var getAllKeysThenSave = function() { - // NOTE: We must fetch all keys to protect against a case where another tab has wrote more - // chunks whan we did -- if so, we must delete them. - idbReq(store.getAllKeys(), function(e) { - var maxChunkIds = getMaxChunkIds(e.target.result); - performSave(maxChunkIds); - }, function(e) { - console.error('Getting all keys failed: ', e); - tx.abort(); - }); + IncrementalIndexedDBAdapter.prototype._applyDBChanges = function (idbStore, dbChanges) { + return __awaiter(this, void 0, void 0, function* () { + dbChanges.collectionsChanges.forEach(collectionChanges => { + collectionChanges.putChunks.forEach(putChunk => { + idbStore.put(putChunk); + }); + collectionChanges.deleteChunkNames.forEach(deleteChunkName => { + idbStore.delete(deleteChunkName); + DEBUG && console.warn('Deleted chunk: ' + deleteChunkName); + }); + }); + idbStore.put(dbChanges.lokiChunk); + }); }; - - var getLokiThenSave = function() { - idbReq(store.get('loki'), function(e) { - if (lokiChunkVersionId(e.target.result) === that._prevLokiVersionId) { - performSave(); - } else { - DEBUG && console.warn('Another writer changed Loki IDB, using slow path...'); - didOverwrite = true; - getAllKeysThenSave(); - } - }, function(e) { - console.error('Getting loki chunk failed: ', e); - tx.abort(); - }); + /** + * Retrieves a serialized db string from the catalog. + * + * @example + * // LOAD + * var idbAdapter = new IncrementalIndexedDBAdapter(); + * var db = new loki('test', { adapter: idbAdapter }); + * db.loadDatabase(function(result) { + * console.log('done'); + * }); + * + * @param {string} dbname - the name of the database to retrieve. + * @param {function} callback - callback should accept string param containing serialized db string. + * @memberof IncrementalIndexedDBAdapter + */ + IncrementalIndexedDBAdapter.prototype.loadDatabase = function (dbname, callback) { + return __awaiter(this, void 0, void 0, function* () { + var that = this; + if (this.operationInProgress) { + throw new Error("Error while loading database - another operation is already in progress. Please use throttledSaves=true option on Loki object"); + } + this.operationInProgress = true; + DEBUG && console.log("loadDatabase - begin"); + DEBUG && console.time("loadDatabase"); + var finish = function (value) { + DEBUG && console.timeEnd("loadDatabase"); + that.operationInProgress = false; + callback(value); + }; + yield this._getAllChunks(dbname, function (chunks) { + return __awaiter(this, void 0, void 0, function* () { + try { + if (!Array.isArray(chunks)) { + throw chunks; // we have an error + } + if (!chunks.length) { + return finish(null); + } + DEBUG && console.log("Found chunks:", chunks.length); + // repack chunks into a map + chunks = yield chunksToMap(chunks, that.keyResolver); + var loki = chunks.loki; + chunks.loki = null; // gc + // populate collections with data + populateLoki(loki, chunks.chunkMap); + chunks = null; // gc + // remember previous version IDs + that._prevLokiVersionId = loki.idbVersionId || null; + that._prevCollectionVersionIds = {}; + loki.collections.forEach(function (collection) { + that._prevCollectionVersionIds[collection.name] = collection.idbVersionId || null; + }); + return finish(loki); + } + catch (error) { + that._prevLokiVersionId = null; + that._prevCollectionVersionIds = {}; + return finish(error); + } + }); + }); + }); }; - - getLokiThenSave(); - } catch (error) { - finish(error); - } - }; - - // gets current largest chunk ID for each collection - function getMaxChunkIds(allKeys) { - var maxChunkIds = {}; - - allKeys.forEach(function (key) { - var keySegments = key.split("."); - // table.chunk.2317 - if (keySegments.length === 3 && keySegments[1] === "chunk") { - var collection = keySegments[0]; - var chunkId = parseInt(keySegments[2]) || 0; - var currentMax = maxChunkIds[collection]; - - if (!currentMax || chunkId > currentMax) { - maxChunkIds[collection] = chunkId; - } + function chunksToMap(chunks, keyResolver) { + return __awaiter(this, void 0, void 0, function* () { + var loki; + var chunkMap = {}; + yield sortChunksInPlace(chunks, keyResolver); + for (let object of chunks) { + var key = object.key; + var value = object.value; + if (keyResolver.isLokiKey(key)) { + loki = value; + continue; + } + else { + if (yield keyResolver.isChunkKey(key)) { + var colName = keyResolver.getCollectionNameForCiphertextChunkKey(key); + if (chunkMap[colName]) { + chunkMap[colName].dataChunks.push(value); + } + else { + chunkMap[colName] = { + metadata: null, + dataChunks: [value], + }; + } + continue; + } + if (keyResolver.isMetadataKey(key)) { + var name = keyResolver.getCollectionNameForMetadataKey(key); + if (chunkMap[name]) { + chunkMap[name].metadata = value; + } + else { + chunkMap[name] = { metadata: value, dataChunks: [] }; + } + continue; + } + } + console.error("Unknown chunk " + key); + throw new Error("Corrupted database - unknown chunk found"); + } + ; + if (!loki) { + throw new Error("Corrupted database - missing database metadata"); + } + return { loki: loki, chunkMap: chunkMap }; + }); } - }); - return maxChunkIds; - } - - function lokiChunkVersionId(chunk) { - try { - if (chunk) { - var loki = JSON.parse(chunk.value); - return loki.idbVersionId || null; - } else { - return null; + function populateLoki(loki, chunkMap) { + loki.collections.forEach(function populateCollection(collectionStub, i) { + var chunkCollection = chunkMap[collectionStub.name]; + if (chunkCollection) { + if (!chunkCollection.metadata) { + throw new Error("Corrupted database - missing metadata chunk for " + collectionStub.name); + } + var collection = chunkCollection.metadata; + chunkCollection.metadata = null; + loki.collections[i] = collection; + var dataChunks = chunkCollection.dataChunks; + dataChunks.forEach(function populateChunk(chunk, i) { + chunk.forEach(function (doc) { + collection.data.push(doc); + }); + dataChunks[i] = null; + }); + } + }); } - } catch (e) { - console.error('Error while parsing loki chunk', e); - return null; - } - } - - IncrementalIndexedDBAdapter.prototype._putInChunks = function(idbStore, loki, incremental, maxChunkIds) { - var that = this; - var collectionVersionIds = []; - var savedSize = 0; - - var prepareCollection = function (collection, i) { - // Find dirty chunk ids - var dirtyChunks = new Set(); - incremental && collection.dirtyIds.forEach(function(lokiId) { - var chunkId = (lokiId / that.chunkSize) | 0; - dirtyChunks.add(chunkId); - }); - collection.dirtyIds = []; - - // Serialize chunks to save - var prepareChunk = function (chunkId) { - var chunkData = that._getChunk(collection, chunkId); - if (that.options.serializeChunk) { - chunkData = that.options.serializeChunk(collection.name, chunkData); - } - // we must stringify now, because IDB is asynchronous, and underlying objects are mutable - // In general, it's also faster to stringify, because we need serialization anyway, and - // JSON.stringify is much better optimized than IDB's structured clone - chunkData = JSON.stringify(chunkData); - savedSize += chunkData.length; - DEBUG && incremental && console.log('Saving: ' + collection.name + ".chunk." + chunkId); - idbStore.put({ - key: collection.name + ".chunk." + chunkId, - value: chunkData, - }); + IncrementalIndexedDBAdapter.prototype._initializeIDB = function (dbname, onError, onSuccess) { + return __awaiter(this, void 0, void 0, function* () { + var that = this; + DEBUG && console.log("initializing idb"); + if (this.idbInitInProgress) { + throw new Error("Cannot open IndexedDB because open is already in progress"); + } + this.idbInitInProgress = true; + const encryptedObjectStoreName = yield that._encryptToString(that._names.objectStoreName); + var openRequest = indexedDB.open(dbname, 1); + openRequest.onupgradeneeded = function (e) { + var db = e.target.result; + DEBUG && console.log('onupgradeneeded, old version: ' + e.oldVersion); + if (e.oldVersion < 1) { + // Version 1 - Initial - Create database + db.createObjectStore(encryptedObjectStoreName, { keyPath: "key" }); + } + else { + // Unknown version + throw new Error("Invalid old version " + e.oldVersion + " for IndexedDB upgrade"); + } + }; + openRequest.onsuccess = function (e) { + that.idbInitInProgress = false; + var db = e.target.result; + const objectStoreNames = db.objectStoreNames; + that.idb = db; + (() => __awaiter(this, void 0, void 0, function* () { + const idbActualLokiObjectStoreName = yield findIdbActualLokiObjectStoreName(objectStoreNames, that._names.objectStoreName, that._decryptFromString.bind(that)); + that.idbActualLokiObjectStoreName = idbActualLokiObjectStoreName; + if (!that.idbActualLokiObjectStoreName) { + onError(new Error("Missing IndexedDB objectStore: " + that._names.objectStoreName + (that.decrypt ? ' (searched using decrypt function)' : ''))); + // Attempt to recover (after reload) by deleting database, since it's damaged anyway + that.deleteDatabase(dbname); + return; + } + var tx = that.idb.transaction([that.idbActualLokiObjectStoreName], "readonly"); + var store = tx.objectStore(that.idbActualLokiObjectStoreName); + const keyResolver = yield extractkeyResolver(store, that._names, that.encrypt, that._encryptToString.bind(that), that.decrypt, that._decryptFromString.bind(that)); + that.keyResolver = keyResolver; + onSuccess(); + }))(); + try { + DEBUG && console.log("init success"); + db.onversionchange = function (versionChangeEvent) { + // Ignore if database was deleted and recreated in the meantime + if (that.idb !== db) { + return; + } + DEBUG && console.log('IDB version change', versionChangeEvent); + // This function will be called if another connection changed DB version + // (Most likely database was deleted from another browser tab, unless there's a new version + // of this adapter, or someone makes a connection to IDB outside of this adapter) + // We must close the database to avoid blocking concurrent deletes. + // The database will be unusable after this. Be sure to supply `onversionchange` option + // to force logout + that.idb.close(); + that.idb = null; + if (that.options.onversionchange) { + that.options.onversionchange(versionChangeEvent); + } + }; + } + catch (e) { + console.error("Error while retrieving actual IDB lokiKeyName", e); + throw e; + } + ; + }; + openRequest.onblocked = function (e) { + console.error("IndexedDB open is blocked", e); + onError(new Error("IndexedDB open is blocked by open connection")); + }; + openRequest.onerror = function (e) { + that.idbInitInProgress = false; + console.error("IndexedDB open error", e); + onError(e); + }; + }); + }; + IncrementalIndexedDBAdapter.prototype._getAllChunks = function (dbname, callback) { + return __awaiter(this, void 0, void 0, function* () { + var that = this; + if (!this.idb) { + this._initializeIDB(dbname, callback, function () { + that._getAllChunks(dbname, callback); + }); + return; + } + var tx = this.idb.transaction([that.idbActualLokiObjectStoreName], "readonly"); + var store = tx.objectStore(that.idbActualLokiObjectStoreName); + // If there are a lot of chunks (>100), don't request them all in one go, but in multiple + // "megachunks" (chunks of chunks). This improves concurrency, as main thread is already busy + // while IDB process is still fetching data. Details: https://github.com/techfort/LokiJS/pull/874 + function getMegachunks(keys) { + return __awaiter(this, void 0, void 0, function* () { + var megachunkCount = that.megachunkCount; + var keyRanges = createKeyRanges(keys, megachunkCount); + var allChunks = []; + var megachunksReceived = 0; + function processMegachunk(megachunk, megachunkIndex, keyRange) { + return __awaiter(this, void 0, void 0, function* () { + // var debugMsg = 'processing chunk ' + megachunkIndex + ' (' + keyRange.lower + ' -- ' + keyRange.upper + ')' + // DEBUG && console.time(debugMsg); + for (let i = 0; i < megachunk.length; i++) { + try { + const chunk = megachunk[i]; + yield parseChunk(chunk, that.deserializeChunk, that.keyResolver, that.decrypt, that._decryptFromString.bind(that)); + allChunks.push(chunk); + megachunk[i] = null; // gc + } + catch (e) { + throw new Error(e); + } + } + // DEBUG && console.timeEnd(debugMsg); + megachunksReceived += 1; + if (megachunksReceived === megachunkCount) { + callback(allChunks); + } + }); + } + // Stagger megachunk requests - first one half, then request the second when first one comes + // back. This further improves concurrency. + function requestMegachunk(index) { + return __awaiter(this, void 0, void 0, function* () { + var keyRange = keyRanges[index]; + idbReq(store.getAll(keyRange), function (e) { + if (index < megachunkCount / 2) { + requestMegachunk(index + megachunkCount / 2); + } + const megachunk = e.target.result; + processMegachunk(megachunk, index, keyRange); + }, function (e) { + callback(e); + }); + }); + } + for (var i = 0; i < megachunkCount / 2; i += 1) { + yield requestMegachunk(i); + } + }); + } + function getAllChunks() { + idbReq(store.getAll(), function (e) { + var allChunks = e.target.result; + (() => __awaiter(this, void 0, void 0, function* () { + yield Promise.all(allChunks.map(function (chunk) { + return __awaiter(this, void 0, void 0, function* () { + yield parseChunk(chunk, that.deserializeChunk, that.keyResolver, that.decrypt, that._decryptFromString.bind(that)); + }); + })); + callback(allChunks); + }))(); + }, function (e) { + callback(e); + }); + } + function getAllKeys() { + idbReq(store.getAllKeys(), function (e) { + const keys = e.target.result; + if (keys.length > 100) { + // it is okay if this is sorted as 0, 1, 10, 100 and not 0, 1, 2... + var sortedKeys = keys.sort(); + getMegachunks(sortedKeys); + } + else { + getAllChunks(); + } + }, function (e) { + callback(e); + }); + if (that.options.onFetchStart) { + that.options.onFetchStart(); + } + } + getAllKeys(); + }); }; - if (incremental) { - dirtyChunks.forEach(prepareChunk); - } else { - // add all chunks - var maxChunkId = (collection.maxId / that.chunkSize) | 0; - for (var j = 0; j <= maxChunkId; j += 1) { - prepareChunk(j); - } - - // delete chunks with larger ids than what we have - // NOTE: we don't have to delete metadata chunks as they will be absent from loki anyway - // NOTE: failures are silently ignored, so we don't have to worry about holes - var persistedMaxChunkId = maxChunkIds[collection.name] || 0; - for (var k = maxChunkId + 1; k <= persistedMaxChunkId; k += 1) { - var deletedChunkName = collection.name + ".chunk." + k; - idbStore.delete(deletedChunkName); - DEBUG && console.warn('Deleted chunk: ' + deletedChunkName); - } + function parseChunk(chunk, deserializeChunk, keyResolver, decryptFn, decryptFromStringFn) { + return __awaiter(this, void 0, void 0, function* () { + if (typeof chunk.value === 'string') { + chunk.value = JSON.parse(yield decryptFromStringFn(chunk.value)); + } + else { + chunk.value = JSON.parse(yield decryptFn(chunk.value)); + } + if (deserializeChunk) { + if (yield keyResolver.isChunkKey(chunk.key)) { + var collectionName = keyResolver.getCollectionNameForCiphertextChunkKey(chunk.key); + chunk.value = deserializeChunk(collectionName, chunk.value); + } + } + }); } - - // save collection metadata as separate chunk (but only if changed) - if (collection.dirty || dirtyChunks.size || !incremental) { - collection.idIndex = []; // this is recreated lazily - collection.data = []; - collection.idbVersionId = randomVersionId(); - collectionVersionIds.push({ name: collection.name, versionId: collection.idbVersionId }); - - var metadataChunk = JSON.stringify(collection); - savedSize += metadataChunk.length; - DEBUG && incremental && console.log('Saving: ' + collection.name + ".metadata"); - idbStore.put({ - key: collection.name + ".metadata", - value: metadataChunk, - }); + /** + * Deletes a database from IndexedDB + * + * @example + * // DELETE DATABASE + * // delete 'finance'/'test' value from catalog + * idbAdapter.deleteDatabase('test', function { + * // database deleted + * }); + * + * @param {string} dbname - the name of the database to delete from IDB + * @param {function=} callback - (Optional) executed on database delete + * @memberof IncrementalIndexedDBAdapter + */ + IncrementalIndexedDBAdapter.prototype.deleteDatabase = function (dbname, callback) { + if (this.operationInProgress) { + throw new Error("Error while deleting database - another operation is already in progress. Please use throttledSaves=true option on Loki object"); + } + this.operationInProgress = true; + var that = this; + DEBUG && console.log("deleteDatabase - begin"); + DEBUG && console.time("deleteDatabase"); + this._prevLokiVersionId = null; + this._prevCollectionVersionIds = {}; + if (this.idb) { + this.idb.close(); + this.idb = null; + } + var request = indexedDB.deleteDatabase(dbname); + request.onsuccess = function () { + that.operationInProgress = false; + DEBUG && console.timeEnd("deleteDatabase"); + callback({ success: true }); + }; + request.onerror = function (e) { + that.operationInProgress = false; + console.error("Error while deleting database", e); + callback({ success: false }); + }; + request.onblocked = function (e) { + // We can't call callback with failure status, because this will be called even if we + // succeed in just a moment + console.error("Deleting database failed because it's blocked by another connection", e); + }; + }; + IncrementalIndexedDBAdapter.prototype._encryptToString = function (s) { + return __awaiter(this, void 0, void 0, function* () { + const encrypted = yield this.encrypt(s); + if (this.encryptOutputsString) { + // encrypt algo already directly outputs string - not optimal but possible atm + return encrypted; + } + // trying to avoid spread to prevent max call stack size exceeded. + let binary = ''; + const bytes = new Uint8Array(encrypted); + const len = bytes.byteLength; + for (let i = 0; i < len; i++) { + binary += String.fromCharCode(bytes[i]); + } + return window.btoa(binary); + }); + }; + IncrementalIndexedDBAdapter.prototype._decryptFromString = function (s) { + return __awaiter(this, void 0, void 0, function* () { + if (this.encryptOutputsString) { + return yield this.decrypt(s); + } + const encrypted = Uint8Array.from(atob(s), c => c.charCodeAt(0)); + return yield this.decrypt(encrypted); + }); + }; + function randomVersionId() { + // Appears to have enough entropy for chunk version IDs + // (Only has to be different than enough of its own previous versions that there's no writer + // that thinks a new version is the same as an earlier one, not globally unique) + return Math.random().toString(36).substring(2); } - - // leave only names in the loki chunk - loki.collections[i] = { name: collection.name }; - }; - loki.collections.forEach(prepareCollection); - - loki.idbVersionId = randomVersionId(); - var serializedMetadata = JSON.stringify(loki); - savedSize += serializedMetadata.length; - - DEBUG && incremental && console.log('Saving: loki'); - idbStore.put({ key: "loki", value: serializedMetadata }); - - DEBUG && console.log("saved size: " + savedSize); - return { - lokiVersionId: loki.idbVersionId, - collectionVersionIds: collectionVersionIds, - }; - }; - - /** - * Retrieves a serialized db string from the catalog. - * - * @example - * // LOAD - * var idbAdapter = new IncrementalIndexedDBAdapter(); - * var db = new loki('test', { adapter: idbAdapter }); - * db.loadDatabase(function(result) { - * console.log('done'); - * }); - * - * @param {string} dbname - the name of the database to retrieve. - * @param {function} callback - callback should accept string param containing serialized db string. - * @memberof IncrementalIndexedDBAdapter - */ - IncrementalIndexedDBAdapter.prototype.loadDatabase = function(dbname, callback) { - var that = this; - - if (this.operationInProgress) { - throw new Error("Error while loading database - another operation is already in progress. Please use throttledSaves=true option on Loki object"); - } - - this.operationInProgress = true; - - DEBUG && console.log("loadDatabase - begin"); - DEBUG && console.time("loadDatabase"); - - var finish = function (value) { - DEBUG && console.timeEnd("loadDatabase"); - that.operationInProgress = false; - callback(value); - }; - - this._getAllChunks(dbname, function(chunks) { - try { - if (!Array.isArray(chunks)) { - throw chunks; // we have an error - } - - if (!chunks.length) { - return finish(null); - } - - DEBUG && console.log("Found chunks:", chunks.length); - - // repack chunks into a map - chunks = chunksToMap(chunks); - var loki = chunks.loki; - chunks.loki = null; // gc - - // populate collections with data - populateLoki(loki, chunks.chunkMap); - chunks = null; // gc - - // remember previous version IDs - that._prevLokiVersionId = loki.idbVersionId || null; - that._prevCollectionVersionIds = {}; - loki.collections.forEach(function (collection) { - that._prevCollectionVersionIds[collection.name] = collection.idbVersionId || null; - }); - - return finish(loki); - } catch (error) { - that._prevLokiVersionId = null; - that._prevCollectionVersionIds = {}; - return finish(error); + function _getSortKey(object, keyResolver) { + return __awaiter(this, void 0, void 0, function* () { + var key = object.key; + if (yield keyResolver.isChunkKey(key)) { + return extractChunkIdFromChunkKey(key); + } + return -1; // consistent type must be returned + }); } - }); - }; - - function chunksToMap(chunks) { - var loki; - var chunkMap = {}; - - sortChunksInPlace(chunks); - - chunks.forEach(function(object) { - var key = object.key; - var value = object.value; - if (key === "loki") { - loki = value; - return; - } else if (key.includes(".")) { - var keySegments = key.split("."); - if (keySegments.length === 3 && keySegments[1] === "chunk") { - var colName = keySegments[0]; - if (chunkMap[colName]) { - chunkMap[colName].dataChunks.push(value); - } else { - chunkMap[colName] = { - metadata: null, - dataChunks: [value], - }; - } - return; - } else if (keySegments.length === 2 && keySegments[1] === "metadata") { - var name = keySegments[0]; - if (chunkMap[name]) { - chunkMap[name].metadata = value; - } else { - chunkMap[name] = { metadata: value, dataChunks: [] }; + function sortChunksInPlace(chunks, keyResolver) { + return __awaiter(this, void 0, void 0, function* () { + // sort chunks in place to load data in the right order (ascending loki ids) + // on both Safari and Chrome, we'll get chunks in order like this: 0, 1, 10, 100... + // we get sort keys in advance to prevent potentially decrypting multiple times + const mapped = new Map(yield Promise.all(chunks.map((item) => __awaiter(this, void 0, void 0, function* () { + const sortKey = yield _getSortKey(item, keyResolver); + return [item.key, sortKey]; + })))); + chunks.sort(function (a, b) { + const aKey = mapped.get(a.key), bKey = mapped.get(b.key); + if (!bKey) + return 1; + if (!aKey) + return -1; + if (aKey < bKey) + return -1; + if (aKey > bKey) + return 1; + return 0; + }); + }); + } + function createKeyRanges(keys, count) { + var countPerRange = Math.floor(keys.length / count); + var keyRanges = []; + var minKey, maxKey; + for (var i = 0; i < count; i += 1) { + minKey = keys[countPerRange * i]; + maxKey = keys[countPerRange * (i + 1)]; + if (i === 0) { + // ... < maxKey + keyRanges.push(IDBKeyRange.upperBound(maxKey, true)); + } + else if (i === count - 1) { + // >= minKey + keyRanges.push(IDBKeyRange.lowerBound(minKey)); + } + else { + // >= minKey && < maxKey + keyRanges.push(IDBKeyRange.bound(minKey, maxKey, false, true)); + } } - return; - } + return keyRanges; } - - console.error("Unknown chunk " + key); - throw new Error("Corrupted database - unknown chunk found"); - }); - - if (!loki) { - throw new Error("Corrupted database - missing database metadata"); - } - - return { loki: loki, chunkMap: chunkMap }; - } - - function populateLoki(loki, chunkMap) { - loki.collections.forEach(function populateCollection(collectionStub, i) { - var chunkCollection = chunkMap[collectionStub.name]; - if (chunkCollection) { - if (!chunkCollection.metadata) { - throw new Error("Corrupted database - missing metadata chunk for " + collectionStub.name); - } - var collection = chunkCollection.metadata; - chunkCollection.metadata = null; - - loki.collections[i] = collection; - - var dataChunks = chunkCollection.dataChunks; - dataChunks.forEach(function populateChunk(chunk, i) { - chunk.forEach(function(doc) { - collection.data.push(doc); + function idbReq(request, onsuccess, onerror) { + request.onsuccess = function (e) { + try { + return onsuccess(e); + } + catch (error) { + onerror(error); + } + }; + request.onerror = onerror; + return request; + } + function idbRequestResult(request) { + return new Promise((resolve, reject) => { + request.onsuccess = function (e) { + resolve(e.target.result); + }; + request.onerror = function (e) { + reject(e); + }; }); - dataChunks[i] = null; - }); } - }); - } - - IncrementalIndexedDBAdapter.prototype._initializeIDB = function(dbname, onError, onSuccess) { - var that = this; - DEBUG && console.log("initializing idb"); - - if (this.idbInitInProgress) { - throw new Error("Cannot open IndexedDB because open is already in progress"); - } - this.idbInitInProgress = true; - - var openRequest = indexedDB.open(dbname, 1); - - openRequest.onupgradeneeded = function(e) { - var db = e.target.result; - DEBUG && console.log('onupgradeneeded, old version: ' + e.oldVersion); - - if (e.oldVersion < 1) { - // Version 1 - Initial - Create database - db.createObjectStore('LokiIncrementalData', { keyPath: "key" }); - } else { - // Unknown version - throw new Error("Invalid old version " + e.oldVersion + " for IndexedDB upgrade"); + function findIdbActualLokiObjectStoreName(objectStoreNames, decryptedObjectStoreName, decryptFromStringFn) { + return __awaiter(this, void 0, void 0, function* () { + var domStringList = objectStoreNames; + for (var i = 0; i < domStringList.length; i++) { + if ((yield decryptFromStringFn(domStringList[i])) === decryptedObjectStoreName) { + return domStringList[i]; + } + } + return null; + }); } - }; - - openRequest.onsuccess = function(e) { - that.idbInitInProgress = false; - var db = e.target.result; - that.idb = db; - - if (!db.objectStoreNames.contains('LokiIncrementalData')) { - onError(new Error("Missing LokiIncrementalData")); - // Attempt to recover (after reload) by deleting database, since it's damaged anyway - that.deleteDatabase(dbname); - return; + function isFunction(fn) { + return typeof fn === 'function'; } - - DEBUG && console.log("init success"); - - db.onversionchange = function(versionChangeEvent) { - // Ignore if database was deleted and recreated in the meantime - if (that.idb !== db) { - return; - } - - DEBUG && console.log('IDB version change', versionChangeEvent); - // This function will be called if another connection changed DB version - // (Most likely database was deleted from another browser tab, unless there's a new version - // of this adapter, or someone makes a connection to IDB outside of this adapter) - // We must close the database to avoid blocking concurrent deletes. - // The database will be unusable after this. Be sure to supply `onversionchange` option - // to force logout - that.idb.close(); - that.idb = null; - if (that.options.onversionchange) { - that.options.onversionchange(versionChangeEvent); - } - }; - - onSuccess(); - }; - - openRequest.onblocked = function(e) { - console.error("IndexedDB open is blocked", e); - onError(new Error("IndexedDB open is blocked by open connection")); - }; - - openRequest.onerror = function(e) { - that.idbInitInProgress = false; - console.error("IndexedDB open error", e); - onError(e); - }; - }; - - IncrementalIndexedDBAdapter.prototype._getAllChunks = function(dbname, callback) { - var that = this; - if (!this.idb) { - this._initializeIDB(dbname, callback, function() { - that._getAllChunks(dbname, callback); - }); - return; - } - - var tx = this.idb.transaction(['LokiIncrementalData'], "readonly"); - var store = tx.objectStore('LokiIncrementalData'); - - var deserializeChunk = this.options.deserializeChunk; - - // If there are a lot of chunks (>100), don't request them all in one go, but in multiple - // "megachunks" (chunks of chunks). This improves concurrency, as main thread is already busy - // while IDB process is still fetching data. Details: https://github.com/techfort/LokiJS/pull/874 - function getMegachunks(keys) { - var megachunkCount = that.megachunkCount; - var keyRanges = createKeyRanges(keys, megachunkCount); - - var allChunks = []; - var megachunksReceived = 0; - - function processMegachunk(e, megachunkIndex, keyRange) { - // var debugMsg = 'processing chunk ' + megachunkIndex + ' (' + keyRange.lower + ' -- ' + keyRange.upper + ')' - // DEBUG && console.time(debugMsg); - var megachunk = e.target.result; - megachunk.forEach(function (chunk, i) { - parseChunk(chunk, deserializeChunk); - allChunks.push(chunk); - megachunk[i] = null; // gc - }); - // DEBUG && console.timeEnd(debugMsg); - - megachunksReceived += 1; - if (megachunksReceived === megachunkCount) { - callback(allChunks); - } + function arrayBuffersEqual(buffer1, buffer2) { + if ((buffer1 === null || buffer1 === void 0 ? void 0 : buffer1.byteLength) !== (buffer2 === null || buffer2 === void 0 ? void 0 : buffer2.byteLength)) { + return false; + } + const view1 = new Uint8Array(buffer1); + const view2 = new Uint8Array(buffer2); + for (let i = 0; i < view1.length; i++) { + if (view1[i] !== view2[i]) { + return false; + } + } + return true; + } + function doNothing(x) { + return __awaiter(this, void 0, void 0, function* () { return x; }); } - - // Stagger megachunk requests - first one half, then request the second when first one comes - // back. This further improves concurrency. - function requestMegachunk(index) { - var keyRange = keyRanges[index]; - idbReq(store.getAll(keyRange), function(e) { - if (index < megachunkCount / 2) { - requestMegachunk(index + megachunkCount / 2); + function makeExternalFunctionSafe(fn, erroMessageGenerator) { + return function () { + try { + return fn.apply(this, arguments); + } + catch (e) { + console.error(erroMessageGenerator(arguments), e); + throw e; + } + }; + } + function getChunkKeyWithoutChunkId(key) { + var matchKeyWithoutChunkId = key.match(/^(.+)\.\d+$/); + if (matchKeyWithoutChunkId === null) { + return null; } - - processMegachunk(e, index, keyRange); - }, function(e) { - callback(e); - }); + return matchKeyWithoutChunkId[1]; } - - for (var i = 0; i < megachunkCount / 2; i += 1) { - requestMegachunk(i); + function extractChunkIdFromChunkKey(key) { + var chunkId = key.match(/^.+\.(\d+)$/); + if (chunkId === null) { + return null; + } + return parseInt(chunkId[1], 10); } - } - - function getAllChunks() { - idbReq(store.getAll(), function(e) { - var allChunks = e.target.result; - allChunks.forEach(function (chunk) { - parseChunk(chunk, deserializeChunk); - }); - callback(allChunks); - }, function(e) { - callback(e); - }); - } - - function getAllKeys() { - idbReq(store.getAllKeys(), function(e) { - var keys = e.target.result.sort(); - if (keys.length > 100) { - getMegachunks(keys); - } else { - getAllChunks(); - } - }, function(e) { - callback(e); - }); - - if (that.options.onFetchStart) { - that.options.onFetchStart(); + function isCiphertextChunkKey(ciphertextChunkKey, _names, decryptFn, decryptFromStringFn) { + return __awaiter(this, void 0, void 0, function* () { + if (typeof ciphertextChunkKey !== 'string') { + return false; + } + var ciphertextChunkKeyWithoutChunkId = getChunkKeyWithoutChunkId(ciphertextChunkKey); + if (!ciphertextChunkKeyWithoutChunkId) { + return false; + } + var plaintextChunkKeyWithoutChunkId = yield decryptFromStringFn(ciphertextChunkKeyWithoutChunkId); + return isPlaintextChunkKeyWithoutChunkId(plaintextChunkKeyWithoutChunkId, _names); + }); } - } - - getAllKeys(); - }; - - function parseChunk(chunk, deserializeChunk) { - chunk.value = JSON.parse(chunk.value); - if (deserializeChunk) { - var segments = chunk.key.split('.'); - if (segments.length === 3 && segments[1] === 'chunk') { - var collectionName = segments[0]; - chunk.value = deserializeChunk(collectionName, chunk.value); + function isPlaintextChunkKeyWithoutChunkId(plaintextChunkKeyWithoutChunkId, _names) { + return (plaintextChunkKeyWithoutChunkId.length - plaintextChunkKeyWithoutChunkId.lastIndexOf("." + _names.chunk) - ("." + _names.chunk).length) === 0; } - } - } - - /** - * Deletes a database from IndexedDB - * - * @example - * // DELETE DATABASE - * // delete 'finance'/'test' value from catalog - * idbAdapter.deleteDatabase('test', function { - * // database deleted - * }); - * - * @param {string} dbname - the name of the database to delete from IDB - * @param {function=} callback - (Optional) executed on database delete - * @memberof IncrementalIndexedDBAdapter - */ - IncrementalIndexedDBAdapter.prototype.deleteDatabase = function(dbname, callback) { - if (this.operationInProgress) { - throw new Error("Error while deleting database - another operation is already in progress. Please use throttledSaves=true option on Loki object"); - } - - this.operationInProgress = true; - - var that = this; - DEBUG && console.log("deleteDatabase - begin"); - DEBUG && console.time("deleteDatabase"); - - this._prevLokiVersionId = null; - this._prevCollectionVersionIds = {}; - - if (this.idb) { - this.idb.close(); - this.idb = null; - } - - var request = indexedDB.deleteDatabase(dbname); - - request.onsuccess = function() { - that.operationInProgress = false; - DEBUG && console.timeEnd("deleteDatabase"); - callback({ success: true }); - }; - - request.onerror = function(e) { - that.operationInProgress = false; - console.error("Error while deleting database", e); - callback({ success: false }); - }; - - request.onblocked = function(e) { - // We can't call callback with failure status, because this will be called even if we - // succeed in just a moment - console.error("Deleting database failed because it's blocked by another connection", e); - }; - }; - - function randomVersionId() { - // Appears to have enough entropy for chunk version IDs - // (Only has to be different than enough of its own previous versions that there's no writer - // that thinks a new version is the same as an earlier one, not globally unique) - return Math.random().toString(36).substring(2); - } - - function _getSortKey(object) { - var key = object.key; - if (key.includes(".")) { - var segments = key.split("."); - if (segments.length === 3 && segments[1] === "chunk") { - return parseInt(segments[2], 10); + function extractCollectionNameFromPlaintextChunkKey(plaintextChunkKey, _names) { + var plaintextChunkKeyWithoutChunkId = getChunkKeyWithoutChunkId(plaintextChunkKey); + if (!plaintextChunkKeyWithoutChunkId === null) { + return null; + } + return extractCollectionNameFromPlaintextChunkKeyWithoutChunkId(plaintextChunkKeyWithoutChunkId, _names); } - } - - return -1; // consistent type must be returned - } - - function sortChunksInPlace(chunks) { - // sort chunks in place to load data in the right order (ascending loki ids) - // on both Safari and Chrome, we'll get chunks in order like this: 0, 1, 10, 100... - chunks.sort(function(a, b) { - var aKey = _getSortKey(a), - bKey = _getSortKey(b); - if (aKey < bKey) return -1; - if (aKey > bKey) return 1; - return 0; - }); - } - - function createKeyRanges(keys, count) { - var countPerRange = Math.floor(keys.length / count); - var keyRanges = []; - var minKey, maxKey; - for (var i = 0; i < count; i += 1) { - minKey = keys[countPerRange * i]; - maxKey = keys[countPerRange * (i + 1)]; - if (i === 0) { - // ... < maxKey - keyRanges.push(IDBKeyRange.upperBound(maxKey, true)); - } else if (i === count - 1) { - // >= minKey - keyRanges.push(IDBKeyRange.lowerBound(minKey)); - } else { - // >= minKey && < maxKey - keyRanges.push(IDBKeyRange.bound(minKey, maxKey, false, true)); + function extractCollectionNameFromPlaintextChunkKeyWithoutChunkId(plaintextChunkKeyWithoutChunkId, _names) { + const lastIndexOfChunkKeyName = plaintextChunkKeyWithoutChunkId.lastIndexOf("." + _names.chunk); + if (lastIndexOfChunkKeyName === -1) { + throw new Error("Malformed chunk key without chunk id: " + plaintextChunkKeyWithoutChunkId + ". Could not find chunk term (" + _names.chunk + ")"); + } + return plaintextChunkKeyWithoutChunkId.substring(0, lastIndexOfChunkKeyName); } - } - return keyRanges; - } - - function idbReq(request, onsuccess, onerror) { - request.onsuccess = function (e) { - try { - return onsuccess(e); - } catch (error) { - onerror(error); + function isPlaintextMetadataKey(plaintextMetadataKey, _names) { + return (plaintextMetadataKey.length - plaintextMetadataKey.lastIndexOf("." + _names.metadata) - ("." + _names.metadata).length) === 0; } - }; - request.onerror = onerror; - return request; - } - - return IncrementalIndexedDBAdapter; - })(); + function extractCollectionNameFromPlaintextMetadataKey(plaintextMetadataKey, _names) { + return plaintextMetadataKey.substring(0, plaintextMetadataKey.lastIndexOf("." + _names.metadata)); + } + function extractkeyResolver(store, _names, encryptFn, encryptToStringFn, decryptFn, decryptFromStringFn) { + var isEncriptionNotEnabled = !encryptFn; + if (isEncriptionNotEnabled) { + return new Promise(function (resolve) { + resolve({ + actualLokiKey: _names.lokiKeyName, + isLokiKey: function (plaintextKey) { + return plaintextKey === _names.lokiKeyName; + }, + isMetadataKey: function (plaintextKey) { + return isPlaintextMetadataKey(plaintextKey, _names); + }, + isChunkKey: function (plaintextKey) { + return __awaiter(this, void 0, void 0, function* () { + var plaintextChunkKeyWithoutChunkId = getChunkKeyWithoutChunkId(plaintextKey); + if (!plaintextChunkKeyWithoutChunkId) { + return false; + } + return isPlaintextChunkKeyWithoutChunkId(plaintextChunkKeyWithoutChunkId, _names); + }); + }, + getCollectionNameForMetadataKey: function (plaintextKey) { + return extractCollectionNameFromPlaintextMetadataKey(plaintextKey, _names); + }, + getOrGenerateCiphertextCollectionMetadataKey: function (collectionName) { + return __awaiter(this, void 0, void 0, function* () { + return collectionName + "." + _names.metadata; + }); + }, + getCollectionNameForCiphertextChunkKey: function (key) { + return extractCollectionNameFromPlaintextChunkKey(key, _names); + }, + getOrGenerateCiphertextCollectionChunkKey: function (collectionName, chunkId) { + return __awaiter(this, void 0, void 0, function* () { + return collectionName + "." + _names.chunk + "." + chunkId; + }); + } + }); + }); + } + return new Promise(function (resolve, reject) { + idbReq(store.getAllKeys(), function (e) { + var keys = e.target.result; + (() => __awaiter(this, void 0, void 0, function* () { + var ciphertextLokiKey = null; + var plaintextCollectionNamesToCiphertextChunkKeysWithoutChunkId = { + /* plaintextCollectionName: ciphertextChunkKeyWithoutChunkId */ + }; + var keyResolver = { + ciphertextCollectionMetadataKeys: { + /* collectioName: ciphertextCollectionNameAndMetadataForThisCollection */ + }, + metadataCiphertextToCollectionName: { + /* ciphertextCollectionNameAndMetadataForThisCollection: collectionName */ + }, + chunkCiphertextToCollectionName: { + /* ciphertextCollectionNameAndChunkForThisCollection: collectionName */ + } + }; + if (keys.length === 0) { + // newly created database, we generate lokiKeyName and the others will be generated on-the-fly as needed + ciphertextLokiKey = yield encryptToStringFn(_names.lokiKeyName); + } + else { + for (var i = 0; i < keys.length; i++) { + const key = keys[i]; + if (yield isCiphertextChunkKey(key, _names, decryptFn, decryptFromStringFn)) { + var ciphertextChunkKeyWithoutChunkId = getChunkKeyWithoutChunkId(key); + if (!ciphertextChunkKeyWithoutChunkId) { + throw Error("Could not extract collection name from ciphertext chunk key: " + key + ". It did not match the [ciphertext].[chunkId] pattern."); + } + const plaintextCollectionName = extractCollectionNameFromPlaintextChunkKeyWithoutChunkId(yield decryptFromStringFn(ciphertextChunkKeyWithoutChunkId), _names); + plaintextCollectionNamesToCiphertextChunkKeysWithoutChunkId[plaintextCollectionName] = ciphertextChunkKeyWithoutChunkId; + keyResolver.chunkCiphertextToCollectionName[ciphertextChunkKeyWithoutChunkId] = plaintextCollectionName; + } + else { + var plaintextKey = yield decryptFromStringFn(key); + if (plaintextKey === _names.lokiKeyName) { + ciphertextLokiKey = key; + } + else if (isPlaintextMetadataKey(plaintextKey, _names)) { + var collectionName = extractCollectionNameFromPlaintextMetadataKey(plaintextKey, _names); + keyResolver.ciphertextCollectionMetadataKeys[collectionName] = key; + keyResolver.metadataCiphertextToCollectionName[key] = collectionName; + } + else { + // todo maybe just warn + throw Error('Error while loading keys from IDB: Unknown or malformed key (not chunk, loki or meta): ' + key + ' - Plaintext: ' + plaintextKey); + } + } + } + } + if (ciphertextLokiKey) { + resolve({ + actualLokiKey: ciphertextLokiKey, + metadataCiphertextToCollectionName: keyResolver.metadataCiphertextToCollectionName, + isLokiKey: function (ciphertextKey) { + return ciphertextKey === ciphertextLokiKey; + }, + isMetadataKey: function (ciphertextKey) { + return !!keyResolver.metadataCiphertextToCollectionName[ciphertextKey]; + }, + isChunkKey: function (ciphertextKey) { + return __awaiter(this, void 0, void 0, function* () { + return yield isCiphertextChunkKey(ciphertextKey, _names, decryptFn, decryptFromStringFn); + }); + }, + getCollectionNameForMetadataKey: function (ciphertextKey) { + return keyResolver.metadataCiphertextToCollectionName[ciphertextKey]; + }, + getOrGenerateCiphertextCollectionMetadataKey: function (collectionName) { + return __awaiter(this, void 0, void 0, function* () { + if (!keyResolver.ciphertextCollectionMetadataKeys[collectionName]) { + const metadataCiphertext = yield encryptToStringFn(collectionName + "." + _names.metadata); + keyResolver.ciphertextCollectionMetadataKeys[collectionName] = metadataCiphertext; + keyResolver.metadataCiphertextToCollectionName[metadataCiphertext] = collectionName; + } + return keyResolver.ciphertextCollectionMetadataKeys[collectionName]; + }); + }, + getCollectionNameForCiphertextChunkKey: function (key) { + var keyWithoutChunkId = getChunkKeyWithoutChunkId(key); + return keyResolver.chunkCiphertextToCollectionName[keyWithoutChunkId]; + }, + getOrGenerateCiphertextCollectionChunkKey: function (collectionName, chunkId) { + return __awaiter(this, void 0, void 0, function* () { + if (!plaintextCollectionNamesToCiphertextChunkKeysWithoutChunkId[collectionName]) { + const ciphertextCollectionNameAndChunk = yield encryptToStringFn(collectionName + "." + _names.chunk); + plaintextCollectionNamesToCiphertextChunkKeysWithoutChunkId[collectionName] = ciphertextCollectionNameAndChunk; + keyResolver.chunkCiphertextToCollectionName[ciphertextCollectionNameAndChunk] = collectionName; + } + return plaintextCollectionNamesToCiphertextChunkKeysWithoutChunkId[collectionName] + "." + chunkId; + }); + } + }); + } + else { + reject({ message: "Failed to resolve keyResolver. DB was not empty, a loki key with name '" + _names.lokiKeyName + "' is expected but was not found." }); + } + }))(); + }, function (e) { + reject({ message: "Error on IDB getAllKeys request", e }); + }); + }); + } + return IncrementalIndexedDBAdapter; + })(); }); diff --git a/src/incremental-indexeddb-adapter.ts b/src/incremental-indexeddb-adapter.ts new file mode 100644 index 00000000..404616b7 --- /dev/null +++ b/src/incremental-indexeddb-adapter.ts @@ -0,0 +1,1249 @@ +// note: initial authors don't like Typescript but just don't tell them, shhh. Thing is that it +// seems like there is very little or close to no activity on upstream repositories which is why +// I don't really expect this to be merged and is one of the reason for deciding for it. This is +// far from being pretty or good but I wanted to make minimum change as much as possible. As a +// consequence this might not be the smallest script or optimized so keep that in mind if using. + +declare var define: any; +declare var exports: any; +declare var module: any; + +(function (root, factory) { + + if (typeof define === "function" && define.amd) { + // AMD + define([], factory); + } else if (typeof exports === "object") { + // CommonJS + module.exports = factory(); + } else { + // Browser globals + (root as any).IncrementalIndexedDBAdapter = factory(); + } +})(this, function () { + return (function () { + "use strict"; + + /* jshint -W030 */ + var DEBUG = typeof window !== 'undefined' && !!(window as any).__loki_incremental_idb_debug; + + /** + * An improved Loki persistence adapter for IndexedDB (not compatible with LokiIndexedAdapter) + * Unlike LokiIndexedAdapter, the database is saved not as one big JSON blob, but split into + * small chunks with individual collection documents. When saving, only the chunks with changed + * documents (and database metadata) is saved to IndexedDB. This speeds up small incremental + * saves by an order of magnitude on large (tens of thousands of records) databases. It also + * avoids Safari 13 bug that would cause the database to balloon in size to gigabytes + * + * The `appname` argument is not provided - to distinguish between multiple app on the same + * domain, simply use a different Loki database name + * + * @example + * var adapter = new IncrementalIndexedDBAdapter(); + * + * @constructor IncrementalIndexedDBAdapter + * + * @param {object=} options Configuration options for the adapter + * @param {function} options.onversionchange Function to call on `IDBDatabase.onversionchange` event + * (most likely database deleted from another browser tab) + * @param {function} options.onFetchStart Function to call once IDB load has begun. + * Use this as an opportunity to execute code concurrently while IDB does work on a separate thread + * @param {function} options.onDidOverwrite Called when this adapter is forced to overwrite contents + * of IndexedDB. This happens if there's another open tab of the same app that's making changes. + * You might use it as an opportunity to alert user to the potential loss of data + * @param {function} options.serializeChunk Called with a chunk (array of Loki documents) before + * it's saved to IndexedDB. You can use it to manually compress on-disk representation + * for faster database loads. Hint: Hand-written conversion of objects to arrays is very + * profitable for performance. If you use this, you must also pass options.deserializeChunk. + * @param {function} options.deserializeChunk Called with a chunk serialized with options.serializeChunk + * Expects an array of Loki documents as the return value + * @param {number} options.megachunkCount Number of parallel requests for data when loading database. + * Can be tuned for a specific application + * @param {function} options.encrypt Called on each collection name or chunk string (after serialization), + * before saving into IDB. + * @param {function} options.decrypt Called on each collecion name or chunk string after retrieval from IDB. + */ + function IncrementalIndexedDBAdapter(options) { + const that = this; + + this.mode = "incremental"; + this.options = options || {}; + this.chunkSize = 100; + this.megachunkCount = this.options.megachunkCount || 20; + + this.idb = null; // will be lazily loaded on first operation that needs it + this.idbActualLokiObjectStoreName = null; // will be lazily loaded, same as .idb + this.keyResolver = null; // will be lazily loaded, same as .idb + + this._prevLokiVersionId = null; + this._prevCollectionVersionIds = {}; + + var shouldSetupEncryption = !!this.options.encrypt; + if (shouldSetupEncryption) { + if (shouldSetupEncryption && !this.options.decrypt) { + throw Error('encrypt was provided, but decrypt was not. You must pass both functions.'); + } + if (shouldSetupEncryption && !isFunction(this.options.encrypt)) { + throw Error('encrypt was provided, but it is not an async function!'); + } + if (shouldSetupEncryption && !isFunction(this.options.decrypt)) { + throw Error('decrypt was provided, but it is not an async function!'); + } + this.encrypt = makeExternalFunctionSafe(this.options.encrypt, function (a) { return 'Error while invoking encrypt function. Supplied args: ' + a; }); + this.decrypt = makeExternalFunctionSafe( + this.options.decrypt, + function (a) { return 'Error while invoking decrypt function. Is the data really encrypted? Supplied args: ' + a; } + ); + // not perfect and could cause problems + this.encrypt('test').then(result => { + that.encryptOutputsString = (typeof result === 'string'); + }); + + this._names = { + objectStoreName: "LID", + lokiKeyName: "lk_____________", // some padding to give it roughly the same length as .ck., so that is is indistinguishable + chunk: "ck", + metadata: "md___" // padding for the same reason as lokiKeyName + }; + + } else { + this.encrypt = doNothing; + this.decrypt = doNothing; + this.encrypt('test').then(result => { + that.encryptOutputsString = (typeof result === 'string'); + }); + this._names = { + objectStoreName: "LokiIncrementalData", + lokiKeyName: "loki", + chunk: "chunk", + metadata: "metadata" + }; + } + + if (!(this.megachunkCount >= 4 && this.megachunkCount % 2 === 0)) { + throw new Error('megachunkCount must be >=4 and divisible by 2'); + } + } + + // chunkId - index of the data chunk - e.g. chunk 0 will be lokiIds 0-99 + IncrementalIndexedDBAdapter.prototype._getChunk = function (collection, chunkId) { + // 0-99, 100-199, etc. + var minId = chunkId * this.chunkSize; + var maxId = minId + this.chunkSize - 1; + + // use idIndex to find first collection.data position within the $loki range + collection.ensureId(); + var idIndex = collection.idIndex; + + var firstDataPosition: number | null = null; + + var max = idIndex.length - 1, + min = 0, + mid; + + while (idIndex[min] < idIndex[max]) { + mid = (min + max) >> 1; + + if (idIndex[mid] < minId) { + min = mid + 1; + } else { + max = mid; + } + } + + if (max === min && idIndex[min] >= minId && idIndex[min] <= maxId) { + firstDataPosition = min; + } + + if (firstDataPosition === null) { + // no elements in this chunk + return []; + } + + // find last position + // if loki IDs are contiguous (no removed elements), last position will be first + chunk - 1 + // (and we look back in case there are missing pieces) + // TODO: Binary search (not as important as first position, worst case scanario is only chunkSize steps) + var lastDataPosition: number | null = null; + for (var i = firstDataPosition + this.chunkSize - 1; i >= firstDataPosition; i--) { + if (idIndex[i] <= maxId) { + lastDataPosition = i; + break; + } + } + + // verify + var firstElement = collection.data[firstDataPosition]; + if (!(firstElement && firstElement.$loki >= minId && firstElement.$loki <= maxId)) { + throw new Error("broken invariant firstelement"); + } + + if (lastDataPosition === null) { + throw new Error("Unexpected lastDataPosition"); + } + + var lastElement = collection.data[lastDataPosition]; + if (!(lastElement && lastElement.$loki >= minId && lastElement.$loki <= maxId)) { + throw new Error("broken invariant lastElement"); + } + + // this will have *up to* 'this.chunkSize' elements (might have less, because $loki ids + // will have holes when data is deleted) + var chunkData = collection.data.slice(firstDataPosition, lastDataPosition + 1); + + if (chunkData.length > this.chunkSize) { + throw new Error("broken invariant - chunk size"); + } + + return chunkData; + }; + + /** + * Incrementally saves the database to IndexedDB + * + * @example + * var idbAdapter = new IncrementalIndexedDBAdapter(); + * var db = new loki('test', { adapter: idbAdapter }); + * var coll = db.addCollection('testColl'); + * coll.insert({test: 'val'}); + * db.saveDatabase(); + * + * @param {string} dbname - the name to give the serialized database + * @param {function} getLokiCopy - returns copy of the Loki database + * @param {function} callback - (Optional) callback passed obj.success with true or false + * @memberof IncrementalIndexedDBAdapter + */ + IncrementalIndexedDBAdapter.prototype.saveDatabase = async function (dbname, getLokiCopy, callback) { + var that = this; + + if (!this.idb) { + this._initializeIDB(dbname, callback, function () { + that.saveDatabase(dbname, getLokiCopy, callback); + }); + return; + } + + if (this.operationInProgress) { + throw new Error("Error while saving to database - another operation is already in progress. Please use throttledSaves=true option on Loki object"); + } + this.operationInProgress = true; + + DEBUG && console.log("saveDatabase - begin"); + DEBUG && console.time("saveDatabase"); + function finish(e) { + DEBUG && e && console.error(e); + DEBUG && console.timeEnd("saveDatabase"); + that.operationInProgress = false; + callback(e); + } + + // try..catch is required, e.g.: + // InvalidStateError: Failed to execute 'transaction' on 'IDBDatabase': The database connection is closing. + // (this may happen if another tab has called deleteDatabase) + try { + var updatePrevVersionIds = function () { + console.error('Unexpected successful tx - cannot update previous version ids'); + }; + + const initialLokiVersionId = await that.getLokiVersionId() + // note that initialPureLokiObject can be encrypted + const initialPureLokiObject: any = await idbRequestResult(that.getPureLokiObjectRequest()) + + + var didOverwrite = false; + + let maxChunkIds = undefined + if (initialLokiVersionId !== that._prevLokiVersionId) { + DEBUG && console.warn('Another writer changed Loki IDB, using slow path...'); + didOverwrite = true; + + // Incrementally saving changed chunks breaks down if there is more than one writer to IDB + // (multiple tabs of the same web app), leading to data corruption. To fix that, we save all + // metadata chunks (loki + collections) with a unique ID on each save and remember it. Before + // the subsequent save, we read loki from IDB to check if its version ID changed. If not, we're + // guaranteed that persisted DB is consistent with our diff. Otherwise, we fall back to the slow + // path and overwrite *all* database chunks with our version. Both reading and writing must + // happen in the same IDB transaction for this to work. + // TODO: We can optimize the slow path by fetching collection metadata chunks and comparing their + // version IDs with those last seen by us. Since any change in collection data requires a metadata + // chunk save, we're guaranteed that if the IDs match, we don't need to overwrite chukns of this collection + + // NOTE: We must fetch all keys to protect against a case where another tab has wrote more + // chunks whan we did -- if so, we must delete them. + const tx = this.idb.transaction([this.idbActualLokiObjectStoreName], "readwrite"); + var store = tx.objectStore(this.idbActualLokiObjectStoreName); + const allKeys = await idbRequestResult(store.getAllKeys()) + + maxChunkIds = await getMaxChunkIds(allKeys, that.keyResolver); + } + + const incremental = !maxChunkIds; + + const chunkInfo = await that._getLokiChanges(getLokiCopy(), incremental, maxChunkIds); + + var tx = that.idb.transaction([that.idbActualLokiObjectStoreName], "readwrite"); + tx.oncomplete = function () { + updatePrevVersionIds(); + finish(undefined); + if (didOverwrite && that.options.onDidOverwrite) { + that.options.onDidOverwrite(); + } + }; + + tx.onerror = function (e) { + finish(e); + }; + + tx.onabort = function (e) { + finish(e); + }; + + var store = tx.objectStore(that.idbActualLokiObjectStoreName); + + // we recheck if there was version change + try { + idbReq(that.getPureLokiObjectRequest(tx), function(e) { + const latestPureLokiObject = e.target.result; + // we compare loki object and expect that version changed if it doesn't match. Reason for this is + // that to get version itself we would potentially be required to decrypt which in turn can be async. + // This can cause transaction to stop which would prevent all of this from working. + const lokiObjectsMatch = (latestPureLokiObject === undefined && initialPureLokiObject === undefined) + || (that.encryptOutputsString && latestPureLokiObject?.value === initialPureLokiObject?.value) + || (!that.encryptOutputsString && arrayBuffersEqual(latestPureLokiObject?.value, initialPureLokiObject?.value)) + if (lokiObjectsMatch) { + that._applyDBChanges(store, chunkInfo.dbChanges); + + // Update last seen version IDs, but only after the transaction is successful + updatePrevVersionIds = function () { + that._prevLokiVersionId = chunkInfo.lokiVersionId; + chunkInfo.collectionVersionIds.forEach(function (collectionInfo) { + that._prevCollectionVersionIds[collectionInfo.name] = collectionInfo.versionId; + }); + }; + tx.commit && tx.commit(); + } else { + // something saved in between while we were preparing data (maybe multiple tabs?). + tx.abort(); + } + }, function(error) { + tx.abort(); + finish(error); + }) + } catch(error) { + tx.abort(); + finish(error); + } + } catch (error) { + finish(error); + } + }; + + // gets current largest chunk ID for each collection + async function getMaxChunkIds(allCiphertextKeys, keyResolver) { + const maxChunkIds = {}; + for(let ciphertextKey of allCiphertextKeys) { + // table.chunk.2317 + if (await keyResolver.isChunkKey(ciphertextKey)) { + var collection = keyResolver.getCollectionNameForCiphertextChunkKey(ciphertextKey); + var chunkId = extractChunkIdFromChunkKey(ciphertextKey) || 0; + var currentMax = maxChunkIds[collection]; + + if (!currentMax || chunkId > currentMax) { + maxChunkIds[collection] = chunkId; + } + } + } + return maxChunkIds; + } + + IncrementalIndexedDBAdapter.prototype.getPureLokiObjectRequest = function(tx=undefined) { + if (!tx) { + tx = this.idb.transaction([this.idbActualLokiObjectStoreName], "readwrite"); + } + var store = tx.objectStore(this.idbActualLokiObjectStoreName); + return store.get(this.keyResolver.actualLokiKey) + } + + IncrementalIndexedDBAdapter.prototype.getLokiVersionId = async function(tx=undefined) { + if (!tx) { + tx = this.idb.transaction([this.idbActualLokiObjectStoreName], "readwrite"); + } + + var store = tx.objectStore(this.idbActualLokiObjectStoreName); + + const chunk = await idbRequestResult(store.get(this.keyResolver.actualLokiKey)) + + return await lokiChunkVersionId(chunk, this.decrypt); + } + + async function lokiChunkVersionId(chunk, decryptFn) { + try { + if (chunk) { + var loki = JSON.parse(await decryptFn(chunk.value)); + return loki.idbVersionId || null; + } else { + return null; + } + } catch (e) { + console.error('Error while parsing loki chunk', e); + return null; + } + } + + IncrementalIndexedDBAdapter.prototype._getLokiChanges = async function (loki, incremental, maxChunkIds) { + var that = this; + var collectionVersionIds: { name: any, versionId: any; }[] = []; + var savedSize = 0; + + var prepareCollection = async function (collection, i) { + // Find dirty chunk ids + var dirtyChunks = new Set(); + incremental && collection.dirtyIds.forEach(function (lokiId) { + var chunkId = (lokiId / that.chunkSize) | 0; + dirtyChunks.add(chunkId); + }); + collection.dirtyIds = []; + + const putChunks = [] + const deleteChunkNames = [] + + // Serialize chunks to save + var prepareChunk = async function (chunkId) { + var chunkData = that._getChunk(collection, chunkId); + if (that.options.serializeChunk) { + chunkData = that.options.serializeChunk(collection.name, chunkData); + } + // we must stringify now, because IDB is asynchronous, and underlying objects are mutable + // In general, it's also faster to stringify, because we need serialization anyway, and + // JSON.stringify is much better optimized than IDB's structured clone + chunkData = await that.encrypt(JSON.stringify(chunkData)); + savedSize += that.encryptOutputsString ? chunkData.length : chunkData.byteLength; + DEBUG && incremental && console.log('Saving: ' + collection.name + ".chunk." + chunkId); + try { + putChunks.push({ + key: await that.keyResolver.getOrGenerateCiphertextCollectionChunkKey(collection.name, chunkId), + value: chunkData, + }) + } catch(e) { + console.error(e) + } + }; + if (incremental) { + for(let dirtyChunk of dirtyChunks) { + await prepareChunk(dirtyChunk); + } + } else { + // add all chunks + var maxChunkId = (collection.maxId / that.chunkSize) | 0; + for (var j = 0; j <= maxChunkId; j += 1) { + await prepareChunk(j); + } + + // delete chunks with larger ids than what we have + // NOTE: we don't have to delete metadata chunks as they will be absent from loki anyway + // NOTE: failures are silently ignored, so we don't have to worry about holes + var persistedMaxChunkId = maxChunkIds[collection.name] || 0; + for (var k = maxChunkId + 1; k <= persistedMaxChunkId; k += 1) { + var deletedChunkName = await that.keyResolver.getOrGenerateCiphertextCollectionChunkKey(collection.name, k); + deleteChunkNames.push(deletedChunkName); + DEBUG && console.warn('Deleted chunk: ' + deletedChunkName); + } + } + + // save collection metadata as separate chunk (but only if changed) + if (collection.dirty || dirtyChunks.size || !incremental) { + collection.idIndex = []; // this is recreated lazily + collection.data = []; + collection.idbVersionId = randomVersionId(); + collectionVersionIds.push({ name: collection.name, versionId: collection.idbVersionId }); + + var metadataChunk = await that.encrypt(JSON.stringify(collection)); + savedSize += that.encryptOutputsString ? metadataChunk.length : metadataChunk.byteLength; + DEBUG && incremental && console.log('Saving: ' + collection.name + ".metadata"); + putChunks.push({ + key: await that.keyResolver.getOrGenerateCiphertextCollectionMetadataKey(collection.name), + value: metadataChunk, + }) + } + + // leave only names in the loki chunk + loki.collections[i] = { name: collection.name }; + return { putChunks, deleteChunkNames } + }; + const collectionsChanges = await Promise.all(loki.collections.map((collection, index) => prepareCollection(collection, index))) + loki.idbVersionId = randomVersionId(); + var serializedMetadata = await that.encrypt(JSON.stringify(loki)); + savedSize += that.encryptOutputsString ? serializedMetadata.length : serializedMetadata.byteLength; + + DEBUG && incremental && console.log('Saving: loki'); + const lokiChunk = { key: that.keyResolver.actualLokiKey, value: serializedMetadata } + + DEBUG && console.log("expected saved size: " + savedSize); + return { + lokiVersionId: loki.idbVersionId, + collectionVersionIds: collectionVersionIds, + dbChanges: { + collectionsChanges: collectionsChanges, + lokiChunk, + }, + }; + }; + + IncrementalIndexedDBAdapter.prototype._applyDBChanges = async function (idbStore, dbChanges) { + dbChanges.collectionsChanges.forEach(collectionChanges => { + collectionChanges.putChunks.forEach(putChunk => { + idbStore.put(putChunk) + }); + + collectionChanges.deleteChunkNames.forEach(deleteChunkName => { + idbStore.delete(deleteChunkName) + DEBUG && console.warn('Deleted chunk: ' + deleteChunkName); + }); + }) + + idbStore.put(dbChanges.lokiChunk); + } + + /** + * Retrieves a serialized db string from the catalog. + * + * @example + * // LOAD + * var idbAdapter = new IncrementalIndexedDBAdapter(); + * var db = new loki('test', { adapter: idbAdapter }); + * db.loadDatabase(function(result) { + * console.log('done'); + * }); + * + * @param {string} dbname - the name of the database to retrieve. + * @param {function} callback - callback should accept string param containing serialized db string. + * @memberof IncrementalIndexedDBAdapter + */ + IncrementalIndexedDBAdapter.prototype.loadDatabase = async function (dbname, callback) { + var that = this; + + if (this.operationInProgress) { + throw new Error("Error while loading database - another operation is already in progress. Please use throttledSaves=true option on Loki object"); + } + + this.operationInProgress = true; + + DEBUG && console.log("loadDatabase - begin"); + DEBUG && console.time("loadDatabase"); + + var finish = function (value) { + DEBUG && console.timeEnd("loadDatabase"); + that.operationInProgress = false; + callback(value); + }; + + await this._getAllChunks(dbname, async function (chunks) { + try { + if (!Array.isArray(chunks)) { + throw chunks; // we have an error + } + + if (!chunks.length) { + return finish(null); + } + + DEBUG && console.log("Found chunks:", chunks.length); + + // repack chunks into a map + chunks = await chunksToMap(chunks, that.keyResolver); + var loki = chunks.loki; + chunks.loki = null; // gc + + // populate collections with data + populateLoki(loki, chunks.chunkMap); + chunks = null; // gc + + // remember previous version IDs + that._prevLokiVersionId = loki.idbVersionId || null; + that._prevCollectionVersionIds = {}; + loki.collections.forEach(function (collection) { + that._prevCollectionVersionIds[collection.name] = collection.idbVersionId || null; + }); + + return finish(loki); + } catch (error) { + that._prevLokiVersionId = null; + that._prevCollectionVersionIds = {}; + return finish(error); + } + }); + }; + + async function chunksToMap(chunks, keyResolver) { + var loki; + var chunkMap = {}; + await sortChunksInPlace(chunks, keyResolver); + for(let object of chunks){ + var key = (object as any).key; + var value = (object as any).value; + if (keyResolver.isLokiKey(key)) { + loki = value; + continue; + } else { + if (await keyResolver.isChunkKey(key)) { + var colName = keyResolver.getCollectionNameForCiphertextChunkKey(key); + if (chunkMap[colName]) { + chunkMap[colName].dataChunks.push(value); + } else { + chunkMap[colName] = { + metadata: null, + dataChunks: [value], + }; + } + continue; + } + if (keyResolver.isMetadataKey(key)) { + var name = keyResolver.getCollectionNameForMetadataKey(key); + if (chunkMap[name]) { + chunkMap[name].metadata = value; + } else { + chunkMap[name] = { metadata: value, dataChunks: [] }; + } + continue; + } + } + + console.error("Unknown chunk " + key); + throw new Error("Corrupted database - unknown chunk found"); + }; + + if (!loki) { + throw new Error("Corrupted database - missing database metadata"); + } + + return { loki: loki, chunkMap: chunkMap }; + } + + function populateLoki(loki, chunkMap) { + loki.collections.forEach(function populateCollection(collectionStub, i) { + var chunkCollection = chunkMap[collectionStub.name]; + if (chunkCollection) { + if (!chunkCollection.metadata) { + throw new Error("Corrupted database - missing metadata chunk for " + collectionStub.name); + } + var collection = chunkCollection.metadata; + chunkCollection.metadata = null; + + loki.collections[i] = collection; + var dataChunks = chunkCollection.dataChunks; + dataChunks.forEach(function populateChunk(chunk, i) { + chunk.forEach(function (doc) { + collection.data.push(doc); + }); + dataChunks[i] = null; + }); + } + }); + } + + IncrementalIndexedDBAdapter.prototype._initializeIDB = async function (dbname, onError, onSuccess) { + var that = this; + DEBUG && console.log("initializing idb"); + + if (this.idbInitInProgress) { + throw new Error("Cannot open IndexedDB because open is already in progress"); + } + this.idbInitInProgress = true; + + const encryptedObjectStoreName = await that._encryptToString(that._names.objectStoreName); + + var openRequest = indexedDB.open(dbname, 1); + + openRequest.onupgradeneeded = function (e) { + var db = (e.target as any).result; + DEBUG && console.log('onupgradeneeded, old version: ' + e.oldVersion); + if (e.oldVersion < 1) { + // Version 1 - Initial - Create database + db.createObjectStore(encryptedObjectStoreName, { keyPath: "key" }); + } else { + // Unknown version + throw new Error("Invalid old version " + e.oldVersion + " for IndexedDB upgrade"); + } + }; + + openRequest.onsuccess = function (e) { + that.idbInitInProgress = false; + var db = (e.target as any).result; + const objectStoreNames = db.objectStoreNames; + that.idb = db; + + (async() => { + const idbActualLokiObjectStoreName = await findIdbActualLokiObjectStoreName(objectStoreNames, that._names.objectStoreName, that._decryptFromString.bind(that)) + that.idbActualLokiObjectStoreName = idbActualLokiObjectStoreName; + + if (!that.idbActualLokiObjectStoreName) { + onError(new Error("Missing IndexedDB objectStore: " + that._names.objectStoreName + (that.decrypt ? ' (searched using decrypt function)' : ''))); + // Attempt to recover (after reload) by deleting database, since it's damaged anyway + that.deleteDatabase(dbname); + return; + } + + var tx = that.idb.transaction([that.idbActualLokiObjectStoreName], "readonly"); + var store = tx.objectStore(that.idbActualLokiObjectStoreName); + + const keyResolver = await extractkeyResolver(store, that._names, that.encrypt, that._encryptToString.bind(that), + that.decrypt, that._decryptFromString.bind(that)) + + that.keyResolver = keyResolver; + onSuccess(); + })() + + try { + DEBUG && console.log("init success"); + + db.onversionchange = function (versionChangeEvent) { + // Ignore if database was deleted and recreated in the meantime + if (that.idb !== db) { + return; + } + + DEBUG && console.log('IDB version change', versionChangeEvent); + // This function will be called if another connection changed DB version + // (Most likely database was deleted from another browser tab, unless there's a new version + // of this adapter, or someone makes a connection to IDB outside of this adapter) + // We must close the database to avoid blocking concurrent deletes. + // The database will be unusable after this. Be sure to supply `onversionchange` option + // to force logout + that.idb.close(); + that.idb = null; + if (that.options.onversionchange) { + that.options.onversionchange(versionChangeEvent); + } + }; + + } catch(e) { + console.error("Error while retrieving actual IDB lokiKeyName", e); + throw e; + }; + }; + + openRequest.onblocked = function (e) { + console.error("IndexedDB open is blocked", e); + onError(new Error("IndexedDB open is blocked by open connection")); + }; + + openRequest.onerror = function (e) { + that.idbInitInProgress = false; + console.error("IndexedDB open error", e); + onError(e); + }; + }; + + IncrementalIndexedDBAdapter.prototype._getAllChunks = async function (dbname, callback) { + var that = this; + if (!this.idb) { + this._initializeIDB(dbname, callback, function () { + that._getAllChunks(dbname, callback); + }); + return; + } + + var tx = this.idb.transaction([that.idbActualLokiObjectStoreName], "readonly"); + var store = tx.objectStore(that.idbActualLokiObjectStoreName); + + // If there are a lot of chunks (>100), don't request them all in one go, but in multiple + // "megachunks" (chunks of chunks). This improves concurrency, as main thread is already busy + // while IDB process is still fetching data. Details: https://github.com/techfort/LokiJS/pull/874 + async function getMegachunks(keys) { + var megachunkCount = that.megachunkCount; + var keyRanges = createKeyRanges(keys, megachunkCount); + + var allChunks: any[] = []; + var megachunksReceived = 0; + + async function processMegachunk(megachunk, megachunkIndex, keyRange) { + // var debugMsg = 'processing chunk ' + megachunkIndex + ' (' + keyRange.lower + ' -- ' + keyRange.upper + ')' + // DEBUG && console.time(debugMsg); + + for(let i=0; i { + await Promise.all(allChunks.map(async function (chunk) { + await parseChunk(chunk, that.deserializeChunk, that.keyResolver, that.decrypt, that._decryptFromString.bind(that)); + })); + callback(allChunks); + })() + }, function (e) { + callback(e); + }); + } + + function getAllKeys() { + idbReq(store.getAllKeys(), function (e) { + const keys = e.target.result; + if (keys.length > 100) { + // it is okay if this is sorted as 0, 1, 10, 100 and not 0, 1, 2... + var sortedKeys = keys.sort(); + getMegachunks(sortedKeys); + } else { + getAllChunks(); + } + }, function (e) { + callback(e); + }); + + if (that.options.onFetchStart) { + that.options.onFetchStart(); + } + } + + getAllKeys(); + }; + + async function parseChunk(chunk, deserializeChunk, keyResolver, decryptFn: (value) => Promise, decryptFromStringFn: (value) => Promise) { + if (typeof chunk.value === 'string') { + chunk.value = JSON.parse(await decryptFromStringFn(chunk.value)); + } else { + chunk.value = JSON.parse(await decryptFn(chunk.value)); + } + + if (deserializeChunk) { + if (await keyResolver.isChunkKey(chunk.key)) { + var collectionName = keyResolver.getCollectionNameForCiphertextChunkKey(chunk.key); + chunk.value = deserializeChunk(collectionName, chunk.value); + } + } + } + + /** + * Deletes a database from IndexedDB + * + * @example + * // DELETE DATABASE + * // delete 'finance'/'test' value from catalog + * idbAdapter.deleteDatabase('test', function { + * // database deleted + * }); + * + * @param {string} dbname - the name of the database to delete from IDB + * @param {function=} callback - (Optional) executed on database delete + * @memberof IncrementalIndexedDBAdapter + */ + IncrementalIndexedDBAdapter.prototype.deleteDatabase = function (dbname, callback) { + if (this.operationInProgress) { + throw new Error("Error while deleting database - another operation is already in progress. Please use throttledSaves=true option on Loki object"); + } + + this.operationInProgress = true; + + var that = this; + DEBUG && console.log("deleteDatabase - begin"); + DEBUG && console.time("deleteDatabase"); + + this._prevLokiVersionId = null; + this._prevCollectionVersionIds = {}; + + if (this.idb) { + this.idb.close(); + this.idb = null; + } + + var request = indexedDB.deleteDatabase(dbname); + + request.onsuccess = function () { + that.operationInProgress = false; + DEBUG && console.timeEnd("deleteDatabase"); + callback({ success: true }); + }; + + request.onerror = function (e) { + that.operationInProgress = false; + console.error("Error while deleting database", e); + callback({ success: false }); + }; + + request.onblocked = function (e) { + // We can't call callback with failure status, because this will be called even if we + // succeed in just a moment + console.error("Deleting database failed because it's blocked by another connection", e); + }; + }; + + IncrementalIndexedDBAdapter.prototype._encryptToString = async function (s) { + const encrypted = await this.encrypt(s) + if (this.encryptOutputsString) { + // encrypt algo already directly outputs string - not optimal but possible atm + return encrypted; + } + + // trying to avoid spread to prevent max call stack size exceeded. + let binary = ''; + const bytes = new Uint8Array(encrypted); + const len = bytes.byteLength; + for (let i = 0; i < len; i++) { + binary += String.fromCharCode(bytes[i]); + } + + return window.btoa(binary); + } + + IncrementalIndexedDBAdapter.prototype._decryptFromString = async function (s) { + if (this.encryptOutputsString) { + return await this.decrypt(s); + } + const encrypted = Uint8Array.from(atob(s), c => c.charCodeAt(0)); + return await this.decrypt(encrypted) + } + + function randomVersionId() { + // Appears to have enough entropy for chunk version IDs + // (Only has to be different than enough of its own previous versions that there's no writer + // that thinks a new version is the same as an earlier one, not globally unique) + return Math.random().toString(36).substring(2); + } + + async function _getSortKey(object, keyResolver) { + var key = object.key; + if (await keyResolver.isChunkKey(key)) { + return extractChunkIdFromChunkKey(key); + } + + return -1; // consistent type must be returned + } + + async function sortChunksInPlace(chunks, keyResolver) { + // sort chunks in place to load data in the right order (ascending loki ids) + // on both Safari and Chrome, we'll get chunks in order like this: 0, 1, 10, 100... + + // we get sort keys in advance to prevent potentially decrypting multiple times + const mapped = new Map(await Promise.all(chunks.map(async item => { + const sortKey = await _getSortKey(item, keyResolver); + return [item.key, sortKey]; + }))); + + chunks.sort(function (a, b) { + const aKey = mapped.get(a.key), + bKey = mapped.get(b.key); + if (!bKey) return 1; + if (!aKey) return -1; + if (aKey < bKey) return -1; + if (aKey > bKey) return 1; + return 0; + }); + } + + function createKeyRanges(keys, count) { + var countPerRange = Math.floor(keys.length / count); + var keyRanges: any[] = []; + var minKey, maxKey; + for (var i = 0; i < count; i += 1) { + minKey = keys[countPerRange * i]; + maxKey = keys[countPerRange * (i + 1)]; + if (i === 0) { + // ... < maxKey + keyRanges.push(IDBKeyRange.upperBound(maxKey, true)); + } else if (i === count - 1) { + // >= minKey + keyRanges.push(IDBKeyRange.lowerBound(minKey)); + } else { + // >= minKey && < maxKey + keyRanges.push(IDBKeyRange.bound(minKey, maxKey, false, true)); + } + } + return keyRanges; + } + + function idbReq(request, onsuccess, onerror) { + request.onsuccess = function (e) { + try { + return onsuccess(e); + } catch (error) { + onerror(error); + } + }; + request.onerror = onerror; + return request; + } + + function idbRequestResult(request) { + return new Promise((resolve, reject) => { + request.onsuccess = function(e) { + resolve(e.target.result); + } + request.onerror = function(e) { + reject(e); + } + }) + } + + async function findIdbActualLokiObjectStoreName(objectStoreNames, decryptedObjectStoreName, decryptFromStringFn) { + var domStringList = objectStoreNames; + for (var i = 0; i < domStringList.length; i++) { + if (await decryptFromStringFn(domStringList[i]) === decryptedObjectStoreName) { + return domStringList[i]; + } + } + return null; + } + + function isFunction(fn) { + return typeof fn === 'function'; + } + + function arrayBuffersEqual(buffer1, buffer2) { + if (buffer1?.byteLength !== buffer2?.byteLength) { + return false; + } + + const view1 = new Uint8Array(buffer1); + const view2 = new Uint8Array(buffer2); + + for (let i = 0; i < view1.length; i++) { + if (view1[i] !== view2[i]) { + return false; + } + } + + return true; + } + + async function doNothing(x): Promise { return x; } + + function makeExternalFunctionSafe(fn, erroMessageGenerator) { + return function () { + try { + return fn.apply(this, arguments); + } catch (e) { + console.error(erroMessageGenerator(arguments), e); + throw e; + } + }; + } + + function getChunkKeyWithoutChunkId(key) { + var matchKeyWithoutChunkId = key.match(/^(.+)\.\d+$/); + if (matchKeyWithoutChunkId === null) { + return null; + } + return matchKeyWithoutChunkId[1]; + } + + function extractChunkIdFromChunkKey(key) { + var chunkId = key.match(/^.+\.(\d+)$/); + if (chunkId === null) { + return null; + } + return parseInt(chunkId[1], 10); + } + + async function isCiphertextChunkKey(ciphertextChunkKey, _names, decryptFn, decryptFromStringFn) { + if (typeof ciphertextChunkKey !== 'string') { + return false; + } + var ciphertextChunkKeyWithoutChunkId = getChunkKeyWithoutChunkId(ciphertextChunkKey); + if (!ciphertextChunkKeyWithoutChunkId) { + return false; + } + var plaintextChunkKeyWithoutChunkId = await decryptFromStringFn(ciphertextChunkKeyWithoutChunkId); + return isPlaintextChunkKeyWithoutChunkId(plaintextChunkKeyWithoutChunkId, _names); + } + + function isPlaintextChunkKeyWithoutChunkId(plaintextChunkKeyWithoutChunkId, _names) { + return (plaintextChunkKeyWithoutChunkId.length - plaintextChunkKeyWithoutChunkId.lastIndexOf("." + _names.chunk) - ("." + _names.chunk).length) === 0; + } + + function extractCollectionNameFromPlaintextChunkKey(plaintextChunkKey, _names) { + var plaintextChunkKeyWithoutChunkId = getChunkKeyWithoutChunkId(plaintextChunkKey); + if (!plaintextChunkKeyWithoutChunkId === null) { + return null; + } + return extractCollectionNameFromPlaintextChunkKeyWithoutChunkId(plaintextChunkKeyWithoutChunkId, _names); + } + + function extractCollectionNameFromPlaintextChunkKeyWithoutChunkId(plaintextChunkKeyWithoutChunkId, _names) { + const lastIndexOfChunkKeyName = plaintextChunkKeyWithoutChunkId.lastIndexOf("." + _names.chunk); + if (lastIndexOfChunkKeyName === -1) { + throw new Error("Malformed chunk key without chunk id: " + plaintextChunkKeyWithoutChunkId + ". Could not find chunk term (" + _names.chunk + ")"); + } + return plaintextChunkKeyWithoutChunkId.substring(0, lastIndexOfChunkKeyName); + } + + function isPlaintextMetadataKey(plaintextMetadataKey, _names) { + return (plaintextMetadataKey.length - plaintextMetadataKey.lastIndexOf("." + _names.metadata) - ("." + _names.metadata).length) === 0; + } + + function extractCollectionNameFromPlaintextMetadataKey(plaintextMetadataKey, _names) { + return plaintextMetadataKey.substring(0, plaintextMetadataKey.lastIndexOf("." + _names.metadata)); + } + + function extractkeyResolver(store, _names, encryptFn, encryptToStringFn, decryptFn, decryptFromStringFn) { + var isEncriptionNotEnabled = !encryptFn; + + if (isEncriptionNotEnabled) { + return new Promise(function (resolve) { + resolve({ + actualLokiKey: _names.lokiKeyName, + isLokiKey: function (plaintextKey) { + return plaintextKey === _names.lokiKeyName; + }, + isMetadataKey: function (plaintextKey) { + return isPlaintextMetadataKey(plaintextKey, _names); + }, + isChunkKey: async function (plaintextKey) { + var plaintextChunkKeyWithoutChunkId = getChunkKeyWithoutChunkId(plaintextKey); + if (!plaintextChunkKeyWithoutChunkId) { + return false; + } + return isPlaintextChunkKeyWithoutChunkId(plaintextChunkKeyWithoutChunkId, _names); + }, + getCollectionNameForMetadataKey: function (plaintextKey) { + return extractCollectionNameFromPlaintextMetadataKey(plaintextKey, _names); + }, + getOrGenerateCiphertextCollectionMetadataKey: async function (collectionName) { + return collectionName + "." + _names.metadata; + }, + getCollectionNameForCiphertextChunkKey: function (key) { + return extractCollectionNameFromPlaintextChunkKey(key, _names); + }, + getOrGenerateCiphertextCollectionChunkKey: async function (collectionName, chunkId) { + return collectionName + "." + _names.chunk + "." + chunkId; + } + }); + }); + } + + return new Promise(function (resolve, reject) { + idbReq(store.getAllKeys(), function (e) { + var keys = e.target.result; + + (async() => { + var ciphertextLokiKey = null; + var plaintextCollectionNamesToCiphertextChunkKeysWithoutChunkId = { + /* plaintextCollectionName: ciphertextChunkKeyWithoutChunkId */ + }; + var keyResolver = { + ciphertextCollectionMetadataKeys: { + /* collectioName: ciphertextCollectionNameAndMetadataForThisCollection */ + }, + metadataCiphertextToCollectionName: { + /* ciphertextCollectionNameAndMetadataForThisCollection: collectionName */ + }, + + chunkCiphertextToCollectionName: { + /* ciphertextCollectionNameAndChunkForThisCollection: collectionName */ + } + }; + if (keys.length === 0) { + // newly created database, we generate lokiKeyName and the others will be generated on-the-fly as needed + ciphertextLokiKey = await encryptToStringFn(_names.lokiKeyName); + } else { + for (var i = 0; i < keys.length; i++) { + const key = keys[i]; + if (await isCiphertextChunkKey(key, _names, decryptFn, decryptFromStringFn)) { + var ciphertextChunkKeyWithoutChunkId = getChunkKeyWithoutChunkId(key); + if (!ciphertextChunkKeyWithoutChunkId) { + throw Error("Could not extract collection name from ciphertext chunk key: " + key + ". It did not match the [ciphertext].[chunkId] pattern."); + } + const plaintextCollectionName = extractCollectionNameFromPlaintextChunkKeyWithoutChunkId(await decryptFromStringFn(ciphertextChunkKeyWithoutChunkId), _names); + plaintextCollectionNamesToCiphertextChunkKeysWithoutChunkId[plaintextCollectionName] = ciphertextChunkKeyWithoutChunkId; + keyResolver.chunkCiphertextToCollectionName[ciphertextChunkKeyWithoutChunkId] = plaintextCollectionName; + } else { + var plaintextKey = await decryptFromStringFn(key); + if (plaintextKey === _names.lokiKeyName) { + ciphertextLokiKey = key; + } else if (isPlaintextMetadataKey(plaintextKey, _names)) { + var collectionName = extractCollectionNameFromPlaintextMetadataKey(plaintextKey, _names); + keyResolver.ciphertextCollectionMetadataKeys[collectionName] = key; + keyResolver.metadataCiphertextToCollectionName[key] = collectionName; + } else { + // todo maybe just warn + throw Error('Error while loading keys from IDB: Unknown or malformed key (not chunk, loki or meta): ' + key + ' - Plaintext: ' + plaintextKey); + } + } + } + } + if (ciphertextLokiKey) { + resolve({ + actualLokiKey: ciphertextLokiKey, + metadataCiphertextToCollectionName: keyResolver.metadataCiphertextToCollectionName, + isLokiKey: function (ciphertextKey) { + return ciphertextKey === ciphertextLokiKey; + }, + isMetadataKey: function (ciphertextKey) { + return !!keyResolver.metadataCiphertextToCollectionName[ciphertextKey]; + }, + isChunkKey: async function (ciphertextKey) { + return await isCiphertextChunkKey(ciphertextKey, _names, decryptFn, decryptFromStringFn); + }, + getCollectionNameForMetadataKey: function (ciphertextKey) { + return keyResolver.metadataCiphertextToCollectionName[ciphertextKey]; + }, + getOrGenerateCiphertextCollectionMetadataKey: async function (collectionName) { + if (!keyResolver.ciphertextCollectionMetadataKeys[collectionName]) { + const metadataCiphertext = await encryptToStringFn(collectionName + "." + _names.metadata); + keyResolver.ciphertextCollectionMetadataKeys[collectionName] = metadataCiphertext; + keyResolver.metadataCiphertextToCollectionName[metadataCiphertext] = collectionName; + } + return keyResolver.ciphertextCollectionMetadataKeys[collectionName]; + }, + getCollectionNameForCiphertextChunkKey: function (key) { + var keyWithoutChunkId = getChunkKeyWithoutChunkId(key); + return keyResolver.chunkCiphertextToCollectionName[keyWithoutChunkId]; + }, + getOrGenerateCiphertextCollectionChunkKey: async function (collectionName, chunkId) { + if (!plaintextCollectionNamesToCiphertextChunkKeysWithoutChunkId[collectionName]) { + const ciphertextCollectionNameAndChunk = await encryptToStringFn(collectionName + "." + _names.chunk); + plaintextCollectionNamesToCiphertextChunkKeysWithoutChunkId[collectionName] = ciphertextCollectionNameAndChunk; + keyResolver.chunkCiphertextToCollectionName[ciphertextCollectionNameAndChunk] = collectionName; + } + return plaintextCollectionNamesToCiphertextChunkKeysWithoutChunkId[collectionName] + "." + chunkId; + } + }); + } else { + reject({ message: "Failed to resolve keyResolver. DB was not empty, a loki key with name '" + _names.lokiKeyName + "' is expected but was not found." }); + } + })() + }, function (e) { + reject({ message: "Error on IDB getAllKeys request", e }); + }); + }); + } + + return IncrementalIndexedDBAdapter; + })(); +}); \ No newline at end of file diff --git a/test.db b/test.db index 95e90213..f7c70ee7 100644 --- a/test.db +++ b/test.db @@ -1 +1 @@ -{"filename":"test.db","collections":[{"name":"items","data":[{"name":"n1","meta":{"revision":0,"created":1597663752918,"version":0},"$loki":1},{"name":"n2","meta":{"revision":0,"created":1597663752918,"version":0},"$loki":2}],"idIndex":null,"binaryIndices":{},"constraints":null,"uniqueNames":[],"transforms":{},"objType":"items","dirty":false,"cachedIndex":null,"cachedBinaryIndex":null,"cachedData":null,"adaptiveBinaryIndices":true,"transactional":false,"cloneObjects":false,"cloneMethod":"parse-stringify","asyncListeners":false,"disableMeta":false,"disableChangesApi":true,"disableDeltaChangesApi":true,"autoupdate":false,"serializableIndices":true,"disableFreeze":false,"ttl":null,"maxId":2,"DynamicViews":[],"events":{"insert":[],"update":[],"pre-insert":[],"pre-update":[],"close":[],"flushbuffer":[],"error":[],"delete":[null],"warning":[null]},"changes":[],"dirtyIds":[]}],"databaseVersion":1.5,"engineVersion":1.5,"autosave":false,"autosaveInterval":5000,"autosaveHandle":null,"throttledSaves":true,"options":{"serializationMethod":"normal","destructureDelimiter":"$<\n"},"persistenceMethod":"fs","persistenceAdapter":null,"verbose":false,"events":{"init":[null],"loaded":[],"flushChanges":[],"close":[],"changes":[],"warning":[]},"ENV":"NODEJS"} \ No newline at end of file +{"filename":"test.db","collections":[{"name":"items","data":[{"name":"n1","meta":{"revision":0,"created":1706121885408,"version":0},"$loki":1},{"name":"n2","meta":{"revision":0,"created":1706121885408,"version":0},"$loki":2}],"idIndex":null,"binaryIndices":{},"constraints":null,"uniqueNames":[],"transforms":{},"objType":"items","dirty":false,"cachedIndex":null,"cachedBinaryIndex":null,"cachedData":null,"adaptiveBinaryIndices":true,"transactional":false,"cloneObjects":false,"cloneMethod":"parse-stringify","asyncListeners":false,"disableMeta":false,"disableChangesApi":true,"disableDeltaChangesApi":true,"autoupdate":false,"serializableIndices":true,"disableFreeze":false,"ttl":null,"maxId":2,"DynamicViews":[],"events":{"insert":[],"update":[],"pre-insert":[],"pre-update":[],"close":[],"flushbuffer":[],"error":[],"delete":[null],"warning":[null]},"changes":[],"dirtyIds":[]}],"databaseVersion":1.5,"engineVersion":1.5,"autosave":false,"autosaveInterval":5000,"autosaveHandle":null,"throttledSaves":true,"options":{"serializationMethod":"normal","destructureDelimiter":"$<\n"},"persistenceMethod":"fs","persistenceAdapter":null,"verbose":false,"events":{"init":[null],"loaded":[],"flushChanges":[],"close":[],"changes":[],"warning":[]},"ENV":"NODEJS"} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..658dce6c --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "target": "es2015", + "lib": ["es2015", "dom", "ES2015"], + "module": "commonjs", + "forceConsistentCasingInFileNames": true, + "strict": false, + "skipLibCheck": true + } +}