diff --git a/CHANGELOG.md b/CHANGELOG.md index 0db9ff3..039b8cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # offline-editor-js - Changelog +## Version 2.12 + +No breaking changes. + +**Enhancements** +* Adds support for token-based authentication when syncing feature edits. +* Reduces POST request payload size when syncing edits by removing the InfoTemplate from request parameters. + ## Version 2.11.0.1 - Aug. 6, 2015 No breaking changes. Documentation and samples update, only. diff --git a/dist/offline-edit-min.js b/dist/offline-edit-min.js index feb9c55..d31a55a 100644 --- a/dist/offline-edit-min.js +++ b/dist/offline-edit-min.js @@ -1,6 +1,5 @@ -/*! offline-editor-js - v2.11.0 - 2015-07-30 +/*! offline-editor-js - v2.12.0 - 2015-08-07 * Copyright (c) 2015 Environmental Systems Research Institute, Inc. * Apache License*/ -define(["dojo/Evented","dojo/_base/Deferred","dojo/promise/all","dojo/_base/declare","dojo/_base/array","dojo/dom-attr","dojo/dom-style","dojo/query","esri/config","esri/layers/GraphicsLayer","esri/graphic","esri/request","esri/symbols/SimpleMarkerSymbol","esri/symbols/SimpleLineSymbol","esri/symbols/SimpleFillSymbol","esri/urlUtils"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p){"use strict";return d("O.esri.Edit.OfflineFeaturesManager",[a],{_onlineStatus:"online",_featureLayers:{},_featureCollectionUsageFlag:!1,_editStore:new O.esri.Edit.EditStore,_defaultXhrTimeout:15e3,ONLINE:"online",OFFLINE:"offline",RECONNECTING:"reconnecting",attachmentsStore:null,proxyPath:null,ENABLE_FEATURECOLLECTION:!1,DB_NAME:"features_store",DB_OBJECTSTORE_NAME:"features",DB_UID:"objectid",ATTACHMENTS_DB_NAME:"attachments_store",ATTACHMENTS_DB_OBJECTSTORE_NAME:"attachments",events:{EDITS_SENT:"edits-sent",EDITS_ENQUEUED:"edits-enqueued",EDITS_ENQUEUED_ERROR:"edits-enqueued-error",EDITS_SENT_ERROR:"edits-sent-error",ALL_EDITS_SENT:"all-edits-sent",ATTACHMENT_ENQUEUED:"attachment-enqueued",ATTACHMENTS_SENT:"attachments-sent",EXTEND_COMPLETE:"extend-complete"},initAttachments:function(a){if(a=a||function(a){},!this._checkFileAPIs())return a(!1,"File APIs not supported");try{if(this.attachmentsStore=new O.esri.Edit.AttachmentsStore,this.attachmentsStore.dbName=this.ATTACHMENTS_DB_NAME,this.attachmentsStore.objectStoreName=this.ATTACHMENTS_DB_OBJECTSTORE_NAME,!this.attachmentsStore.isSupported())return a(!1,"indexedDB not supported");this.attachmentsStore.init(a)}catch(b){}},extend:function(a,d,i){function l(){try{a._phantomLayer=new j({opacity:.8}),a._map.addLayer(a._phantomLayer)}catch(b){}}var m=[],n=this;a.offlineExtended=!0,a.objectIdField=this.DB_UID;var o=null;a.url&&(o=a.url,this._featureLayers[a.url]=a),a._mode.featureLayer.hasOwnProperty("_collection")&&(this._featureCollectionUsageFlag=!0),this._editStore._isDBInit||m.push(this._initializeDB(i,o)),a._applyEdits=a.applyEdits,a._addAttachment=a.addAttachment,a._queryAttachmentInfos=a.queryAttachmentInfos,a._deleteAttachments=a.deleteAttachments,a._updateAttachment=a.updateAttachment,a.queryAttachmentInfos=function(a,c,d){if(n.getOnlineStatus()===n.ONLINE){var e=this._queryAttachmentInfos(a,function(){n.emit(n.events.ATTACHMENTS_INFO,arguments),c&&c.apply(this,arguments)},d);return e}if(n.attachmentsStore){var f=new b;return n.attachmentsStore.getAttachmentsByFeatureId(this.url,a,function(a){c&&c(a),f.resolve(a)}),f}},a.addAttachment=function(a,c,d,e){if(n.getOnlineStatus()===n.ONLINE)return this._addAttachment(a,c,function(){n.emit(n.events.ATTACHMENTS_SENT,arguments),d&&d.apply(this,arguments)},function(a){e&&e.apply(this,arguments)});if(n.attachmentsStore){var f=this._getFilesFromForm(c),g=f[0],i=new b,j=this._getNextTempId();return n.attachmentsStore.store(this.url,j,a,g,n.attachmentsStore.TYPE.ADD,function(b,c){var f={attachmentId:j,objectId:a,success:b};if(b){n.emit(n.events.ATTACHMENT_ENQUEUED,f),d&&d(f),i.resolve(f);var g=this._url.path+"/"+a+"/attachments/"+j,k=h("[href="+g+"]");k.attr("href",c.url)}else f.error="can't store attachment",e&&e(f),i.reject(f)}.bind(this)),i}},a.updateAttachment=function(a,c,d,e,f){if(n.getOnlineStatus()===n.ONLINE)return this._updateAttachment(a,c,d,function(){e&&e.apply(this,arguments)},function(a){f&&f.apply(this,arguments)});if(n.attachmentsStore){var g=this._getFilesFromForm(d),i=g[0],j=n.attachmentsStore.TYPE.UPDATE,k=new b;return 0>c&&(j=n.attachmentsStore.TYPE.ADD),n.attachmentsStore.store(this.url,c,a,i,j,function(b,d){var g={attachmentId:c,objectId:a,success:b};if(b){n.emit(n.events.ATTACHMENT_ENQUEUED,g),e&&e(g),k.resolve(g);var i=this._url.path+"/"+a+"/attachments/"+c,j=h("[href="+i+"]");j.attr("href",d.url)}else g.error="layer.updateAttachment::attachmentStore can't store attachment",f&&f(g),k.reject(g)}.bind(this)),k}},a.deleteAttachments=function(a,d,e,f){if(n.getOnlineStatus()===n.ONLINE){var g=this._deleteAttachments(a,d,function(){e&&e.apply(this,arguments)},function(a){f&&f.apply(this,arguments)});return g}if(n.attachmentsStore){var h=[];d.forEach(function(c){c=parseInt(c,10);var d=new b;if(0>c)n.attachmentsStore["delete"](c,function(b){var e={objectId:a,attachmentId:c,success:b};d.resolve(e)});else{var e=new Blob([],{type:"image/png"});n.attachmentsStore.store(this.url,c,a,e,n.attachmentsStore.TYPE.DELETE,function(b,e){var f={attachmentId:c,objectId:a,success:b};b?d.resolve(f):d.reject(f)}.bind(this))}h.push(d)},this);var i=c(h);return i.then(function(a){e&&e(a)}),i}},a.applyEdits=function(d,e,f,g,h){var i=[];if(n.getOnlineStatus()===n.ONLINE){var j=this._applyEdits(d,e,f,function(){n.emit(n.events.EDITS_SENT,arguments),g&&g.apply(this,arguments)},h);return j}var k=new b,l={addResults:[],updateResults:[],deleteResults:[]},m={};return d=d||[],d.forEach(function(a){var c=new b,d=this._getNextTempId();a.attributes[this.objectIdField]=d;var e=this;this._validateFeature(a,this.url,n._editStore.ADD).then(function(b){b.success?e._pushValidatedAddFeatureToDB(e,a,b.operation,l,d,c):c.resolve(!0)},function(a){c.reject(a)}),i.push(c)},this),e=e||[],e.forEach(function(a){var c=new b,d=a.attributes[this.objectIdField];m[d]=a;var e=this;this._validateFeature(a,this.url,n._editStore.UPDATE).then(function(b){b.success?e._pushValidatedUpdateFeatureToDB(e,a,b.operation,l,d,c):c.resolve(!0)},function(a){c.reject(a)}),i.push(c)},this),f=f||[],f.forEach(function(a){var c=new b,d=a.attributes[this.objectIdField],e=this;this._validateFeature(a,this.url,n._editStore.DELETE).then(function(b){b.success?e._pushValidatedDeleteFeatureToDB(e,a,b.operation,l,d,c):c.resolve(!0)},function(a){c.reject(a)}),i.push(c)},this),c(i).then(function(b){for(var c=!0,e=0;eg;g++){var h=a[g].toJson();if(f.push(h),g==e-1){var i=JSON.stringify(f),j=JSON.stringify(d);c(i,j);break}}},a.getFeatureLayerJSON=function(a,b){require(["esri/request"],function(c){var d=c({url:a,content:{f:"json"},handleAs:"json",callbackParamName:"callback"});d.then(function(a){b(!0,a)},function(a){b(!1,a.message)})})},a.setFeatureLayerJSONDataStore=function(a,b){n._editStore.pushFeatureLayerJSON(a,function(a,c){b(a,c)})},a.getFeatureLayerJSONDataStore=function(a){n._editStore.getFeatureLayerJSON(function(b,c){a(b,c)})},a.setPhantomLayerGraphics=function(a){var b=a.length;if(b>0)for(var c=0;b>c;c++){var d=new k(a[c]);this._phantomLayer.add(d)}},a.getPhantomLayerGraphics=function(b){for(var c=a._phantomLayer.graphics,d=a._phantomLayer.graphics.length,e=[],f=0;d>f;f++){var g=c[f].toJson();if(e.push(g),f==d-1){var h=JSON.stringify(e);b(h);break}}},a.getPhantomGraphicsArray=function(a){n._editStore.getPhantomGraphicsArray(function(b,c){"end"==c?a(!0,b):a(!1,c)})},a.getAttachmentsUsage=function(a){n.attachmentsStore.getUsage(function(b,c){a(b,c)})},a.resetAttachmentsDatabase=function(a){n.attachmentsStore.resetAttachmentsQueue(function(b,c){a(b,c)})},a.getUsage=function(a){n._editStore.getUsage(function(b,c){a(b,c)})},a.resetDatabase=function(a){n._editStore.resetEditsQueue(function(b,c){a(b,c)})},a.pendingEditsCount=function(a){n._editStore.pendingEditsCount(function(b){a(b)})},a.getFeatureDefinition=function(a,b,c,d){var e={layerDefinition:a,featureSet:{features:b,geometryType:c}};d(e)},a.getAllEditsArray=function(a){n._editStore.getAllEditsArray(function(b,c){"end"==c?a(!0,b):a(!1,c)})},a._pushFeatureCollections=function(){n._editStore._getFeatureCollections(function(b,c){var d={featureLayerUrl:a.url,featureLayerCollection:a.toJson()},e=[d],f={id:n._editStore.FEATURE_COLLECTION_ID,featureCollections:e};if(a.hasAttachments=d.featureLayerCollection.layerDefinition.hasAttachments,b){for(var g=0,h=0;hd;d++)n.attachmentsStore.replaceFeatureId(this.url,a[d],b[d],function(a){--f,g+=a?1:0,0===f&&c(g)}.bind(this))},a._nextTempId=-1,a._getNextTempId=function(){return this._nextTempId--},l(),c(m).then(function(b){0===b.length&&o?(this.ENABLE_FEATURECOLLECTION&&a._pushFeatureCollections(),d(!0,null)):b[0].success&&!o?this._editStore.getFeatureLayerJSON(function(b,c){b?(this._featureLayers[c.__featureLayerURL]=a,a.url=c.__featureLayerURL,this.ENABLE_FEATURECOLLECTION&&a._pushFeatureCollections(),d(!0,null)):d(!1,c)}.bind(this)):b[0].success&&(this.ENABLE_FEATURECOLLECTION&&a._pushFeatureCollections(),d(!0,null))}.bind(this))},goOffline:function(){this._onlineStatus=this.OFFLINE},goOnline:function(a){this._onlineStatus=this.RECONNECTING,this._replayStoredEdits(function(b,c){var d={success:b,responses:c};this._onlineStatus=this.ONLINE,null!=this.attachmentsStore?this._sendStoredAttachments(function(b,c,e){d.attachments={success:b,responses:c,dbResponses:e},a&&a(d)}.bind(this)):a&&a(d)}.bind(this))},getOnlineStatus:function(){return this._onlineStatus},serializeFeatureGraphicsArray:function(a,b){for(var c=a.length,d=[],e=0;c>e;e++){var f=a[e].toJson();if(d.push(f),e==c-1){var g=JSON.stringify(d);b(g);break}}},getFeatureCollections:function(a){this._editStore._isDBInit?this._editStore._getFeatureCollections(function(b,c){a(b,c)}):this._initializeDB(null,null).then(function(b){b.success&&this._editStore._getFeatureCollections(function(b,c){a(b,c)})}.bind(this),function(b){a(!1,b)})},getFeatureLayerJSONDataStore:function(a){this._editStore._isDBInit?this._editStore.getFeatureLayerJSON(function(b,c){a(b,c)}):this._initializeDB(null,null).then(function(b){b.success&&this._editStore.getFeatureLayerJSON(function(b,c){a(b,c)})}.bind(this),function(b){a(!1,b)})},_initializeDB:function(a,c){var d=new b,e=this._editStore;return e.dbName=this.DB_NAME,e.objectStoreName=this.DB_OBJECTSTORE_NAME,e.objectId=this.DB_UID,e.init(function(b,f){"object"==typeof a&&b===!0&&void 0!==a&&null!==a?(c&&(a.__featureLayerURL=c),e.pushFeatureLayerJSON(a,function(a,b){a?d.resolve({success:!0,error:null}):d.reject({success:!1,error:b})})):b?d.resolve({success:!0,error:null}):d.reject({success:!1,error:null})}),d},_checkFileAPIs:function(){return window.File&&window.FileReader&&window.FileList&&window.Blob?(XMLHttpRequest.prototype.sendAsBinary||(XMLHttpRequest.prototype.sendAsBinary=function(a){function b(a){return 255&a.charCodeAt(0)}var c=Array.prototype.map.call(a,b),d=new Uint8Array(c);this.send(d.buffer)}),!0):!1},_extendAjaxReq:function(a){a.sendAsBinary=XMLHttpRequest.prototype.sendAsBinary},_phantomSymbols:[],_getPhantomSymbol:function(a,b){if(0===this._phantomSymbols.length){var c=[0,255,0,255],d=1.5;this._phantomSymbols.point=[],this._phantomSymbols.point[this._editStore.ADD]=new m({type:"esriSMS",style:"esriSMSCross",xoffset:10,yoffset:10,color:[255,255,255,0],size:15,outline:{color:c,width:d,type:"esriSLS",style:"esriSLSSolid"}}),this._phantomSymbols.point[this._editStore.UPDATE]=new m({type:"esriSMS",style:"esriSMSCircle",xoffset:0,yoffset:0,color:[255,255,255,0],size:15,outline:{color:c,width:d,type:"esriSLS",style:"esriSLSSolid"}}),this._phantomSymbols.point[this._editStore.DELETE]=new m({type:"esriSMS",style:"esriSMSX",xoffset:0,yoffset:0,color:[255,255,255,0],size:15,outline:{color:c,width:d,type:"esriSLS",style:"esriSLSSolid"}}),this._phantomSymbols.multipoint=null,this._phantomSymbols.polyline=[],this._phantomSymbols.polyline[this._editStore.ADD]=new n({type:"esriSLS",style:"esriSLSSolid",color:c,width:d}),this._phantomSymbols.polyline[this._editStore.UPDATE]=new n({type:"esriSLS",style:"esriSLSSolid",color:c,width:d}),this._phantomSymbols.polyline[this._editStore.DELETE]=new n({type:"esriSLS",style:"esriSLSSolid",color:c,width:d}),this._phantomSymbols.polygon=[],this._phantomSymbols.polygon[this._editStore.ADD]=new o({type:"esriSFS",style:"esriSFSSolid",color:[255,255,255,0],outline:{type:"esriSLS",style:"esriSLSSolid",color:c,width:d}}),this._phantomSymbols.polygon[this._editStore.UPDATE]=new o({type:"esriSFS",style:"esriSFSSolid",color:[255,255,255,0],outline:{type:"esriSLS",style:"esriSLSDash",color:c,width:d}}),this._phantomSymbols.polygon[this._editStore.DELETE]=new o({type:"esriSFS",style:"esriSFSSolid",color:[255,255,255,0],outline:{type:"esriSLS",style:"esriSLSDot",color:c,width:d}})}return this._phantomSymbols[a.type][b]},_uploadAttachment:function(a){var c=new b,d=this._featureLayers[a.featureLayerUrl],e=new FormData;switch(e.append("attachment",a.file),a.type){case this.attachmentsStore.TYPE.ADD:d.addAttachment(a.objectId,e,function(b){c.resolve({attachmentResult:b,id:a.id})},function(a){c.reject(a)});break;case this.attachmentsStore.TYPE.UPDATE:e.append("attachmentId",a.id),d._sendAttachment("update",a.objectId,e,function(b){c.resolve({attachmentResult:b,id:a.id})},function(a){c.reject(a)});break;case this.attachmentsStore.TYPE.DELETE:d.deleteAttachments(a.objectId,[a.id],function(b){c.resolve({attachmentResult:b,id:a.id})},function(a){c.reject(a)})}return c.promise},_deleteAttachmentFromDB:function(a,c){var d=new b;return this.attachmentsStore["delete"](a,function(a){d.resolve({success:a,result:c})}),d},_cleanAttachmentsDB:function(a,b){var d=this,e=[],f=0;a.forEach(function(a){"object"==typeof a.attachmentResult&&a.attachmentResult.success?e.push(d._deleteAttachmentFromDB(a.id,null)):a.attachmentResult instanceof Array?a.attachmentResult.forEach(function(b){b.success?e.push(d._deleteAttachmentFromDB(a.id,null)):f++}):f++});var g=c(e);g.then(function(c){b(f>0?{errors:!0,attachmentsDBResults:c,uploadResults:a}:{errors:!1,attachmentsDBResults:c,uploadResults:a})})},_sendStoredAttachments:function(a){this.attachmentsStore.getAllAttachments(function(b){var d=this,e=[];b.forEach(function(a){var b=this._uploadAttachment(a);e.push(b)},this);var f=c(e);f.then(function(b){d._cleanAttachmentsDB(b,function(c){c.errors?a&&a(!1,b,c):a&&a(!0,b,c)})},function(b){a&&a(!1,b)})}.bind(this))},_replayStoredEdits:function(a){var b,d={},e=this,f=[],g=[],h=[],i=[],j=[],l=this._featureLayers,m=this.attachmentsStore,n=this._editStore;this._editStore.getAllEditsArray(function(o,p){if(o.length>0){j=o;for(var q=j.length,r=0;q>r;r++){b=l[j[r].layer],null==m&&b.hasAttachments,b._attachmentsStore=m,b.__onEditsComplete=b.onEditsComplete,b.onEditsComplete=function(){},f=[],g=[],h=[],i=[];var s=new k(j[r].graphic);switch(j[r].operation){case n.ADD:for(var t=0;t0&&(g.updateResults[0].success?(h.layer=g.layer,h.id=g.updateResults[0].objectId,d.push(h)):e.push(g)),g.deleteResults.length>0&&(g.deleteResults[0].success?(h.layer=g.layer,h.id=g.deleteResults[0].objectId,d.push(h)):e.push(g)),g.addResults.length>0&&(g.addResults[0].success?(h.layer=g.layer,h.id=g.tempId,d.push(h)):e.push(g))}for(var i={},j=d.length,k=0;j>k;k++)i[k]=this._updateDatabase(d[k]);var l=c(i);l.then(function(a){e.length>0?b(!1,a):b(!0,a)},function(a){b(!1,a)})}else b(!0,{})},_updateDatabase:function(a){var c=new b,d={};return d.attributes={},d.attributes[this.DB_UID]=a.id,this._editStore["delete"](a.layer,d,function(a,b){a?c.resolve({success:!0,error:null}):c.reject({success:!1,error:b})}.bind(this)),c.promise},getFeatureLayerJSON:function(a,b){require(["esri/request"],function(c){var d=c({url:a,content:{f:"json"},handleAs:"json",callbackParamName:"callback"});d.then(function(a){b(!0,a)},function(a){b(!1,a.message)})})},_internalApplyEdits:function(a,c,d,e,f,g){var h=this,i=new b;return a._applyEdits(e,f,g,function(b,e,f){if(a._phantomLayer.clear(),null!=a._attachmentsStore&&a.hasAttachments&&d.length>0){var g=b.map(function(a){return a.objectId});a._replaceFeatureIds(d,g,function(a){})}h._cleanDatabase(a,d,b,e,f).then(function(g){i.resolve({id:c,layer:a.url,tempId:d,addResults:b,updateResults:e,deleteResults:f,databaseResults:g,databaseErrors:null})},function(g){i.resolve({id:c,layer:a.url,tempId:d,addResults:b,updateResults:e,deleteResults:f,databaseResults:null,databaseErrors:g})})},function(b){a.onEditsComplete=a.__onEditsComplete,delete a.__onEditsComplete,i.reject(b)}),i.promise},_internalApplyEditsAll:function(a,c,d,e,f,g){var h=this,i=new b;return this._makeEditRequest(a.url,e,f,g,function(b,f,g){if(a._phantomLayer.clear(),null!=a._attachmentsStore&&a.hasAttachments&&d.length>0){var j=b.map(function(a){return a.objectId});a._replaceFeatureIds(d,j,function(e){i.resolve({id:c,layer:a.url,tempId:d,addResults:b,updateResults:f,deleteResults:g,syncError:null})})}if(b.length>0){var l=new k(e[0].geometry,null,e[0].attributes);a.add(l)}h._cleanDatabase(a,d,b,f,g).then(function(e){i.resolve({id:c,layer:a.url,tempId:d,addResults:b,updateResults:f,deleteResults:g,databaseResults:e,databaseErrors:null,syncError:null})},function(e){i.resolve({id:c,layer:a.url,tempId:d,addResults:b,updateResults:f,deleteResults:g,databaseResults:null,databaseErrors:e,syncError:e})})},function(b){a.onEditsComplete=a.__onEditsComplete,delete a.__onEditsComplete,i.reject(b)}),i.promise},_cleanDatabase:function(a,c,d,e,f){var g=new b,h=null;e.length>0&&e[0].success&&(h=e[0].objectId),f.length>0&&f[0].success&&(h=f[0].objectId),d.length>0&&d[0].success&&(h=c);var i={};return i.attributes={},i.attributes[this.DB_UID]=h,this._editStore["delete"](a.url,i,function(a,b){if(a){var c=this._editStore.PHANTOM_GRAPHIC_PREFIX+this._editStore._PHANTOM_PREFIX_TOKEN+i.attributes[this.DB_UID];this._editStore.deletePhantomGraphic(c,function(a,b){a?g.resolve({success:!0,error:null,id:c}):g.reject({success:!1,error:b,id:c})})}else g.reject({success:!1,error:b,id:c})}.bind(this)),g.promise},_makeEditRequest:function(a,b,c,d,e,f){var g="f=json",h="",i="",j="";if(b.length>0&&(h="&adds="+JSON.stringify(b)),c.length>0&&(i="&updates="+JSON.stringify(c)),d.length>0){var k=d[0].attributes[this.DB_UID];j="&deletes="+k}var l=g+h+i+j,m=new XMLHttpRequest;m.open("POST",a+"/applyEdits",!0),m.setRequestHeader("Content-type","application/x-www-form-urlencoded"),m.onload=function(){if(200===m.status&&""!==m.responseText)try{var a=JSON.parse(this.response);e(a.addResults,a.updateResults,a.deleteResults)}catch(b){f("Unable to parse xhr response")}},m.onerror=function(a){f(a)},m.ontimeout=function(){f("xhr timeout error")},m.timeout=this._defaultXhrTimeout,m.send(l)},_parseResponsesArray:function(a){var c=new b,d=0;for(var e in a)a.hasOwnProperty(e)&&(a[e].addResults.map(function(a){a.success||d++}),a[e].updateResults.map(function(a){a.success||d++}),a[e].deleteResults.map(function(a){a.success||d++}));return c.resolve(d>0?!1:!0),c.promise}})}),"undefined"!=typeof O?O.esri.Edit={}:(O={},O.esri={Edit:{}}),O.esri.Edit.EditStore=function(){"use strict";this._db=null,this._isDBInit=!1,this.dbName="features_store",this.objectStoreName="features",this.objectId="objectid",this.ADD="add",this.UPDATE="update",this.DELETE="delete",this.FEATURE_LAYER_JSON_ID="feature-layer-object-1001",this.FEATURE_COLLECTION_ID="feature-collection-object-1001",this.PHANTOM_GRAPHIC_PREFIX="phantom-layer",this._PHANTOM_PREFIX_TOKEN="|@|",this.isSupported=function(){return window.indexedDB?!0:!1},this.pushEdit=function(a,b,c,d){var e={id:b+"/"+c.attributes[this.objectId],operation:a,layer:b,type:c.geometry.type,graphic:c.toJson()};if("undefined"==typeof c.attributes[this.objectId])d(!1,"editsStore.pushEdit() - failed to insert undefined objectId into database. Did you set offlineFeaturesManager.DB_UID? "+JSON.stringify(c.attributes));else{var f=this._db.transaction([this.objectStoreName],"readwrite");f.oncomplete=function(a){d(!0)},f.onerror=function(a){d(!1,a.target.error.message)};var g=f.objectStore(this.objectStoreName);g.put(e)}},this.pushFeatureLayerJSON=function(a,b){"object"!=typeof a&&b(!1,"dataObject type is not an object.");var c=this._db;a.id=this.FEATURE_LAYER_JSON_ID,this.getFeatureLayerJSON(function(d,e){var f;if(d&&"undefined"!=typeof e){f=c.transaction([this.objectStoreName],"readwrite").objectStore(this.objectStoreName);for(var g in a)a.hasOwnProperty(g)&&(e[g]=a[g]);var h=f.put(e);h.onsuccess=function(){b(!0,null)},h.onerror=function(a){b(!1,a)}}else{var i=c.transaction([this.objectStoreName],"readwrite");i.oncomplete=function(a){b(!0,null)},i.onerror=function(a){b(!1,a.target.error.message)},f=i.objectStore(this.objectStoreName);try{f.put(a)}catch(j){b(!1,JSON.stringify(j))}}}.bind(this))},this.getFeatureLayerJSON=function(a){var b=this._db.transaction([this.objectStoreName],"readwrite").objectStore(this.objectStoreName),c=b.get(this.FEATURE_LAYER_JSON_ID);c.onsuccess=function(){var b=c.result;"undefined"!=typeof b?a(!0,b):a(!1,"nothing found")},c.onerror=function(b){a(!1,b)}},this.deleteFeatureLayerJSON=function(a){var b=this._db,c=null,d=this,e=this.FEATURE_LAYER_JSON_ID;require(["dojo/Deferred"],function(f){c=new f,c.then(function(b){d.editExists(e).then(function(b){a(!1,{message:"object was not deleted."})},function(b){a(!0,{message:"id does not exist"})})},function(b){a(!1,{message:"id does not exist"})}),d.editExists(e).then(function(a){var f=b.transaction([d.objectStoreName],"readwrite").objectStore(d.objectStoreName),g=f["delete"](e);g.onsuccess=function(){c.resolve(!0)},g.onerror=function(a){c.reject({success:!1,error:a})}},function(a){c.reject({success:!1,message:a})}.bind(this))})},this.pushPhantomGraphic=function(a,b){var c=this._db,d=this.PHANTOM_GRAPHIC_PREFIX+this._PHANTOM_PREFIX_TOKEN+a.attributes[this.objectId],e={id:d,graphic:a.toJson()},f=c.transaction([this.objectStoreName],"readwrite");f.oncomplete=function(a){b(!0,null)},f.onerror=function(a){b(!1,a.target.error.message)};var g=f.objectStore(this.objectStoreName);g.put(e)},this.getPhantomGraphicsArray=function(a){var b=[];if(null!==this._db){var c=this.PHANTOM_GRAPHIC_PREFIX,d=this._db.transaction([this.objectStoreName]).objectStore(this.objectStoreName).openCursor();d.onsuccess=function(d){var e=d.target.result;e&&e.value&&e.value.id?(-1!=e.value.id.indexOf(c)&&b.push(e.value),e["continue"]()):a(b,"end")}.bind(this),d.onerror=function(b){a(null,b)}}else a(null,"no db")},this._getPhantomGraphicsArraySimple=function(a){var b=[];if(null!==this._db){var c=this.PHANTOM_GRAPHIC_PREFIX,d=this._db.transaction([this.objectStoreName]).objectStore(this.objectStoreName).openCursor();d.onsuccess=function(d){var e=d.target.result;e&&e.value&&e.value.id?(-1!=e.value.id.indexOf(c)&&b.push(e.value.id),e["continue"]()):a(b,"end")}.bind(this),d.onerror=function(b){a(null,b)}}else a(null,"no db")},this.deletePhantomGraphic=function(a,b){var c=this._db,d=null,e=this;require(["dojo/Deferred"],function(f){d=new f,e.editExists(a).then(function(f){d.then(function(c){e.editExists(a).then(function(a){b(!1,"item was not deleted")},function(a){b(!0,"item successfully deleted")})},function(a){b(!1,a)});var g=c.transaction([e.objectStoreName],"readwrite").objectStore(e.objectStoreName),h=g["delete"](a);h.onsuccess=function(){d.resolve(!0)},h.onerror=function(a){d.reject({success:!1,error:a})}},function(a){b(!1,"item doesn't exist in db")})})},this.resetLimitedPhantomGraphicsQueue=function(a,b){if(Object.keys(a).length>0){var c=this._db,d=0,e=c.transaction([this.objectStoreName],"readwrite"),f=e.objectStore(this.objectStoreName);f.onerror=function(){d++},e.oncomplete=function(){b(0===d?!0:!1)};for(var g in a)if(a.hasOwnProperty(g)){var h=a[g],i=this.PHANTOM_GRAPHIC_PREFIX+this._PHANTOM_PREFIX_TOKEN+h.id;h.updateResults.length>0&&h.updateResults[0].success&&f["delete"](i),h.deleteResults.length>0&&h.deleteResults[0].success&&f["delete"](i),h.addResults.length>0&&h.addResults[0].success&&f["delete"](i)}}else b(!0)},this.resetPhantomGraphicsQueue=function(a){var b=this._db;this._getPhantomGraphicsArraySimple(function(c){if(c!=[]){var d=0,e=b.transaction([this.objectStoreName],"readwrite"),f=e.objectStore(this.objectStoreName);f.onerror=function(){d++},e.oncomplete=function(){a(0===d?!0:!1)};for(var g=c.length,h=0;g>h;h++)f["delete"](c[h])}else a(!0)}.bind(this))},this.getEdit=function(a,b){var c=this._db.transaction([this.objectStoreName],"readwrite").objectStore(this.objectStoreName);if("undefined"==typeof a)return void b(!1,"id is undefined.");var d=c.get(a);d.onsuccess=function(){var c=d.result;c&&c.id==a?b(!0,c):b(!1,"Id not found")},d.onerror=function(a){b(!1,a)}},this.getAllEdits=function(a){if(null!==this._db){var b=this.FEATURE_LAYER_JSON_ID,c=this.FEATURE_COLLECTION_ID,d=this.PHANTOM_GRAPHIC_PREFIX,e=this._db.transaction([this.objectStoreName]).objectStore(this.objectStoreName).openCursor();e.onsuccess=function(e){var f=e.target.result;f&&f.hasOwnProperty("value")&&f.value.hasOwnProperty("id")?(f.value.id!==b&&f.value.id!==c&&-1==f.value.id.indexOf(d)&&a(f.value,null),f["continue"]()):a(null,"end")}.bind(this),e.onerror=function(b){a(null,b)}}else a(null,"no db")},this.getAllEditsArray=function(a){var b=[];if(null!==this._db){var c=this.FEATURE_LAYER_JSON_ID,d=this.FEATURE_COLLECTION_ID,e=this.PHANTOM_GRAPHIC_PREFIX,f=this._db.transaction([this.objectStoreName]).objectStore(this.objectStoreName).openCursor();f.onsuccess=function(f){var g=f.target.result;g&&g.value&&g.value.id?(g.value.id!==c&&g.value.id!==d&&-1==g.value.id.indexOf(e)&&b.push(g.value),g["continue"]()):a(b,"end")}.bind(this),f.onerror=function(b){a(null,b)}}else a(null,"no db")},this.updateExistingEdit=function(a,b,c,d){var e=this._db.transaction([this.objectStoreName],"readwrite").objectStore(this.objectStoreName),f=e.get(c.attributes[this.objectId]);f.onsuccess=function(){f.result;var g={id:b+"/"+c.attributes[this.objectId],operation:a,layer:b,graphic:c.toJson()},h=e.put(g);h.onsuccess=function(){d(!0)},h.onerror=function(a){d(!1,a)}}.bind(this)},this["delete"]=function(a,b,c){var d=this._db,e=null,f=this,g=a+"/"+b.attributes[this.objectId];require(["dojo/Deferred"],function(a){e=new a,f.editExists(g).then(function(a){e.then(function(a){f.editExists(g).then(function(a){c(!1)},function(a){c(!0)})},function(a){c(!1,a)});var b=d.transaction([f.objectStoreName],"readwrite").objectStore(f.objectStoreName),h=b["delete"](g);h.onsuccess=function(){e.resolve(!0)},h.onerror=function(a){e.reject({success:!1,error:a})}},function(a){c(!1)})})},this.resetEditsQueue=function(a){var b=this._db.transaction([this.objectStoreName],"readwrite").objectStore(this.objectStoreName).clear();b.onsuccess=function(b){setTimeout(function(){a(!0)},0)},b.onerror=function(b){a(!1,b)}},this.pendingEditsCount=function(a){var b=0,c=this.FEATURE_LAYER_JSON_ID,d=this.FEATURE_COLLECTION_ID,e=this.PHANTOM_GRAPHIC_PREFIX,f=this._db.transaction([this.objectStoreName],"readwrite"),g=f.objectStore(this.objectStoreName);g.openCursor().onsuccess=function(f){var g=f.target.result;g&&g.value&&g.value.id&&-1==g.value.id.indexOf(e)?(g.value.id!==c&&g.value.id!==d&&b++,g["continue"]()):a(b)}},this.editExists=function(a){var b=this._db,c=null,d=this;return require(["dojo/Deferred"],function(e){c=new e;var f=b.transaction([d.objectStoreName],"readwrite").objectStore(d.objectStoreName),g=f.get(a);g.onsuccess=function(){var b=g.result;b&&b.id==a?c.resolve({success:!0,error:null}):c.reject({success:!1,error:"objectId is not a match."})},g.onerror=function(a){c.reject({success:!1,error:a})}}),c},this.getUsage=function(a){var b=this.FEATURE_LAYER_JSON_ID,c=this.FEATURE_COLLECTION_ID,d=this.PHANTOM_GRAPHIC_PREFIX,e={sizeBytes:0,editCount:0},f=this._db.transaction([this.objectStoreName]).objectStore(this.objectStoreName).openCursor();f.onsuccess=function(f){var g=f.target.result;if(g&&g.value&&g.value.id){var h=g.value,i=JSON.stringify(h);e.sizeBytes+=i.length,-1==g.value.id.indexOf(d)&&g.value.id!==b&&g.value.id!==c&&(e.editCount+=1),g["continue"]()}else a(e,null)},f.onerror=function(b){a(null,b)}},this._pushFeatureCollections=function(a,b){var c=this._db.transaction([this.objectStoreName],"readwrite");c.oncomplete=function(a){b(!0)},c.onerror=function(a){b(!1,a.target.error.message)};var d=c.objectStore(this.objectStoreName);d.put(a)},this._getFeatureCollections=function(a){var b=this._db.transaction([this.objectStoreName],"readonly").objectStore(this.objectStoreName),c=b.get(this.FEATURE_COLLECTION_ID); - -c.onsuccess=function(){var b=c.result;"undefined"!=typeof b?a(!0,b):a(!1,null)},c.onerror=function(b){a(!1,b)}},this._serialize=function(a){var b=a.toJson(),c={attributes:b.attributes,geometry:b.geometry,infoTemplate:b.infoTemplate,symbol:b.symbol};return JSON.stringify(c)},this._deserialize=function(a){var b;return require(["esri/graphic"],function(c){b=new c(JSON.parse(a))}),b},this.init=function(a){var b=indexedDB.open(this.dbName,11);a=a||function(a){}.bind(this),b.onerror=function(b){a(!1,b.target.errorCode)}.bind(this),b.onupgradeneeded=function(a){var b=a.target.result;b.objectStoreNames.contains(this.objectStoreName)&&b.deleteObjectStore(this.objectStoreName),b.createObjectStore(this.objectStoreName,{keyPath:"id"})}.bind(this),b.onsuccess=function(b){this._db=b.target.result,this._isDBInit=!0,a(!0,null)}.bind(this)}},O.esri.Edit.AttachmentsStore=function(){"use strict";this._db=null,this.dbName="attachments_store",this.objectStoreName="attachments",this.TYPE={ADD:"add",UPDATE:"update",DELETE:"delete"},this.isSupported=function(){return window.indexedDB?!0:!1},this.store=function(a,b,c,d,e,f){try{e==this.TYPE.ADD||e==this.TYPE.UPDATE||e==this.TYPE.DELETE?this._readFile(d,function(g,h){if(g){var i={id:b,objectId:c,type:e,featureId:a+"/"+c,contentType:d.type,name:d.name,size:d.size,featureLayerUrl:a,content:h,file:d},j=this._db.transaction([this.objectStoreName],"readwrite");j.oncomplete=function(a){f(!0,i)},j.onerror=function(a){f(!1,a.target.error.message)};try{j.objectStore(this.objectStoreName).put(i)}catch(k){f(!1,k)}}else f(!1,h)}.bind(this)):f(!1,"attachmentsStore.store() Invalid type in the constructor!")}catch(g){f(!1,g.stack)}},this.retrieve=function(a,b){var c=this._db.transaction([this.objectStoreName]).objectStore(this.objectStoreName),d=c.get(a);d.onsuccess=function(a){var c=a.target.result;c?b(!0,c):b(!1,"not found")},d.onerror=function(a){b(!1,a)}},this.getAttachmentsByFeatureId=function(a,b,c){var d=a+"/"+b,e=[],f=this._db.transaction([this.objectStoreName]).objectStore(this.objectStoreName),g=f.index("featureId"),h=IDBKeyRange.only(d);g.openCursor(h).onsuccess=function(a){var b=a.target.result;b?(e.push(b.value),b["continue"]()):c(e)}},this.getAttachmentsByFeatureLayer=function(a,b){var c=[],d=this._db.transaction([this.objectStoreName]).objectStore(this.objectStoreName),e=d.index("featureLayerUrl"),f=IDBKeyRange.only(a);e.openCursor(f).onsuccess=function(a){var d=a.target.result;d?(c.push(d.value),d["continue"]()):b(c)}},this.getAllAttachments=function(a){var b=[],c=this._db.transaction([this.objectStoreName]).objectStore(this.objectStoreName);c.openCursor().onsuccess=function(c){var d=c.target.result;d?(b.push(d.value),d["continue"]()):a(b)}},this.deleteAttachmentsByFeatureId=function(a,b,c){var d=a+"/"+b,e=this._db.transaction([this.objectStoreName],"readwrite").objectStore(this.objectStoreName),f=e.index("featureId"),g=IDBKeyRange.only(d),h=0;f.openCursor(g).onsuccess=function(a){var b=a.target.result;b?(e["delete"](b.primaryKey),h++,b["continue"]()):setTimeout(function(){c(h)},0)}.bind(this)},this["delete"]=function(a,b){this.retrieve(a,function(c,d){if(!c)return void b(!1,"attachment "+a+" not found");var e=this._db.transaction([this.objectStoreName],"readwrite").objectStore(this.objectStoreName)["delete"](a);e.onsuccess=function(a){setTimeout(function(){b(!0)},0)},e.onerror=function(a){b(!1,a)}}.bind(this))},this.deleteAll=function(a){this.getAllAttachments(function(b){var c=this._db.transaction([this.objectStoreName],"readwrite").objectStore(this.objectStoreName).clear();c.onsuccess=function(b){setTimeout(function(){a(!0)},0)},c.onerror=function(b){a(!1,b)}}.bind(this))},this.replaceFeatureId=function(a,b,c,d){var e=a+"/"+b,f=this._db.transaction([this.objectStoreName],"readwrite").objectStore(this.objectStoreName),g=f.index("featureId"),h=IDBKeyRange.only(e),i=0;g.openCursor(h).onsuccess=function(b){var e=b.target.result;if(e){var g=a+"/"+c,h=e.value;h.featureId=g,h.objectId=c,f.put(h),i++,e["continue"]()}else setTimeout(function(){d(i)},1)}},this.getUsage=function(a){var b={sizeBytes:0,attachmentCount:0},c=this._db.transaction([this.objectStoreName]).objectStore(this.objectStoreName).openCursor();c.onsuccess=function(c){var d=c.target.result;if(d){var e=d.value,f=JSON.stringify(e);b.sizeBytes+=f.length,b.attachmentCount+=1,d["continue"]()}else a(b,null)}.bind(this),c.onerror=function(b){a(null,b)}},this.resetAttachmentsQueue=function(a){var b=this._db.transaction([this.objectStoreName],"readwrite").objectStore(this.objectStoreName).clear();b.onsuccess=function(b){setTimeout(function(){a(!0)},0)},b.onerror=function(b){a(!1,b)}},this._readFile=function(a,b){var c=new FileReader;c.onload=function(a){b(!0,a.target.result)},c.onerror=function(a){b(!1,a.target.result)},c.readAsBinaryString(a)},this.init=function(a){var b=indexedDB.open(this.dbName,12);a=a||function(a){}.bind(this),b.onerror=function(b){a(!1,b.target.errorCode)}.bind(this),b.onupgradeneeded=function(a){var b=a.target.result;b.objectStoreNames.contains(this.objectStoreName)&&b.deleteObjectStore(this.objectStoreName);var c=b.createObjectStore(this.objectStoreName,{keyPath:"id"});c.createIndex("featureId","featureId",{unique:!1}),c.createIndex("featureLayerUrl","featureLayerUrl",{unique:!1})}.bind(this),b.onsuccess=function(b){this._db=b.target.result,a(!0)}.bind(this)}}; \ No newline at end of file +define(["dojo/Evented","dojo/_base/Deferred","dojo/promise/all","dojo/_base/declare","dojo/_base/array","dojo/dom-attr","dojo/dom-style","dojo/query","esri/config","esri/kernel","esri/layers/GraphicsLayer","esri/graphic","esri/request","esri/symbols/SimpleMarkerSymbol","esri/symbols/SimpleLineSymbol","esri/symbols/SimpleFillSymbol","esri/urlUtils"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q){"use strict";return d("O.esri.Edit.OfflineFeaturesManager",[a],{_onlineStatus:"online",_featureLayers:{},_featureCollectionUsageFlag:!1,_editStore:new O.esri.Edit.EditStore,_defaultXhrTimeout:15e3,ONLINE:"online",OFFLINE:"offline",RECONNECTING:"reconnecting",attachmentsStore:null,proxyPath:null,ENABLE_FEATURECOLLECTION:!1,DB_NAME:"features_store",DB_OBJECTSTORE_NAME:"features",DB_UID:"objectid",ATTACHMENTS_DB_NAME:"attachments_store",ATTACHMENTS_DB_OBJECTSTORE_NAME:"attachments",events:{EDITS_SENT:"edits-sent",EDITS_ENQUEUED:"edits-enqueued",EDITS_ENQUEUED_ERROR:"edits-enqueued-error",EDITS_SENT_ERROR:"edits-sent-error",ALL_EDITS_SENT:"all-edits-sent",ATTACHMENT_ENQUEUED:"attachment-enqueued",ATTACHMENTS_SENT:"attachments-sent",EXTEND_COMPLETE:"extend-complete"},initAttachments:function(a){if(a=a||function(a){},!this._checkFileAPIs())return a(!1,"File APIs not supported");try{if(this.attachmentsStore=new O.esri.Edit.AttachmentsStore,this.attachmentsStore.dbName=this.ATTACHMENTS_DB_NAME,this.attachmentsStore.objectStoreName=this.ATTACHMENTS_DB_OBJECTSTORE_NAME,!this.attachmentsStore.isSupported())return a(!1,"indexedDB not supported");this.attachmentsStore.init(a)}catch(b){}},extend:function(a,d,i){function j(){try{a._phantomLayer=new k({opacity:.8}),a._map.addLayer(a._phantomLayer)}catch(b){}}var m=[],n=this;a.offlineExtended=!0,a.objectIdField=this.DB_UID;var o=null;a.url&&(o=a.url,this._featureLayers[a.url]=a),a._mode.featureLayer.hasOwnProperty("_collection")&&(this._featureCollectionUsageFlag=!0),this._editStore._isDBInit||m.push(this._initializeDB(i,o)),a._applyEdits=a.applyEdits,a._addAttachment=a.addAttachment,a._queryAttachmentInfos=a.queryAttachmentInfos,a._deleteAttachments=a.deleteAttachments,a._updateAttachment=a.updateAttachment,a.queryAttachmentInfos=function(a,c,d){if(n.getOnlineStatus()===n.ONLINE){var e=this._queryAttachmentInfos(a,function(){n.emit(n.events.ATTACHMENTS_INFO,arguments),c&&c.apply(this,arguments)},d);return e}if(n.attachmentsStore){var f=new b;return n.attachmentsStore.getAttachmentsByFeatureId(this.url,a,function(a){c&&c(a),f.resolve(a)}),f}},a.addAttachment=function(a,c,d,e){if(n.getOnlineStatus()===n.ONLINE)return this._addAttachment(a,c,function(){n.emit(n.events.ATTACHMENTS_SENT,arguments),d&&d.apply(this,arguments)},function(a){e&&e.apply(this,arguments)});if(n.attachmentsStore){var f=this._getFilesFromForm(c),g=f[0],i=new b,j=this._getNextTempId();return n.attachmentsStore.store(this.url,j,a,g,n.attachmentsStore.TYPE.ADD,function(b,c){var f={attachmentId:j,objectId:a,success:b};if(b){n.emit(n.events.ATTACHMENT_ENQUEUED,f),d&&d(f),i.resolve(f);var g=this._url.path+"/"+a+"/attachments/"+j,k=h("[href="+g+"]");k.attr("href",c.url)}else f.error="can't store attachment",e&&e(f),i.reject(f)}.bind(this)),i}},a.updateAttachment=function(a,c,d,e,f){if(n.getOnlineStatus()===n.ONLINE)return this._updateAttachment(a,c,d,function(){e&&e.apply(this,arguments)},function(a){f&&f.apply(this,arguments)});if(n.attachmentsStore){var g=this._getFilesFromForm(d),i=g[0],j=n.attachmentsStore.TYPE.UPDATE,k=new b;return 0>c&&(j=n.attachmentsStore.TYPE.ADD),n.attachmentsStore.store(this.url,c,a,i,j,function(b,d){var g={attachmentId:c,objectId:a,success:b};if(b){n.emit(n.events.ATTACHMENT_ENQUEUED,g),e&&e(g),k.resolve(g);var i=this._url.path+"/"+a+"/attachments/"+c,j=h("[href="+i+"]");j.attr("href",d.url)}else g.error="layer.updateAttachment::attachmentStore can't store attachment",f&&f(g),k.reject(g)}.bind(this)),k}},a.deleteAttachments=function(a,d,e,f){if(n.getOnlineStatus()===n.ONLINE){var g=this._deleteAttachments(a,d,function(){e&&e.apply(this,arguments)},function(a){f&&f.apply(this,arguments)});return g}if(n.attachmentsStore){var h=[];d.forEach(function(c){c=parseInt(c,10);var d=new b;if(0>c)n.attachmentsStore["delete"](c,function(b){var e={objectId:a,attachmentId:c,success:b};d.resolve(e)});else{var e=new Blob([],{type:"image/png"});n.attachmentsStore.store(this.url,c,a,e,n.attachmentsStore.TYPE.DELETE,function(b,e){var f={attachmentId:c,objectId:a,success:b};b?d.resolve(f):d.reject(f)}.bind(this))}h.push(d)},this);var i=c(h);return i.then(function(a){e&&e(a)}),i}},a.applyEdits=function(d,e,f,g,h){var i=[];if(n.getOnlineStatus()===n.ONLINE){var j=this._applyEdits(d,e,f,function(){n.emit(n.events.EDITS_SENT,arguments),g&&g.apply(this,arguments)},h);return j}var k=new b,l={addResults:[],updateResults:[],deleteResults:[]},m={};return d=d||[],d.forEach(function(a){var c=new b,d=this._getNextTempId();a.attributes[this.objectIdField]=d;var e=this;this._validateFeature(a,this.url,n._editStore.ADD).then(function(b){b.success?e._pushValidatedAddFeatureToDB(e,a,b.operation,l,d,c):c.resolve(!0)},function(a){c.reject(a)}),i.push(c)},this),e=e||[],e.forEach(function(a){var c=new b,d=a.attributes[this.objectIdField];m[d]=a;var e=this;this._validateFeature(a,this.url,n._editStore.UPDATE).then(function(b){b.success?e._pushValidatedUpdateFeatureToDB(e,a,b.operation,l,d,c):c.resolve(!0)},function(a){c.reject(a)}),i.push(c)},this),f=f||[],f.forEach(function(a){var c=new b,d=a.attributes[this.objectIdField],e=this;this._validateFeature(a,this.url,n._editStore.DELETE).then(function(b){b.success?e._pushValidatedDeleteFeatureToDB(e,a,b.operation,l,d,c):c.resolve(!0)},function(a){c.reject(a)}),i.push(c)},this),c(i).then(function(b){for(var c=!0,e=0;eg;g++){var h=a[g].toJson();if(f.push(h),g==e-1){var i=JSON.stringify(f),j=JSON.stringify(d);c(i,j);break}}},a.getFeatureLayerJSON=function(a,b){require(["esri/request"],function(c){var d=c({url:a,content:{f:"json"},handleAs:"json",callbackParamName:"callback"});d.then(function(a){b(!0,a)},function(a){b(!1,a.message)})})},a.setFeatureLayerJSONDataStore=function(a,b){n._editStore.pushFeatureLayerJSON(a,function(a,c){b(a,c)})},a.getFeatureLayerJSONDataStore=function(a){n._editStore.getFeatureLayerJSON(function(b,c){a(b,c)})},a.setPhantomLayerGraphics=function(a){var b=a.length;if(b>0)for(var c=0;b>c;c++){var d=new l(a[c]);this._phantomLayer.add(d)}},a.getPhantomLayerGraphics=function(b){for(var c=a._phantomLayer.graphics,d=a._phantomLayer.graphics.length,e=[],f=0;d>f;f++){var g=c[f].toJson();if(e.push(g),f==d-1){var h=JSON.stringify(e);b(h);break}}},a.getPhantomGraphicsArray=function(a){n._editStore.getPhantomGraphicsArray(function(b,c){"end"==c?a(!0,b):a(!1,c)})},a.getAttachmentsUsage=function(a){n.attachmentsStore.getUsage(function(b,c){a(b,c)})},a.resetAttachmentsDatabase=function(a){n.attachmentsStore.resetAttachmentsQueue(function(b,c){a(b,c)})},a.getUsage=function(a){n._editStore.getUsage(function(b,c){a(b,c)})},a.resetDatabase=function(a){n._editStore.resetEditsQueue(function(b,c){a(b,c)})},a.pendingEditsCount=function(a){n._editStore.pendingEditsCount(function(b){a(b)})},a.getFeatureDefinition=function(a,b,c,d){var e={layerDefinition:a,featureSet:{features:b,geometryType:c}};d(e)},a.getAllEditsArray=function(a){n._editStore.getAllEditsArray(function(b,c){"end"==c?a(!0,b):a(!1,c)})},a._pushFeatureCollections=function(){n._editStore._getFeatureCollections(function(b,c){var d={featureLayerUrl:a.url,featureLayerCollection:a.toJson()},e=[d],f={id:n._editStore.FEATURE_COLLECTION_ID,featureCollections:e};if(a.hasAttachments=d.featureLayerCollection.layerDefinition.hasAttachments,b){for(var g=0,h=0;hd;d++)n.attachmentsStore.replaceFeatureId(this.url,a[d],b[d],function(a){--f,g+=a?1:0,0===f&&c(g)}.bind(this))},a._nextTempId=-1,a._getNextTempId=function(){return this._nextTempId--},j(),c(m).then(function(b){0===b.length&&o?(this.ENABLE_FEATURECOLLECTION&&a._pushFeatureCollections(),d(!0,null)):b[0].success&&!o?this._editStore.getFeatureLayerJSON(function(b,c){b?(this._featureLayers[c.__featureLayerURL]=a,a.url=c.__featureLayerURL,this.ENABLE_FEATURECOLLECTION&&a._pushFeatureCollections(),d(!0,null)):d(!1,c)}.bind(this)):b[0].success&&(this.ENABLE_FEATURECOLLECTION&&a._pushFeatureCollections(),d(!0,null))}.bind(this))},goOffline:function(){this._onlineStatus=this.OFFLINE},goOnline:function(a){this._onlineStatus=this.RECONNECTING,this._replayStoredEdits(function(b,c){var d={success:b,responses:c};this._onlineStatus=this.ONLINE,null!=this.attachmentsStore?this._sendStoredAttachments(function(b,c,e){d.attachments={success:b,responses:c,dbResponses:e},a&&a(d)}.bind(this)):a&&a(d)}.bind(this))},getOnlineStatus:function(){return this._onlineStatus},serializeFeatureGraphicsArray:function(a,b){for(var c=a.length,d=[],e=0;c>e;e++){var f=a[e].toJson();if(d.push(f),e==c-1){var g=JSON.stringify(d);b(g);break}}},getFeatureCollections:function(a){this._editStore._isDBInit?this._editStore._getFeatureCollections(function(b,c){a(b,c)}):this._initializeDB(null,null).then(function(b){b.success&&this._editStore._getFeatureCollections(function(b,c){a(b,c)})}.bind(this),function(b){a(!1,b)})},getFeatureLayerJSONDataStore:function(a){this._editStore._isDBInit?this._editStore.getFeatureLayerJSON(function(b,c){a(b,c)}):this._initializeDB(null,null).then(function(b){b.success&&this._editStore.getFeatureLayerJSON(function(b,c){a(b,c)})}.bind(this),function(b){a(!1,b)})},_initializeDB:function(a,c){var d=new b,e=this._editStore;return e.dbName=this.DB_NAME,e.objectStoreName=this.DB_OBJECTSTORE_NAME,e.objectId=this.DB_UID,e.init(function(b,f){"object"==typeof a&&b===!0&&void 0!==a&&null!==a?(c&&(a.__featureLayerURL=c),e.pushFeatureLayerJSON(a,function(a,b){a?d.resolve({success:!0,error:null}):d.reject({success:!1,error:b})})):b?d.resolve({success:!0,error:null}):d.reject({success:!1,error:null})}),d},_checkFileAPIs:function(){return window.File&&window.FileReader&&window.FileList&&window.Blob?(XMLHttpRequest.prototype.sendAsBinary||(XMLHttpRequest.prototype.sendAsBinary=function(a){function b(a){return 255&a.charCodeAt(0)}var c=Array.prototype.map.call(a,b),d=new Uint8Array(c);this.send(d.buffer)}),!0):!1},_extendAjaxReq:function(a){a.sendAsBinary=XMLHttpRequest.prototype.sendAsBinary},_phantomSymbols:[],_getPhantomSymbol:function(a,b){if(0===this._phantomSymbols.length){var c=[0,255,0,255],d=1.5;this._phantomSymbols.point=[],this._phantomSymbols.point[this._editStore.ADD]=new n({type:"esriSMS",style:"esriSMSCross",xoffset:10,yoffset:10,color:[255,255,255,0],size:15,outline:{color:c,width:d,type:"esriSLS",style:"esriSLSSolid"}}),this._phantomSymbols.point[this._editStore.UPDATE]=new n({type:"esriSMS",style:"esriSMSCircle",xoffset:0,yoffset:0,color:[255,255,255,0],size:15,outline:{color:c,width:d,type:"esriSLS",style:"esriSLSSolid"}}),this._phantomSymbols.point[this._editStore.DELETE]=new n({type:"esriSMS",style:"esriSMSX",xoffset:0,yoffset:0,color:[255,255,255,0],size:15,outline:{color:c,width:d,type:"esriSLS",style:"esriSLSSolid"}}),this._phantomSymbols.multipoint=null,this._phantomSymbols.polyline=[],this._phantomSymbols.polyline[this._editStore.ADD]=new o({type:"esriSLS",style:"esriSLSSolid",color:c,width:d}),this._phantomSymbols.polyline[this._editStore.UPDATE]=new o({type:"esriSLS",style:"esriSLSSolid",color:c,width:d}),this._phantomSymbols.polyline[this._editStore.DELETE]=new o({type:"esriSLS",style:"esriSLSSolid",color:c,width:d}),this._phantomSymbols.polygon=[],this._phantomSymbols.polygon[this._editStore.ADD]=new p({type:"esriSFS",style:"esriSFSSolid",color:[255,255,255,0],outline:{type:"esriSLS",style:"esriSLSSolid",color:c,width:d}}),this._phantomSymbols.polygon[this._editStore.UPDATE]=new p({type:"esriSFS",style:"esriSFSSolid",color:[255,255,255,0],outline:{type:"esriSLS",style:"esriSLSDash",color:c,width:d}}),this._phantomSymbols.polygon[this._editStore.DELETE]=new p({type:"esriSFS",style:"esriSFSSolid",color:[255,255,255,0],outline:{type:"esriSLS",style:"esriSLSDot",color:c,width:d}})}return this._phantomSymbols[a.type][b]},_uploadAttachment:function(a){var c=new b,d=this._featureLayers[a.featureLayerUrl],e=new FormData;switch(e.append("attachment",a.file),a.type){case this.attachmentsStore.TYPE.ADD:d.addAttachment(a.objectId,e,function(b){c.resolve({attachmentResult:b,id:a.id})},function(a){c.reject(a)});break;case this.attachmentsStore.TYPE.UPDATE:e.append("attachmentId",a.id),d._sendAttachment("update",a.objectId,e,function(b){c.resolve({attachmentResult:b,id:a.id})},function(a){c.reject(a)});break;case this.attachmentsStore.TYPE.DELETE:d.deleteAttachments(a.objectId,[a.id],function(b){c.resolve({attachmentResult:b,id:a.id})},function(a){c.reject(a)})}return c.promise},_deleteAttachmentFromDB:function(a,c){var d=new b;return this.attachmentsStore["delete"](a,function(a){d.resolve({success:a,result:c})}),d},_cleanAttachmentsDB:function(a,b){var d=this,e=[],f=0;a.forEach(function(a){"object"==typeof a.attachmentResult&&a.attachmentResult.success?e.push(d._deleteAttachmentFromDB(a.id,null)):a.attachmentResult instanceof Array?a.attachmentResult.forEach(function(b){b.success?e.push(d._deleteAttachmentFromDB(a.id,null)):f++}):f++});var g=c(e);g.then(function(c){b(f>0?{errors:!0,attachmentsDBResults:c,uploadResults:a}:{errors:!1,attachmentsDBResults:c,uploadResults:a})})},_sendStoredAttachments:function(a){this.attachmentsStore.getAllAttachments(function(b){var d=this,e=[];b.forEach(function(a){var b=this._uploadAttachment(a);e.push(b)},this);var f=c(e);f.then(function(b){d._cleanAttachmentsDB(b,function(c){c.errors?a&&a(!1,b,c):a&&a(!0,b,c)})},function(b){a&&a(!1,b)})}.bind(this))},_replayStoredEdits:function(a){var b,d={},e=this,f=[],g=[],h=[],i=[],j=[],k=this._featureLayers,m=this.attachmentsStore,n=this._editStore;this._editStore.getAllEditsArray(function(o,p){if(o.length>0){j=o;for(var q=j.length,r=0;q>r;r++){b=k[j[r].layer],null==m&&b.hasAttachments,b._attachmentsStore=m,b.__onEditsComplete=b.onEditsComplete,b.onEditsComplete=function(){},f=[],g=[],h=[],i=[];var s=new l(j[r].graphic);switch(j[r].operation){case n.ADD:for(var t=0;t0&&(g.updateResults[0].success?(h.layer=g.layer,h.id=g.updateResults[0].objectId,d.push(h)):e.push(g)),g.deleteResults.length>0&&(g.deleteResults[0].success?(h.layer=g.layer,h.id=g.deleteResults[0].objectId,d.push(h)):e.push(g)),g.addResults.length>0&&(g.addResults[0].success?(h.layer=g.layer,h.id=g.tempId,d.push(h)):e.push(g))}for(var i={},j=d.length,k=0;j>k;k++)i[k]=this._updateDatabase(d[k]);var l=c(i);l.then(function(a){e.length>0?b(!1,a):b(!0,a)},function(a){b(!1,a)})}else b(!0,{})},_updateDatabase:function(a){var c=new b,d={};return d.attributes={},d.attributes[this.DB_UID]=a.id,this._editStore["delete"](a.layer,d,function(a,b){a?c.resolve({success:!0,error:null}):c.reject({success:!1,error:b})}.bind(this)),c.promise},getFeatureLayerJSON:function(a,b){require(["esri/request"],function(c){var d=c({url:a,content:{f:"json"},handleAs:"json",callbackParamName:"callback"});d.then(function(a){b(!0,a)},function(a){b(!1,a.message)})})},_internalApplyEdits:function(a,c,d,e,f,g){var h=this,i=new b;return a._applyEdits(e,f,g,function(b,e,f){if(a._phantomLayer.clear(),null!=a._attachmentsStore&&a.hasAttachments&&d.length>0){var g=b.map(function(a){return a.objectId});a._replaceFeatureIds(d,g,function(a){})}h._cleanDatabase(a,d,b,e,f).then(function(g){i.resolve({id:c,layer:a.url,tempId:d,addResults:b,updateResults:e,deleteResults:f,databaseResults:g,databaseErrors:null})},function(g){i.resolve({id:c,layer:a.url,tempId:d,addResults:b,updateResults:e,deleteResults:f,databaseResults:null,databaseErrors:g})})},function(b){a.onEditsComplete=a.__onEditsComplete,delete a.__onEditsComplete,i.reject(b)}),i.promise},_internalApplyEditsAll:function(a,c,d,e,f,g){var h=this,i=new b;return this._makeEditRequest(a.url,e,f,g,function(b,f,g){if(a._phantomLayer.clear(),null!=a._attachmentsStore&&a.hasAttachments&&d.length>0){var j=b.map(function(a){return a.objectId});a._replaceFeatureIds(d,j,function(e){i.resolve({id:c,layer:a.url,tempId:d,addResults:b,updateResults:f,deleteResults:g,syncError:null})})}if(b.length>0){var k=new l(e[0].geometry,null,e[0].attributes);a.add(k)}h._cleanDatabase(a,d,b,f,g).then(function(e){i.resolve({id:c,layer:a.url,tempId:d,addResults:b,updateResults:f,deleteResults:g,databaseResults:e,databaseErrors:null,syncError:null})},function(e){i.resolve({id:c,layer:a.url,tempId:d,addResults:b,updateResults:f,deleteResults:g,databaseResults:null,databaseErrors:e,syncError:e})})},function(b){a.onEditsComplete=a.__onEditsComplete,delete a.__onEditsComplete,i.reject(b)}),i.promise},_cleanDatabase:function(a,c,d,e,f){var g=new b,h=null;e.length>0&&e[0].success&&(h=e[0].objectId),f.length>0&&f[0].success&&(h=f[0].objectId),d.length>0&&d[0].success&&(h=c);var i={};return i.attributes={},i.attributes[this.DB_UID]=h,this._editStore["delete"](a.url,i,function(a,b){if(a){var c=this._editStore.PHANTOM_GRAPHIC_PREFIX+this._editStore._PHANTOM_PREFIX_TOKEN+i.attributes[this.DB_UID];this._editStore.deletePhantomGraphic(c,function(a,b){a?g.resolve({success:!0,error:null,id:c}):g.reject({success:!1,error:b,id:c})})}else g.reject({success:!1,error:b,id:c})}.bind(this)),g.promise},_makeEditRequest:function(a,b,c,d,f,g){var h="f=json",i="",k="",l="";if(b.length>0&&(i="&adds="+JSON.stringify(b)),c.length>0&&(e.forEach(c,function(a){a.hasOwnProperty("infoTemplate")&&delete a.infoTemplate},this),k="&updates="+JSON.stringify(c)),d.length>0){var m=d[0].attributes[this.DB_UID];l="&deletes="+m}var n=h+i+k+l;j.hasOwnProperty("id")&&j.id.hasOwnProperty("credentials")&&e.forEach(j.id.credentials,function(b){b.server===a.split("/",3).join("/")&&(n=n+"&token="+b.token)},this);var o=new XMLHttpRequest;o.open("POST",a+"/applyEdits",!0),o.setRequestHeader("Content-type","application/x-www-form-urlencoded"),o.onload=function(){if(200===o.status&&""!==o.responseText)try{var a=JSON.parse(this.response);f(a.addResults,a.updateResults,a.deleteResults)}catch(b){g("Unable to parse xhr response",o)}},o.onerror=function(a){g(a)},o.ontimeout=function(){g("xhr timeout error")},o.timeout=this._defaultXhrTimeout,o.send(n)},_parseResponsesArray:function(a){var c=new b,d=0;for(var e in a)a.hasOwnProperty(e)&&(a[e].addResults.map(function(a){a.success||d++}),a[e].updateResults.map(function(a){a.success||d++}),a[e].deleteResults.map(function(a){a.success||d++}));return d>0?c.resolve(!1):c.resolve(!0),c.promise}})}),"undefined"!=typeof O?O.esri.Edit={}:(O={},O.esri={Edit:{}}),O.esri.Edit.EditStore=function(){"use strict";this._db=null,this._isDBInit=!1,this.dbName="features_store",this.objectStoreName="features",this.objectId="objectid",this.ADD="add",this.UPDATE="update",this.DELETE="delete",this.FEATURE_LAYER_JSON_ID="feature-layer-object-1001",this.FEATURE_COLLECTION_ID="feature-collection-object-1001",this.PHANTOM_GRAPHIC_PREFIX="phantom-layer",this._PHANTOM_PREFIX_TOKEN="|@|",this.isSupported=function(){return window.indexedDB?!0:!1},this.pushEdit=function(a,b,c,d){var e={id:b+"/"+c.attributes[this.objectId],operation:a,layer:b,type:c.geometry.type,graphic:c.toJson()};if("undefined"==typeof c.attributes[this.objectId])d(!1,"editsStore.pushEdit() - failed to insert undefined objectId into database. Did you set offlineFeaturesManager.DB_UID? "+JSON.stringify(c.attributes));else{var f=this._db.transaction([this.objectStoreName],"readwrite");f.oncomplete=function(a){d(!0)},f.onerror=function(a){d(!1,a.target.error.message)};var g=f.objectStore(this.objectStoreName);g.put(e)}},this.pushFeatureLayerJSON=function(a,b){"object"!=typeof a&&b(!1,"dataObject type is not an object.");var c=this._db;a.id=this.FEATURE_LAYER_JSON_ID,this.getFeatureLayerJSON(function(d,e){var f;if(d&&"undefined"!=typeof e){f=c.transaction([this.objectStoreName],"readwrite").objectStore(this.objectStoreName);for(var g in a)a.hasOwnProperty(g)&&(e[g]=a[g]);var h=f.put(e);h.onsuccess=function(){b(!0,null)},h.onerror=function(a){b(!1,a)}}else{var i=c.transaction([this.objectStoreName],"readwrite");i.oncomplete=function(a){b(!0,null)},i.onerror=function(a){b(!1,a.target.error.message)},f=i.objectStore(this.objectStoreName);try{f.put(a)}catch(j){b(!1,JSON.stringify(j))}}}.bind(this))},this.getFeatureLayerJSON=function(a){var b=this._db.transaction([this.objectStoreName],"readwrite").objectStore(this.objectStoreName),c=b.get(this.FEATURE_LAYER_JSON_ID);c.onsuccess=function(){var b=c.result;"undefined"!=typeof b?a(!0,b):a(!1,"nothing found")},c.onerror=function(b){a(!1,b)}},this.deleteFeatureLayerJSON=function(a){var b=this._db,c=null,d=this,e=this.FEATURE_LAYER_JSON_ID;require(["dojo/Deferred"],function(f){c=new f,c.then(function(b){d.editExists(e).then(function(b){a(!1,{message:"object was not deleted."})},function(b){a(!0,{message:"id does not exist"})})},function(b){a(!1,{message:"id does not exist"})}),d.editExists(e).then(function(a){var f=b.transaction([d.objectStoreName],"readwrite").objectStore(d.objectStoreName),g=f["delete"](e);g.onsuccess=function(){c.resolve(!0)},g.onerror=function(a){c.reject({success:!1,error:a})}},function(a){c.reject({success:!1,message:a})}.bind(this))})},this.pushPhantomGraphic=function(a,b){var c=this._db,d=this.PHANTOM_GRAPHIC_PREFIX+this._PHANTOM_PREFIX_TOKEN+a.attributes[this.objectId],e={id:d,graphic:a.toJson()},f=c.transaction([this.objectStoreName],"readwrite");f.oncomplete=function(a){b(!0,null)},f.onerror=function(a){b(!1,a.target.error.message)};var g=f.objectStore(this.objectStoreName);g.put(e)},this.getPhantomGraphicsArray=function(a){var b=[];if(null!==this._db){var c=this.PHANTOM_GRAPHIC_PREFIX,d=this._db.transaction([this.objectStoreName]).objectStore(this.objectStoreName).openCursor();d.onsuccess=function(d){var e=d.target.result;e&&e.value&&e.value.id?(-1!=e.value.id.indexOf(c)&&b.push(e.value),e["continue"]()):a(b,"end")}.bind(this),d.onerror=function(b){a(null,b)}}else a(null,"no db")},this._getPhantomGraphicsArraySimple=function(a){var b=[];if(null!==this._db){var c=this.PHANTOM_GRAPHIC_PREFIX,d=this._db.transaction([this.objectStoreName]).objectStore(this.objectStoreName).openCursor();d.onsuccess=function(d){var e=d.target.result;e&&e.value&&e.value.id?(-1!=e.value.id.indexOf(c)&&b.push(e.value.id),e["continue"]()):a(b,"end")}.bind(this),d.onerror=function(b){a(null,b)}}else a(null,"no db")},this.deletePhantomGraphic=function(a,b){var c=this._db,d=null,e=this;require(["dojo/Deferred"],function(f){d=new f,e.editExists(a).then(function(f){d.then(function(c){e.editExists(a).then(function(a){b(!1,"item was not deleted")},function(a){b(!0,"item successfully deleted")})},function(a){b(!1,a)});var g=c.transaction([e.objectStoreName],"readwrite").objectStore(e.objectStoreName),h=g["delete"](a);h.onsuccess=function(){d.resolve(!0)},h.onerror=function(a){d.reject({success:!1,error:a})}},function(a){b(!1,"item doesn't exist in db")})})},this.resetLimitedPhantomGraphicsQueue=function(a,b){if(Object.keys(a).length>0){var c=this._db,d=0,e=c.transaction([this.objectStoreName],"readwrite"),f=e.objectStore(this.objectStoreName);f.onerror=function(){d++},e.oncomplete=function(){b(0===d?!0:!1)};for(var g in a)if(a.hasOwnProperty(g)){var h=a[g],i=this.PHANTOM_GRAPHIC_PREFIX+this._PHANTOM_PREFIX_TOKEN+h.id;h.updateResults.length>0&&h.updateResults[0].success&&f["delete"](i),h.deleteResults.length>0&&h.deleteResults[0].success&&f["delete"](i),h.addResults.length>0&&h.addResults[0].success&&f["delete"](i)}}else b(!0)},this.resetPhantomGraphicsQueue=function(a){var b=this._db;this._getPhantomGraphicsArraySimple(function(c){if(c!=[]){var d=0,e=b.transaction([this.objectStoreName],"readwrite"),f=e.objectStore(this.objectStoreName);f.onerror=function(){d++},e.oncomplete=function(){a(0===d?!0:!1)};for(var g=c.length,h=0;g>h;h++)f["delete"](c[h])}else a(!0)}.bind(this))},this.getEdit=function(a,b){var c=this._db.transaction([this.objectStoreName],"readwrite").objectStore(this.objectStoreName);if("undefined"==typeof a)return void b(!1,"id is undefined.");var d=c.get(a);d.onsuccess=function(){var c=d.result;c&&c.id==a?b(!0,c):b(!1,"Id not found")},d.onerror=function(a){b(!1,a)}},this.getAllEdits=function(a){if(null!==this._db){var b=this.FEATURE_LAYER_JSON_ID,c=this.FEATURE_COLLECTION_ID,d=this.PHANTOM_GRAPHIC_PREFIX,e=this._db.transaction([this.objectStoreName]).objectStore(this.objectStoreName).openCursor();e.onsuccess=function(e){var f=e.target.result;f&&f.hasOwnProperty("value")&&f.value.hasOwnProperty("id")?(f.value.id!==b&&f.value.id!==c&&-1==f.value.id.indexOf(d)&&a(f.value,null),f["continue"]()):a(null,"end")}.bind(this),e.onerror=function(b){a(null,b)}}else a(null,"no db")},this.getAllEditsArray=function(a){var b=[];if(null!==this._db){var c=this.FEATURE_LAYER_JSON_ID,d=this.FEATURE_COLLECTION_ID,e=this.PHANTOM_GRAPHIC_PREFIX,f=this._db.transaction([this.objectStoreName]).objectStore(this.objectStoreName).openCursor();f.onsuccess=function(f){var g=f.target.result;g&&g.value&&g.value.id?(g.value.id!==c&&g.value.id!==d&&-1==g.value.id.indexOf(e)&&b.push(g.value),g["continue"]()):a(b,"end")}.bind(this),f.onerror=function(b){a(null,b)}}else a(null,"no db")},this.updateExistingEdit=function(a,b,c,d){var e=this._db.transaction([this.objectStoreName],"readwrite").objectStore(this.objectStoreName),f=e.get(c.attributes[this.objectId]);f.onsuccess=function(){f.result;var g={id:b+"/"+c.attributes[this.objectId],operation:a,layer:b,graphic:c.toJson()},h=e.put(g);h.onsuccess=function(){d(!0)},h.onerror=function(a){d(!1,a)}}.bind(this)},this["delete"]=function(a,b,c){var d=this._db,e=null,f=this,g=a+"/"+b.attributes[this.objectId];require(["dojo/Deferred"],function(a){e=new a,f.editExists(g).then(function(a){e.then(function(a){f.editExists(g).then(function(a){c(!1)},function(a){c(!0)})},function(a){c(!1,a)});var b=d.transaction([f.objectStoreName],"readwrite").objectStore(f.objectStoreName),h=b["delete"](g);h.onsuccess=function(){e.resolve(!0)},h.onerror=function(a){e.reject({success:!1,error:a})}},function(a){c(!1)})})},this.resetEditsQueue=function(a){var b=this._db.transaction([this.objectStoreName],"readwrite").objectStore(this.objectStoreName).clear();b.onsuccess=function(b){setTimeout(function(){a(!0)},0)},b.onerror=function(b){a(!1,b)}},this.pendingEditsCount=function(a){var b=0,c=this.FEATURE_LAYER_JSON_ID,d=this.FEATURE_COLLECTION_ID,e=this.PHANTOM_GRAPHIC_PREFIX,f=this._db.transaction([this.objectStoreName],"readwrite"),g=f.objectStore(this.objectStoreName);g.openCursor().onsuccess=function(f){var g=f.target.result;g&&g.value&&g.value.id&&-1==g.value.id.indexOf(e)?(g.value.id!==c&&g.value.id!==d&&b++,g["continue"]()):a(b)}},this.editExists=function(a){var b=this._db,c=null,d=this;return require(["dojo/Deferred"],function(e){c=new e;var f=b.transaction([d.objectStoreName],"readwrite").objectStore(d.objectStoreName),g=f.get(a);g.onsuccess=function(){var b=g.result;b&&b.id==a?c.resolve({success:!0,error:null}):c.reject({success:!1,error:"objectId is not a match."})},g.onerror=function(a){c.reject({success:!1,error:a})}}),c},this.getUsage=function(a){var b=this.FEATURE_LAYER_JSON_ID,c=this.FEATURE_COLLECTION_ID,d=this.PHANTOM_GRAPHIC_PREFIX,e={sizeBytes:0,editCount:0},f=this._db.transaction([this.objectStoreName]).objectStore(this.objectStoreName).openCursor();f.onsuccess=function(f){var g=f.target.result;if(g&&g.value&&g.value.id){var h=g.value,i=JSON.stringify(h);e.sizeBytes+=i.length,-1==g.value.id.indexOf(d)&&g.value.id!==b&&g.value.id!==c&&(e.editCount+=1),g["continue"]()}else a(e,null)},f.onerror=function(b){a(null,b)}},this._pushFeatureCollections=function(a,b){ +var c=this._db.transaction([this.objectStoreName],"readwrite");c.oncomplete=function(a){b(!0)},c.onerror=function(a){b(!1,a.target.error.message)};var d=c.objectStore(this.objectStoreName);d.put(a)},this._getFeatureCollections=function(a){var b=this._db.transaction([this.objectStoreName],"readonly").objectStore(this.objectStoreName),c=b.get(this.FEATURE_COLLECTION_ID);c.onsuccess=function(){var b=c.result;"undefined"!=typeof b?a(!0,b):a(!1,null)},c.onerror=function(b){a(!1,b)}},this._serialize=function(a){var b=a.toJson(),c={attributes:b.attributes,geometry:b.geometry,infoTemplate:b.infoTemplate,symbol:b.symbol};return JSON.stringify(c)},this._deserialize=function(a){var b;return require(["esri/graphic"],function(c){b=new c(JSON.parse(a))}),b},this.init=function(a){var b=indexedDB.open(this.dbName,11);a=a||function(a){}.bind(this),b.onerror=function(b){a(!1,b.target.errorCode)}.bind(this),b.onupgradeneeded=function(a){var b=a.target.result;b.objectStoreNames.contains(this.objectStoreName)&&b.deleteObjectStore(this.objectStoreName),b.createObjectStore(this.objectStoreName,{keyPath:"id"})}.bind(this),b.onsuccess=function(b){this._db=b.target.result,this._isDBInit=!0,a(!0,null)}.bind(this)}},O.esri.Edit.AttachmentsStore=function(){"use strict";this._db=null,this.dbName="attachments_store",this.objectStoreName="attachments",this.TYPE={ADD:"add",UPDATE:"update",DELETE:"delete"},this.isSupported=function(){return window.indexedDB?!0:!1},this.store=function(a,b,c,d,e,f){try{e==this.TYPE.ADD||e==this.TYPE.UPDATE||e==this.TYPE.DELETE?this._readFile(d,function(g,h){if(g){var i={id:b,objectId:c,type:e,featureId:a+"/"+c,contentType:d.type,name:d.name,size:d.size,featureLayerUrl:a,content:h,file:d},j=this._db.transaction([this.objectStoreName],"readwrite");j.oncomplete=function(a){f(!0,i)},j.onerror=function(a){f(!1,a.target.error.message)};try{j.objectStore(this.objectStoreName).put(i)}catch(k){f(!1,k)}}else f(!1,h)}.bind(this)):f(!1,"attachmentsStore.store() Invalid type in the constructor!")}catch(g){f(!1,g.stack)}},this.retrieve=function(a,b){var c=this._db.transaction([this.objectStoreName]).objectStore(this.objectStoreName),d=c.get(a);d.onsuccess=function(a){var c=a.target.result;c?b(!0,c):b(!1,"not found")},d.onerror=function(a){b(!1,a)}},this.getAttachmentsByFeatureId=function(a,b,c){var d=a+"/"+b,e=[],f=this._db.transaction([this.objectStoreName]).objectStore(this.objectStoreName),g=f.index("featureId"),h=IDBKeyRange.only(d);g.openCursor(h).onsuccess=function(a){var b=a.target.result;b?(e.push(b.value),b["continue"]()):c(e)}},this.getAttachmentsByFeatureLayer=function(a,b){var c=[],d=this._db.transaction([this.objectStoreName]).objectStore(this.objectStoreName),e=d.index("featureLayerUrl"),f=IDBKeyRange.only(a);e.openCursor(f).onsuccess=function(a){var d=a.target.result;d?(c.push(d.value),d["continue"]()):b(c)}},this.getAllAttachments=function(a){var b=[],c=this._db.transaction([this.objectStoreName]).objectStore(this.objectStoreName);c.openCursor().onsuccess=function(c){var d=c.target.result;d?(b.push(d.value),d["continue"]()):a(b)}},this.deleteAttachmentsByFeatureId=function(a,b,c){var d=a+"/"+b,e=this._db.transaction([this.objectStoreName],"readwrite").objectStore(this.objectStoreName),f=e.index("featureId"),g=IDBKeyRange.only(d),h=0;f.openCursor(g).onsuccess=function(a){var b=a.target.result;b?(e["delete"](b.primaryKey),h++,b["continue"]()):setTimeout(function(){c(h)},0)}.bind(this)},this["delete"]=function(a,b){this.retrieve(a,function(c,d){if(!c)return void b(!1,"attachment "+a+" not found");var e=this._db.transaction([this.objectStoreName],"readwrite").objectStore(this.objectStoreName)["delete"](a);e.onsuccess=function(a){setTimeout(function(){b(!0)},0)},e.onerror=function(a){b(!1,a)}}.bind(this))},this.deleteAll=function(a){this.getAllAttachments(function(b){var c=this._db.transaction([this.objectStoreName],"readwrite").objectStore(this.objectStoreName).clear();c.onsuccess=function(b){setTimeout(function(){a(!0)},0)},c.onerror=function(b){a(!1,b)}}.bind(this))},this.replaceFeatureId=function(a,b,c,d){var e=a+"/"+b,f=this._db.transaction([this.objectStoreName],"readwrite").objectStore(this.objectStoreName),g=f.index("featureId"),h=IDBKeyRange.only(e),i=0;g.openCursor(h).onsuccess=function(b){var e=b.target.result;if(e){var g=a+"/"+c,h=e.value;h.featureId=g,h.objectId=c,f.put(h),i++,e["continue"]()}else setTimeout(function(){d(i)},1)}},this.getUsage=function(a){var b={sizeBytes:0,attachmentCount:0},c=this._db.transaction([this.objectStoreName]).objectStore(this.objectStoreName).openCursor();c.onsuccess=function(c){var d=c.target.result;if(d){var e=d.value,f=JSON.stringify(e);b.sizeBytes+=f.length,b.attachmentCount+=1,d["continue"]()}else a(b,null)}.bind(this),c.onerror=function(b){a(null,b)}},this.resetAttachmentsQueue=function(a){var b=this._db.transaction([this.objectStoreName],"readwrite").objectStore(this.objectStoreName).clear();b.onsuccess=function(b){setTimeout(function(){a(!0)},0)},b.onerror=function(b){a(!1,b)}},this._readFile=function(a,b){var c=new FileReader;c.onload=function(a){b(!0,a.target.result)},c.onerror=function(a){b(!1,a.target.result)},c.readAsBinaryString(a)},this.init=function(a){var b=indexedDB.open(this.dbName,12);a=a||function(a){}.bind(this),b.onerror=function(b){a(!1,b.target.errorCode)}.bind(this),b.onupgradeneeded=function(a){var b=a.target.result;b.objectStoreNames.contains(this.objectStoreName)&&b.deleteObjectStore(this.objectStoreName);var c=b.createObjectStore(this.objectStoreName,{keyPath:"id"});c.createIndex("featureId","featureId",{unique:!1}),c.createIndex("featureLayerUrl","featureLayerUrl",{unique:!1})}.bind(this),b.onsuccess=function(b){this._db=b.target.result,a(!0)}.bind(this)}}; \ No newline at end of file diff --git a/dist/offline-edit-src.js b/dist/offline-edit-src.js index ca3cb4d..e6fb21f 100644 --- a/dist/offline-edit-src.js +++ b/dist/offline-edit-src.js @@ -1,4 +1,4 @@ -/*! offline-editor-js - v2.11.0 - 2015-07-30 +/*! offline-editor-js - v2.12.0 - 2015-08-07 * Copyright (c) 2015 Environmental Systems Research Institute, Inc. * Apache License*/ /*jshint -W030 */ @@ -12,6 +12,7 @@ define([ "dojo/dom-style", "dojo/query", "esri/config", + "esri/kernel", "esri/layers/GraphicsLayer", "esri/graphic", "esri/request", @@ -20,7 +21,7 @@ define([ "esri/symbols/SimpleFillSymbol", "esri/urlUtils"], function (Evented, Deferred, all, declare, array, domAttr, domStyle, query, - esriConfig, GraphicsLayer, Graphic, esriRequest, SimpleMarkerSymbol, SimpleLineSymbol, SimpleFillSymbol, urlUtils) { + esriConfig, kernel, GraphicsLayer, Graphic, esriRequest, SimpleMarkerSymbol, SimpleLineSymbol, SimpleFillSymbol, urlUtils) { "use strict"; return declare("O.esri.Edit.OfflineFeaturesManager", [Evented], { @@ -2107,6 +2108,11 @@ define([ a = "&adds=" + JSON.stringify((adds)); } if(updates.length > 0) { + array.forEach(updates, function(update){ + if(update.hasOwnProperty("infoTemplate")){ // if the update has an infoTemplate attached, + delete update.infoTemplate; // delete it to reduce payload size. + } + }, this); u = "&updates=" + JSON.stringify(updates); } if(deletes.length > 0) { @@ -2116,6 +2122,16 @@ define([ var params = f + a + u + d; + if(kernel.hasOwnProperty("id")){ // if there are credentials stored + if(kernel.id.hasOwnProperty("credentials")){ // within the kernel object, + array.forEach(kernel.id.credentials, function(credential){ // go thru all of them, + if(credential.server === url.split("/", 3).join("/")){ // find the credential that lines up with the server our feature is on, + params = params + "&token=" + credential.token; // and then append the token to the params. + } + }, this); + } + } + var req = new XMLHttpRequest(); req.open("POST", url + "/applyEdits", true); req.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); @@ -2128,14 +2144,15 @@ define([ callback(obj.addResults, obj.updateResults, obj.deleteResults); } catch(err) { - errback("Unable to parse xhr response"); + console.error("EDIT REQUEST REPONSE WAS NOT SUCCESSFUL:", req); + errback("Unable to parse xhr response", req); } } }; req.onerror = function(e) { - console.log("_makeEditRequest failed: " + e); + console.error("_makeEditRequest failed: " + e); errback(e); }; req.ontimeout = function() { diff --git a/dist/offline-tiles-advanced-min.js b/dist/offline-tiles-advanced-min.js index 61bab11..edca8c0 100644 --- a/dist/offline-tiles-advanced-min.js +++ b/dist/offline-tiles-advanced-min.js @@ -1,5 +1,5 @@ -/*! offline-editor-js - v2.11.0 - 2015-07-30 +/*! offline-editor-js - v2.12.0 - 2015-08-07 * Copyright (c) 2015 Environmental Systems Research Institute, Inc. * Apache License*/ -define(["dojo/query","dojo/request","dojo/_base/declare","esri/layers/LOD","esri/geometry/Point","esri/geometry/Extent","esri/layers/TileInfo","esri/SpatialReference","esri/geometry/Polygon","esri/layers/TiledMapServiceLayer"],function(a,b,c,d,e,f,g,h,i,j){"use strict";return c("O.esri.Tiles.OfflineTileEnablerLayer",[j],{tileInfo:null,_imageType:"",_level:null,_minZoom:null,_maxZoom:null,_tilesCore:null,constructor:function(a,b,c,d){this._isLocalStorage()===!1&&(alert("OfflineTiles Library not supported on this browser."),b(!1)),void 0===d||null===d?(this.DB_NAME="offline_tile_store",this.DB_OBJECTSTORE_NAME="tilepath"):(this.DB_NAME=d.dbName,this.DB_OBJECTSTORE_NAME=d.objectStoreName),this._tilesCore=new O.esri.Tiles.TilesCore,Array.prototype.sortNumber=function(){return this.sort(function(a,b){return a-b})},this._self=this,this._lastTileUrl="",this._imageType="",this._getTileUrl=this.getTileUrl;var e=!0;return("undefined"!=typeof c||null!=c)&&(e=c),this.showBlankTiles=!0,this.offline={online:e,store:new O.esri.Tiles.TilesStore,proxyPath:null},this.offline.store.isSupported()?(this.offline.store.dbName=this.DB_NAME,this.offline.store.objectStoreName=this.DB_OBJECTSTORE_NAME,this.offline.store.init(function(c){c&&this._getTileInfoPrivate(a,function(a){void 0===localStorage.__offlineTileInfo&&a!==!1&&(localStorage.__offlineTileInfo=a),this.offline.online===!1&&a===!1&&void 0!==localStorage.__offlineTileInfo?a=localStorage.__offlineTileInfo:this.offline.online===!1&&a===!1&&void 0===localStorage.__offlineTileInfo&&alert("There was a problem retrieving tiled map info in OfflineTilesEnablerLayer."),this._tilesCore._parseGetTileInfo(a,function(a){this.layerInfos=a.resultObj.layers,this.minScale=a.resultObj.minScale,this.maxScale=a.resultObj.maxScale,this.tileInfo=a.tileInfo,this._imageType=this.tileInfo.format.toLowerCase(),this.fullExtent=a.fullExtent,this.spatialReference=this.tileInfo.spatialReference,this.initialExtent=a.initExtent,this.loaded=!0,this.onLoad(this),b(!0)}.bind(this._self))}.bind(this._self))}.bind(this._self)),void 0):b(!1,"indexedDB not supported")},getTileUrl:function(b,c,d){this._level=b;var e=this.url+"/tile/"+b+"/"+c+"/"+d;if(this.offline.online)return this._lastTileUrl=e,e;e=e.split("?")[0];var f="void:/"+b+"/"+c+"/"+d,g=null;return this._tilesCore._getTiles(g,this._imageType,e,f,this.offline.store,a,this.showBlankTiles),f},getBasemapLayer:function(a){var b=a.layerIds[0];return a.getLayer(b)},getLevelEstimation:function(a,b,c){var d=new O.esri.Tiles.TilingScheme(this),e=d.getAllCellIdsInExtent(a,b),f={level:b,tileCount:e.length,sizeBytes:e.length*c};return f},getLevel:function(){return this._level},getMaxZoom:function(a){null==this._maxZoom&&(this._maxZoom=this.tileInfo.lods[this.tileInfo.lods.length-1].level),a(this._maxZoom)},getMinZoom:function(a){null==this._minZoom&&(this._minZoom=this.tileInfo.lods[0].level),a(this._minZoom)},getMinMaxLOD:function(a,b){var c={},d=this.getMap(),e=d.getLevel()+a,f=d.getLevel()+b;return null!=this._maxZoom&&null!=this._minZoom?(c.max=Math.min(this._maxZoom,f),c.min=Math.max(this._minZoom,e)):(this.getMinZoom(function(a){c.min=Math.max(a,e)}),this.getMaxZoom(function(a){c.max=Math.min(a,f)})),c},prepareForOffline:function(a,b,c,d){this._tilesCore._createCellsForOffline(this,a,b,c,function(a){this._doNextTile(0,a,d)}.bind(this))},goOffline:function(){this.offline.online=!1},goOnline:function(){this.offline.online=!0,this.refresh()},isOnline:function(){return this.offline.online},deleteAllTiles:function(a){var b=this.offline.store;b.deleteAll(a)},getOfflineUsage:function(a){var b=this.offline.store;b.usedSpace(a)},getTilePolygons:function(a){this._tilesCore._getTilePolygons(this.offline.store,this.url,this,a)},saveToFile:function(a,b){this._tilesCore._saveToFile(a,this.offline.store,b)},loadFromFile:function(a,b){this._tilesCore._loadFromFile(a,this.offline.store,b)},estimateTileSize:function(a){this._tilesCore._estimateTileSize(b,this._lastTileUrl,this.offline.proxyPath,a)},getExtentBuffer:function(a,b){return b.xmin-=a,b.ymin-=a,b.xmax+=a,b.ymax+=a,b},getTileUrlsByExtent:function(a,b){var c=new O.esri.Tiles.TilingScheme(this),d=c.getAllCellIdsInExtent(a,b),e=[];return d.forEach(function(a){e.push(this.url+"/"+b+"/"+a[1]+"/"+a[0])}.bind(this)),e},_doNextTile:function(a,b,c){var d=b[a],e=this._getTileUrl(d.level,d.row,d.col);this._tilesCore._storeTile(e,this.offline.proxyPath,this.offline.store,function(e,f){e||(f={cell:d,msg:f});var g=c({countNow:a,countMax:b.length,cell:d,error:f,finishedDownloading:!1});g||a===b.length-1?c({finishedDownloading:!0,cancelRequested:g}):this._doNextTile(a+1,b,c)}.bind(this))},_isLocalStorage:function(){var a="test";try{return localStorage.setItem(a,a),localStorage.removeItem(a),!0}catch(b){return!1}},_getTileInfoPrivate:function(a,b){var c=new XMLHttpRequest,d=null!=this.offline.proxyPath?this.offline.proxyPath+"?"+a+"?f=pjson":a+"?f=pjson";c.open("GET",d,!0),c.onload=function(){b(200===c.status&&""!==c.responseText?this.response:!1)},c.onerror=function(a){b(!1)},c.send(null)}})}),"undefined"!=typeof O?O.esri.Tiles={}:(O={},O.esri={Tiles:{}}),O.esri.Tiles.Base64Utils={},O.esri.Tiles.Base64Utils.outputTypes={Base64:0,Hex:1,String:2,Raw:3},O.esri.Tiles.Base64Utils.addWords=function(a,b){var c=(65535&a)+(65535&b),d=(a>>16)+(b>>16)+(c>>16);return d<<16|65535&c},O.esri.Tiles.Base64Utils.stringToWord=function(a){for(var b=8,c=(1<e;e+=b)d[e>>5]|=(a.charCodeAt(e/b)&c)<e;e+=b)d.push(String.fromCharCode(a[e>>5]>>>e%32&c));return d.join("")},O.esri.Tiles.Base64Utils.wordToHex=function(a){for(var b="0123456789abcdef",c=[],d=0,e=4*a.length;e>d;d++)c.push(b.charAt(a[d>>2]>>d%4*8+4&15)+b.charAt(a[d>>2]>>d%4*8&15));return c.join("")},O.esri.Tiles.Base64Utils.wordToBase64=function(a){for(var b="=",c="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",d=[],e=0,f=4*a.length;f>e;e+=3)for(var g=(a[e>>2]>>8*(e%4)&255)<<16|(a[e+1>>2]>>8*((e+1)%4)&255)<<8|a[e+2>>2]>>8*((e+2)%4)&255,h=0;4>h;h++)d.push(8*e+6*h>32*a.length?b:c.charAt(g>>6*(3-h)&63));return d.join("")},/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ -O.esri.Tiles.saveAs=function(a){"use strict";var b=a.document,c=function(){return a.URL||a.webkitURL||a},d=a.URL||a.webkitURL||a,e=b.createElementNS("http://www.w3.org/1999/xhtml","a"),f=!a.externalHost&&"download"in e,g=a.webkitRequestFileSystem,h=a.requestFileSystem||g||a.mozRequestFileSystem,i=function(b){(a.setImmediate||a.setTimeout)(function(){throw b},0)},j="application/octet-stream",k=0,l=[],m=function(){for(var a=l.length;a--;){var b=l[a];"string"==typeof b?d.revokeObjectURL(b):b.remove()}l.length=0},n=function(a,b,c){b=[].concat(b);for(var d=b.length;d--;){var e=a["on"+b[d]];if("function"==typeof e)try{e.call(a,c||a)}catch(f){i(f)}}},o=function(d,i){var m,o,p,q=this,r=d.type,s=!1,t=function(){var a=c().createObjectURL(d);return l.push(a),a},u=function(){n(q,"writestart progress write writeend".split(" "))},v=function(){(s||!m)&&(m=t(d)),o?o.location.href=m:window.open(m,"_blank"),q.readyState=q.DONE,u()},w=function(a){return function(){return q.readyState!==q.DONE?a.apply(this,arguments):void 0}},x={create:!0,exclusive:!1};if(q.readyState=q.INIT,i||(i="download"),f){m=t(d),b=a.document,e=b.createElementNS("http://www.w3.org/1999/xhtml","a"),e.href=m,e.download=i;var y=b.createEvent("MouseEvents");return y.initMouseEvent("click",!0,!1,a,0,0,0,0,0,!1,!1,!1,!1,0,null),e.dispatchEvent(y),q.readyState=q.DONE,void u()}return a.chrome&&r&&r!==j&&(p=d.slice||d.webkitSlice,d=p.call(d,0,d.size,j),s=!0),g&&"download"!==i&&(i+=".download"),(r===j||g)&&(o=a),h?(k+=d.size,void h(a.TEMPORARY,k,w(function(a){a.root.getDirectory("saved",x,w(function(a){var b=function(){a.getFile(i,x,w(function(a){a.createWriter(w(function(b){b.onwriteend=function(b){o.location.href=a.toURL(),l.push(a),q.readyState=q.DONE,n(q,"writeend",b)},b.onerror=function(){var a=b.error;a.code!==a.ABORT_ERR&&v()},"writestart progress write abort".split(" ").forEach(function(a){b["on"+a]=q["on"+a]}),b.write(d),q.abort=function(){b.abort(),q.readyState=q.DONE},q.readyState=q.WRITING}),v)}),v)};a.getFile(i,{create:!1},w(function(a){a.remove(),b()}),w(function(a){a.code===a.NOT_FOUND_ERR?b():v()}))}),v)}),v)):void v()},p=o.prototype,q=function(a,b){return new o(a,b)};return p.abort=function(){var a=this;a.readyState=a.DONE,n(a,"abort")},p.readyState=p.INIT=0,p.WRITING=1,p.DONE=2,p.error=p.onwritestart=p.onprogress=p.onwrite=p.onabort=p.onerror=p.onwriteend=null,a.addEventListener("unload",m,!1),q}(this.self||this.window||this.content),O.esri.Tiles.TilesCore=function(){this._getTiles=function(a,b,c,d,e,f,g){e.retrieve(c,function(c,e){a=f("img[src="+d+"]")[0];var h;return c?(a.style.borderColor="blue",h="data:image/"+b+";base64,"+e.img):g?(a.style.borderColor="green",h="data:image/png;base64,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pmk0TROPj48Hn3l4eIimaSJN06O3A4NJwDMxm82ibdtXo4D5fB6r1Sp+//4dz8/Pw5H+6ekpdrtdJEkS8/n8S/9f713ie3vaceo9x557QAB451Sgfyin34HKshweunk5HzAej2MymXz5+f9nbjJyI9L39Wu5XP55+XQZ39uxR4Z3u90wSXjqEV0wAjhjx47oaZq63Me/ZhIQBAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEAAbAJQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEAvqe/BwCeKjUweoA8pQAAAABJRU5ErkJggg=="):h="data:image/png;base64,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AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDDwAwMBPAABGrpAUwAAAABJRU5ErkJggg==",a.style.visibility="visible",a.src=h,""})},this._storeTile=function(a,b,c,d){a=a.split("?")[0];var e=b?b+"?"+a:a,f=new XMLHttpRequest;f.open("GET",e,!0),f.overrideMimeType("text/plain; charset=x-user-defined"),f.onload=function(){if(200===f.status&&""!==f.responseText){var b=O.esri.Tiles.Base64Utils.wordToBase64(O.esri.Tiles.Base64Utils.stringToWord(this.responseText)),g={url:a,img:b};c.store(g,d)}else d(!1,f.status+" "+f.statusText+": "+f.response+" when downloading "+e)},f.onerror=function(a){d(!1,a)},f.send(null)},this._createCellsForOffline=function(a,b,c,d,e){for(var f=new O.esri.Tiles.TilingScheme(a),g=[],h=b;c>=h;h++){var i=f.getAllCellIdsInExtent(d,h);if(i.forEach(function(a){g.push({level:h,row:a[1],col:a[0]})}),g.length>5e3&&h!==c)break}e(g)},this._saveToFile=function(a,b,c){var d=[];d.push("url,img"),b.getAllTiles(function(b,e,f){if("end"===f){var g=new Blob([d.join("\r\n")],{type:"text/plain;charset=utf-8"}),h=O.esri.Tiles.saveAs(g,a);if(h.readyState===h.DONE)return h.error?c(!1,"Error saving file "+a):c(!0,"Saved "+(d.length-1)+" tiles ("+Math.floor(g.size/1024/1024*100)/100+" Mb) into "+a);h.onerror=function(){c(!1,"Error saving file "+a)},h.onwriteend=function(){c(!0,"Saved "+(d.length-1)+" tiles ("+Math.floor(g.size/1024/1024*100)/100+" Mb) into "+a)}}else d.push(b+","+e)})},this._estimateTileSize=function(a,b,c,d){if(b){var e=c?c+"?"+b:b;a.get(e,{handleAs:"text/plain; charset=x-user-defined",headers:{"X-Requested-With":""},timeout:2e3}).then(function(a){var b=O.esri.Tiles.Base64Utils.wordToBase64(O.esri.Tiles.Base64Utils.stringToWord(a));d(b.length+e.length,null)},function(a){d(null,a)})}else d(0/0)},this._loadFromFile=function(a,b,c){if(window.File&&window.FileReader&&window.FileList&&window.Blob){var d=new FileReader;d.onload=function(d){var e,f,g=d.target.result,h=g.split("\r\n"),i=0;if("url,img"!==h[0])return c(!1,"File "+a.name+" doesn't contain tiles that can be loaded");for(var j=1;j=c;c++)for(d=i;j>=d;d++)k.push([c,d]);return k}}; \ No newline at end of file +define(["dojo/query","dojo/request","dojo/_base/declare","esri/layers/LOD","esri/geometry/Point","esri/geometry/Extent","esri/layers/TileInfo","esri/SpatialReference","esri/geometry/Polygon","esri/layers/TiledMapServiceLayer"],function(a,b,c,d,e,f,g,h,i,j){"use strict";return c("O.esri.Tiles.OfflineTileEnablerLayer",[j],{tileInfo:null,_imageType:"",_level:null,_minZoom:null,_maxZoom:null,_tilesCore:null,constructor:function(a,b,c,d){this._isLocalStorage()===!1&&(alert("OfflineTiles Library not supported on this browser."),b(!1)),void 0===d||null===d?(this.DB_NAME="offline_tile_store",this.DB_OBJECTSTORE_NAME="tilepath"):(this.DB_NAME=d.dbName,this.DB_OBJECTSTORE_NAME=d.objectStoreName),this._tilesCore=new O.esri.Tiles.TilesCore,Array.prototype.sortNumber=function(){return this.sort(function(a,b){return a-b})},this._self=this,this._lastTileUrl="",this._imageType="",this._getTileUrl=this.getTileUrl;var e=!0;return("undefined"!=typeof c||null!=c)&&(e=c),this.showBlankTiles=!0,this.offline={online:e,store:new O.esri.Tiles.TilesStore,proxyPath:null},this.offline.store.isSupported()?(this.offline.store.dbName=this.DB_NAME,this.offline.store.objectStoreName=this.DB_OBJECTSTORE_NAME,this.offline.store.init(function(c){c&&this._getTileInfoPrivate(a,function(a){void 0===localStorage.__offlineTileInfo&&a!==!1&&(localStorage.__offlineTileInfo=a),this.offline.online===!1&&a===!1&&void 0!==localStorage.__offlineTileInfo?a=localStorage.__offlineTileInfo:this.offline.online===!1&&a===!1&&void 0===localStorage.__offlineTileInfo&&alert("There was a problem retrieving tiled map info in OfflineTilesEnablerLayer."),this._tilesCore._parseGetTileInfo(a,function(a){this.layerInfos=a.resultObj.layers,this.minScale=a.resultObj.minScale,this.maxScale=a.resultObj.maxScale,this.tileInfo=a.tileInfo,this._imageType=this.tileInfo.format.toLowerCase(),this.fullExtent=a.fullExtent,this.spatialReference=this.tileInfo.spatialReference,this.initialExtent=a.initExtent,this.loaded=!0,this.onLoad(this),b(!0)}.bind(this._self))}.bind(this._self))}.bind(this._self)),void 0):b(!1,"indexedDB not supported")},getTileUrl:function(b,c,d){this._level=b;var e=this.url+"/tile/"+b+"/"+c+"/"+d;if(this.offline.online)return this._lastTileUrl=e,e;e=e.split("?")[0];var f="void:/"+b+"/"+c+"/"+d,g=null;return this._tilesCore._getTiles(g,this._imageType,e,f,this.offline.store,a,this.showBlankTiles),f},getBasemapLayer:function(a){var b=a.layerIds[0];return a.getLayer(b)},getLevelEstimation:function(a,b,c){var d=new O.esri.Tiles.TilingScheme(this),e=d.getAllCellIdsInExtent(a,b),f={level:b,tileCount:e.length,sizeBytes:e.length*c};return f},getLevel:function(){return this._level},getMaxZoom:function(a){null==this._maxZoom&&(this._maxZoom=this.tileInfo.lods[this.tileInfo.lods.length-1].level),a(this._maxZoom)},getMinZoom:function(a){null==this._minZoom&&(this._minZoom=this.tileInfo.lods[0].level),a(this._minZoom)},getMinMaxLOD:function(a,b){var c={},d=this.getMap(),e=d.getLevel()+a,f=d.getLevel()+b;return null!=this._maxZoom&&null!=this._minZoom?(c.max=Math.min(this._maxZoom,f),c.min=Math.max(this._minZoom,e)):(this.getMinZoom(function(a){c.min=Math.max(a,e)}),this.getMaxZoom(function(a){c.max=Math.min(a,f)})),c},prepareForOffline:function(a,b,c,d){this._tilesCore._createCellsForOffline(this,a,b,c,function(a){this._doNextTile(0,a,d)}.bind(this))},goOffline:function(){this.offline.online=!1},goOnline:function(){this.offline.online=!0,this.refresh()},isOnline:function(){return this.offline.online},deleteAllTiles:function(a){var b=this.offline.store;b.deleteAll(a)},getOfflineUsage:function(a){var b=this.offline.store;b.usedSpace(a)},getTilePolygons:function(a){this._tilesCore._getTilePolygons(this.offline.store,this.url,this,a)},saveToFile:function(a,b){this._tilesCore._saveToFile(a,this.offline.store,b)},loadFromFile:function(a,b){this._tilesCore._loadFromFile(a,this.offline.store,b)},estimateTileSize:function(a){this._tilesCore._estimateTileSize(b,this._lastTileUrl,this.offline.proxyPath,a)},getExtentBuffer:function(a,b){return b.xmin-=a,b.ymin-=a,b.xmax+=a,b.ymax+=a,b},getTileUrlsByExtent:function(a,b){var c=new O.esri.Tiles.TilingScheme(this),d=c.getAllCellIdsInExtent(a,b),e=[];return d.forEach(function(a){e.push(this.url+"/"+b+"/"+a[1]+"/"+a[0])}.bind(this)),e},_doNextTile:function(a,b,c){var d=b[a],e=this._getTileUrl(d.level,d.row,d.col);this._tilesCore._storeTile(e,this.offline.proxyPath,this.offline.store,function(e,f){e||(f={cell:d,msg:f});var g=c({countNow:a,countMax:b.length,cell:d,error:f,finishedDownloading:!1});g||a===b.length-1?c({finishedDownloading:!0,cancelRequested:g}):this._doNextTile(a+1,b,c)}.bind(this))},_isLocalStorage:function(){var a="test";try{return localStorage.setItem(a,a),localStorage.removeItem(a),!0}catch(b){return!1}},_getTileInfoPrivate:function(a,b){var c=new XMLHttpRequest,d=null!=this.offline.proxyPath?this.offline.proxyPath+"?"+a+"?f=pjson":a+"?f=pjson";c.open("GET",d,!0),c.onload=function(){b(200===c.status&&""!==c.responseText?this.response:!1)},c.onerror=function(a){b(!1)},c.send(null)}})}),"undefined"!=typeof O?O.esri.Tiles={}:(O={},O.esri={Tiles:{}}),O.esri.Tiles.Base64Utils={},O.esri.Tiles.Base64Utils.outputTypes={Base64:0,Hex:1,String:2,Raw:3},O.esri.Tiles.Base64Utils.addWords=function(a,b){var c=(65535&a)+(65535&b),d=(a>>16)+(b>>16)+(c>>16);return d<<16|65535&c},O.esri.Tiles.Base64Utils.stringToWord=function(a){for(var b=8,c=(1<e;e+=b)d[e>>5]|=(a.charCodeAt(e/b)&c)<e;e+=b)d.push(String.fromCharCode(a[e>>5]>>>e%32&c));return d.join("")},O.esri.Tiles.Base64Utils.wordToHex=function(a){for(var b="0123456789abcdef",c=[],d=0,e=4*a.length;e>d;d++)c.push(b.charAt(a[d>>2]>>d%4*8+4&15)+b.charAt(a[d>>2]>>d%4*8&15));return c.join("")},O.esri.Tiles.Base64Utils.wordToBase64=function(a){for(var b="=",c="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",d=[],e=0,f=4*a.length;f>e;e+=3)for(var g=(a[e>>2]>>8*(e%4)&255)<<16|(a[e+1>>2]>>8*((e+1)%4)&255)<<8|a[e+2>>2]>>8*((e+2)%4)&255,h=0;4>h;h++)8*e+6*h>32*a.length?d.push(b):d.push(c.charAt(g>>6*(3-h)&63));return d.join("")},/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ +O.esri.Tiles.saveAs=function(a){"use strict";var b=a.document,c=function(){return a.URL||a.webkitURL||a},d=a.URL||a.webkitURL||a,e=b.createElementNS("http://www.w3.org/1999/xhtml","a"),f=!a.externalHost&&"download"in e,g=a.webkitRequestFileSystem,h=a.requestFileSystem||g||a.mozRequestFileSystem,i=function(b){(a.setImmediate||a.setTimeout)(function(){throw b},0)},j="application/octet-stream",k=0,l=[],m=function(){for(var a=l.length;a--;){var b=l[a];"string"==typeof b?d.revokeObjectURL(b):b.remove()}l.length=0},n=function(a,b,c){b=[].concat(b);for(var d=b.length;d--;){var e=a["on"+b[d]];if("function"==typeof e)try{e.call(a,c||a)}catch(f){i(f)}}},o=function(d,i){var m,o,p,q=this,r=d.type,s=!1,t=function(){var a=c().createObjectURL(d);return l.push(a),a},u=function(){n(q,"writestart progress write writeend".split(" "))},v=function(){(s||!m)&&(m=t(d)),o?o.location.href=m:window.open(m,"_blank"),q.readyState=q.DONE,u()},w=function(a){return function(){return q.readyState!==q.DONE?a.apply(this,arguments):void 0}},x={create:!0,exclusive:!1};if(q.readyState=q.INIT,i||(i="download"),f){m=t(d),b=a.document,e=b.createElementNS("http://www.w3.org/1999/xhtml","a"),e.href=m,e.download=i;var y=b.createEvent("MouseEvents");return y.initMouseEvent("click",!0,!1,a,0,0,0,0,0,!1,!1,!1,!1,0,null),e.dispatchEvent(y),q.readyState=q.DONE,void u()}return a.chrome&&r&&r!==j&&(p=d.slice||d.webkitSlice,d=p.call(d,0,d.size,j),s=!0),g&&"download"!==i&&(i+=".download"),(r===j||g)&&(o=a),h?(k+=d.size,void h(a.TEMPORARY,k,w(function(a){a.root.getDirectory("saved",x,w(function(a){var b=function(){a.getFile(i,x,w(function(a){a.createWriter(w(function(b){b.onwriteend=function(b){o.location.href=a.toURL(),l.push(a),q.readyState=q.DONE,n(q,"writeend",b)},b.onerror=function(){var a=b.error;a.code!==a.ABORT_ERR&&v()},"writestart progress write abort".split(" ").forEach(function(a){b["on"+a]=q["on"+a]}),b.write(d),q.abort=function(){b.abort(),q.readyState=q.DONE},q.readyState=q.WRITING}),v)}),v)};a.getFile(i,{create:!1},w(function(a){a.remove(),b()}),w(function(a){a.code===a.NOT_FOUND_ERR?b():v()}))}),v)}),v)):void v()},p=o.prototype,q=function(a,b){return new o(a,b)};return p.abort=function(){var a=this;a.readyState=a.DONE,n(a,"abort")},p.readyState=p.INIT=0,p.WRITING=1,p.DONE=2,p.error=p.onwritestart=p.onprogress=p.onwrite=p.onabort=p.onerror=p.onwriteend=null,a.addEventListener("unload",m,!1),q}(this.self||this.window||this.content),O.esri.Tiles.TilesCore=function(){this._getTiles=function(a,b,c,d,e,f,g){e.retrieve(c,function(c,e){a=f("img[src="+d+"]")[0];var h;return c?(a.style.borderColor="blue",h="data:image/"+b+";base64,"+e.img):g?(a.style.borderColor="green",h="data:image/png;base64,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pmk0TROPj48Hn3l4eIimaSJN06O3A4NJwDMxm82ibdtXo4D5fB6r1Sp+//4dz8/Pw5H+6ekpdrtdJEkS8/n8S/9f713ie3vaceo9x557QAB451Sgfyin34HKshweunk5HzAej2MymXz5+f9nbjJyI9L39Wu5XP55+XQZ39uxR4Z3u90wSXjqEV0wAjhjx47oaZq63Me/ZhIQBAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEAAbAJQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEAvqe/BwCeKjUweoA8pQAAAABJRU5ErkJggg=="):h="data:image/png;base64,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AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDDwAwMBPAABGrpAUwAAAABJRU5ErkJggg==",a.style.visibility="visible",a.src=h,""})},this._storeTile=function(a,b,c,d){a=a.split("?")[0];var e=b?b+"?"+a:a,f=new XMLHttpRequest;f.open("GET",e,!0),f.overrideMimeType("text/plain; charset=x-user-defined"),f.onload=function(){if(200===f.status&&""!==f.responseText){var b=O.esri.Tiles.Base64Utils.wordToBase64(O.esri.Tiles.Base64Utils.stringToWord(this.responseText)),g={url:a,img:b};c.store(g,d)}else d(!1,f.status+" "+f.statusText+": "+f.response+" when downloading "+e)},f.onerror=function(a){d(!1,a)},f.send(null)},this._createCellsForOffline=function(a,b,c,d,e){for(var f=new O.esri.Tiles.TilingScheme(a),g=[],h=b;c>=h;h++){var i=f.getAllCellIdsInExtent(d,h);if(i.forEach(function(a){g.push({level:h,row:a[1],col:a[0]})}),g.length>5e3&&h!==c)break}e(g)},this._saveToFile=function(a,b,c){var d=[];d.push("url,img"),b.getAllTiles(function(b,e,f){if("end"===f){var g=new Blob([d.join("\r\n")],{type:"text/plain;charset=utf-8"}),h=O.esri.Tiles.saveAs(g,a);if(h.readyState===h.DONE)return h.error?c(!1,"Error saving file "+a):c(!0,"Saved "+(d.length-1)+" tiles ("+Math.floor(g.size/1024/1024*100)/100+" Mb) into "+a);h.onerror=function(){c(!1,"Error saving file "+a)},h.onwriteend=function(){c(!0,"Saved "+(d.length-1)+" tiles ("+Math.floor(g.size/1024/1024*100)/100+" Mb) into "+a)}}else d.push(b+","+e)})},this._estimateTileSize=function(a,b,c,d){if(b){var e=c?c+"?"+b:b;a.get(e,{handleAs:"text/plain; charset=x-user-defined",headers:{"X-Requested-With":""},timeout:2e3}).then(function(a){var b=O.esri.Tiles.Base64Utils.wordToBase64(O.esri.Tiles.Base64Utils.stringToWord(a));d(b.length+e.length,null)},function(a){d(null,a)})}else d(NaN)},this._loadFromFile=function(a,b,c){if(window.File&&window.FileReader&&window.FileList&&window.Blob){var d=new FileReader;d.onload=function(d){var e,f,g=d.target.result,h=g.split("\r\n"),i=0;if("url,img"!==h[0])return c(!1,"File "+a.name+" doesn't contain tiles that can be loaded");for(var j=1;j=c;c++)for(d=i;j>=d;d++)k.push([c,d]);return k}}; \ No newline at end of file diff --git a/dist/offline-tiles-advanced-src.js b/dist/offline-tiles-advanced-src.js index 1466768..73d526a 100644 --- a/dist/offline-tiles-advanced-src.js +++ b/dist/offline-tiles-advanced-src.js @@ -1,497 +1,497 @@ -/*! offline-editor-js - v2.11.0 - 2015-07-30 -* Copyright (c) 2015 Environmental Systems Research Institute, Inc. -* Apache License*/ -define([ - "dojo/query", - "dojo/request", - "dojo/_base/declare", - "esri/layers/LOD", - "esri/geometry/Point", - "esri/geometry/Extent", - "esri/layers/TileInfo", - "esri/SpatialReference", - "esri/geometry/Polygon", - "esri/layers/TiledMapServiceLayer" -], function(query, request, declare,LOD,Point,Extent,TileInfo,SpatialReference,Polygon,TiledMapServerLayer) -{ - "use strict"; - return declare("O.esri.Tiles.OfflineTileEnablerLayer",[TiledMapServerLayer],{ - - tileInfo: null, - _imageType: "", - _level: null, //current zoom level - _minZoom: null, - _maxZoom: null, - _tilesCore:null, - - constructor:function(url,callback,/* boolean */ state,/* Object */ dbConfig){ - - if(this._isLocalStorage() === false){ - alert("OfflineTiles Library not supported on this browser."); - callback(false); - } - - if( dbConfig === undefined || dbConfig === null){ - // Database properties - this.DB_NAME = "offline_tile_store"; // Sets the database name. - this.DB_OBJECTSTORE_NAME = "tilepath"; // Represents an object store that allows access to a set of data in the IndexedDB database - } - else { - this.DB_NAME = dbConfig.dbName; - this.DB_OBJECTSTORE_NAME = dbConfig.objectStoreName; - } - - this._tilesCore = new O.esri.Tiles.TilesCore(); - - //For calculating minZoom and maxZoom - Array.prototype.sortNumber = function(){return this.sort(function(a,b){return a - b;});}; - - this._self = this; - this._lastTileUrl = ""; - this._imageType = ""; - - /* we add some methods to the layer object */ - /* we don't want to extend the tiled layer class, as it is a capability that we want to add only to one instance */ - /* we also add some additional attributes inside an "offline" object */ - - this._getTileUrl = this.getTileUrl; - - var isOnline = true; - if(typeof state != "undefined" || state != null){ - isOnline = state; console.log("STATE IS: " + state); - } - - /** - * Option to show/hide blank tile images. When using multiple basemap layers, - * if one has no tiles, this will display and cover another basemap storage which may have tiles. - * @type {boolean} - */ - this.showBlankTiles = true; - - /** - * IMPORTANT! proxyPath is set to null by default since we assume Feature Service is CORS-enabled. - * All AGOL Feature Services are CORS-enabled. - * - * @type {{online: boolean, store: O.esri.Tiles.TilesStore, proxyPath: null}} - */ - this.offline = { - online: isOnline, - store: new O.esri.Tiles.TilesStore(), - proxyPath: null - }; - - if( /*false &&*/ this.offline.store.isSupported() ) - { - this.offline.store.dbName = this.DB_NAME; - this.offline.store.objectStoreName = this.DB_OBJECTSTORE_NAME; - this.offline.store.init(function(success){ - if(success){ - this._getTileInfoPrivate(url,function(result){ - - // Store the layerInfo locally so we have it when browser restarts or is reloaded. - // We need this info in order to properly rebuild the layer. - if(localStorage.__offlineTileInfo === undefined && result !== false){ - localStorage.__offlineTileInfo = result; - } - - // If library is offline then attempt to get layerInfo from localStorage. - if(this.offline.online === false && result === false && localStorage.__offlineTileInfo !== undefined){ - result = localStorage.__offlineTileInfo; - } - else if(this.offline.online === false && result === false && localStorage.__offlineTileInfo === undefined){ - alert("There was a problem retrieving tiled map info in OfflineTilesEnablerLayer."); - } - - this._tilesCore._parseGetTileInfo(result,function(tileResult){ - this.layerInfos = tileResult.resultObj.layers; - this.minScale = tileResult.resultObj.minScale; - this.maxScale = tileResult.resultObj.maxScale; - this.tileInfo = tileResult.tileInfo; - this._imageType = this.tileInfo.format.toLowerCase(); - this.fullExtent = tileResult.fullExtent; - this.spatialReference = this.tileInfo.spatialReference; - this.initialExtent = tileResult.initExtent; - this.loaded = true; - this.onLoad(this); - callback(true); - }.bind(this._self)); - }.bind(this._self)); - } - }.bind(this._self)); - } - else - { - return callback(false, "indexedDB not supported"); - } - }, - - /** - * Internal method that overrides the getTileUrl() method. - * If application is offline then tiles are written to IndexedDB. - * Retrieves tiles as requested by the ArcGIS API for JavaScript. - * If a tile is in cache it is returned. - * If it is not in cache then one is retrieved over the internet. - * @param level - * @param row - * @param col - * @returns {String} URL - */ - getTileUrl: function(level,row,col) - { - console.assert(!isNaN(level) && !isNaN(row) && !isNaN(col), "bad tile requested"); - console.log("looking for tile",level,row,col); - - this._level = level; - - var url = this.url + "/tile/" + level + "/" + row + "/" + col; - console.log("LIBRARY ONLINE " + this.offline.online); - if( this.offline.online ) - { - console.log("fetching url online: ", url); - this._lastTileUrl = url; - return url; - } - - url = url.split("?")[0]; - - /* temporary URL returned immediately, as we haven't retrieved the image from the indexeddb yet */ - var tileid = "void:/"+level+"/"+row+"/"+col; - var img = null; - this._tilesCore._getTiles(img,this._imageType,url,tileid,this.offline.store,query,this.showBlankTiles); - - return tileid; - }, - - /** - * Utility method to get the basemap layer reference - * @param map - * @returns {Number} layerId - */ - getBasemapLayer: function(map) - { - var layerId = map.layerIds[0]; - return map.getLayer(layerId); - }, - - /** - * Returns an object that contains the number of tiles that would need to be downloaded - * for the specified extent and zoom level, and the estimated byte size of such tiles. - * This method is useful to give the user an indication of the required time and space - * before launching the actual download operation. The byte size estimation is very rough. - * @param extent - * @param level - * @param tileSize - * @returns {{level: *, tileCount: Number, sizeBytes: number}} - */ - getLevelEstimation: function(extent, level, tileSize) - { - var tilingScheme = new O.esri.Tiles.TilingScheme(this); - var cellIds = tilingScheme.getAllCellIdsInExtent(extent,level); - - var levelEstimation = { - level: level, - tileCount: cellIds.length, - sizeBytes: cellIds.length * tileSize - }; - - return levelEstimation; - }, - - /** - * Returns the current zoom level - * @returns {number} - */ - getLevel: function(){ - return this._level; - }, - - /** - * Returns the maximum zoom level for this layer - * @param callback number - */ - getMaxZoom: function(callback){ - - if(this._maxZoom == null){ - this._maxZoom = this.tileInfo.lods[this.tileInfo.lods.length-1].level; - } - callback(this._maxZoom); - }, - - /** - * Returns the minimum zoom level for this layer - * @param callback number - */ - getMinZoom: function(callback){ - - if(this._minZoom == null){ - this._minZoom = this.tileInfo.lods[0].level; - } - callback(this._minZoom); - }, - - /** - * Utility method for bracketing above and below your current Level of Detail. Use - * this in conjunction with setting the minLevel and maxLevel in prepareForOffline(). - * @param minZoomAdjust An Integer specifying how far above the current layer you want to retrieve tiles - * @param maxZoomAdjust An Integer specifying how far below (closer to earth) the current layer you want to retrieve tiles - */ - getMinMaxLOD: function(minZoomAdjust,maxZoomAdjust){ - var zoom = {}; - var map = this.getMap(); - var min = map.getLevel() + minZoomAdjust; - var max = map.getLevel() + maxZoomAdjust; - if(this._maxZoom != null && this._minZoom != null){ - zoom.max = Math.min(this._maxZoom, max); //prevent errors by setting the tile layer floor - zoom.min = Math.max(this._minZoom, min); //prevent errors by setting the tile layer ceiling - } - else{ - this.getMinZoom(function(result){ - zoom.min = Math.max(result, min); //prevent errors by setting the tile layer ceiling - }); - - this.getMaxZoom(function(result){ - zoom.max = Math.min(result, max); //prevent errors by setting the tile layer floor - }); - } - - return zoom; - - }, - - /** - * Retrieves tiles and stores them in the local cache. - * @param minLevel - * @param maxLevel - * @param extent - * @param reportProgress - */ - prepareForOffline : function(minLevel, maxLevel, extent, reportProgress) - { - this._tilesCore._createCellsForOffline(this,minLevel,maxLevel,extent,function(cells){ - /* launch tile download */ - this._doNextTile(0, cells, reportProgress); - }.bind(this)); - }, - - /** - * This method puts the layer in offline mode. When in offline mode, - * the layer will not fetch any tile from the remote server. It - * will look up the tiles in the indexed db database and display them in the - * If the tile can't be found in the local database it will show up blank - * (even if there is actual connectivity). The pair of methods goOffline() and - * goOnline()allows the developer to manually control the behaviour of the - * Used in conjunction with the offline dectection library, you can put the layer in - * the appropriate mode when the offline condition changes. - */ - goOffline : function() - { - this.offline.online = false; - }, - - /** - * This method puts the layer in online mode. When in online mode, the layer will - * behave as regular layers, fetching all tiles from the remote server. - * If there is no internet connectivity the tiles may appear thanks to the browsers cache, - * but no attempt will be made to look up tiles in the local database. - */ - goOnline : function() - { - this.offline.online = true; - this.refresh(); - }, - - /** - * Determines if application is online or offline - * @returns {boolean} - */ - isOnline : function() - { - return this.offline.online; - }, - - /** - * Clears the local cache of tiles. - * @param callback callback(boolean, errors) - */ - deleteAllTiles : function(callback) // callback(success) or callback(false, error) - { - var store = this.offline.store; - store.deleteAll(callback); - }, - - /** - * Gets the size in bytes of the local tile cache. - * @param callback callback(size, error) - */ - getOfflineUsage : function(callback) // callback({size: <>, tileCount: <>}) or callback(null,error) - { - var store = this.offline.store; - store.usedSpace(callback); - }, - - /** - * Gets polygons representing all cached cell ids within a particular - * zoom level and bounded by an extent. - * @param callback callback(polygon, error) - */ - getTilePolygons : function(callback) // callback(Polygon polygon) or callback(null, error) - { - this._tilesCore._getTilePolygons(this.offline.store,this.url,this,callback); - }, - - /** - * Saves tile cache into a portable csv format. - * @param fileName - * @param callback callback( boolean, error) - */ - saveToFile : function(fileName, callback) // callback(success, msg) - { - this._tilesCore._saveToFile(fileName,this.offline.store,callback); - }, - - /** - * Reads a csv file into local tile cache. - * @param file - * @param callback callback( boolean, error) - */ - loadFromFile : function(file, callback) // callback(success,msg) - { - console.log("reading",file); - this._tilesCore._loadFromFile(file,this.offline.store,callback); - }, - - /** - * Makes a request to a tile url and uses that as a basis for the - * the average tile size. - * Future Iterations could call multiple tiles and do an actual average. - * @param callback - * @returns {Number} Returns NaN if there was a problem retrieving the tile - */ - estimateTileSize : function(callback) - { - this._tilesCore._estimateTileSize(request,this._lastTileUrl,this.offline.proxyPath,callback); - }, - - /** - * Helper method that returns a new extent buffered by a given measurement that's based on map units. - * E.g. If you are using mercator then buffer would be in meters - * @param buffer - * @returns {Extent} - */ - getExtentBuffer : function(/* int */ buffer, /* Extent */ extent){ - extent.xmin -= buffer; extent.ymin -= buffer; - extent.xmax += buffer; extent.ymax += buffer; - return extent; - }, - - /** - * Helper method that returns an array of tile urls within a given extent and level - * @returns Array - */ - getTileUrlsByExtent : function(extent,level){ - var tilingScheme = new O.esri.Tiles.TilingScheme(this); - var level_cell_ids = tilingScheme.getAllCellIdsInExtent(extent,level); - var cells = []; - - level_cell_ids.forEach(function(cell_id) - { - cells.push(this.url + "/" + level + "/" + cell_id[1] + "/" + cell_id[0]); - }.bind(this)); - - return cells; - }, - - /* internal methods */ - - _doNextTile : function(i, cells, reportProgress) - { - var cell = cells[i]; - - var url = this._getTileUrl(cell.level,cell.row,cell.col); - - this._tilesCore._storeTile(url,this.offline.proxyPath,this.offline.store,function(success, error) - { - if(!success) - { - console.log("error storing tile", cell, error); - error = { cell:cell, msg:error}; - } - - var cancelRequested = reportProgress({countNow:i, countMax:cells.length, cell: cell, error: error, finishedDownloading:false}); - - if( cancelRequested || i === cells.length-1 ) - { - reportProgress({ finishedDownloading: true, cancelRequested: cancelRequested}); - } - else - { - this._doNextTile(i+1, cells, reportProgress); - } - - }.bind(this)); - }, - - /** - * Test for localStorage functionality - * @returns {boolean} - * @private - */ - _isLocalStorage: function(){ - var test = "test"; - try { - localStorage.setItem(test, test); - localStorage.removeItem(test); - return true; - } catch(e) { - return false; - } - }, - - /** - * Attempts an http request to verify if app is online or offline. - * Use this in conjunction with the offline checker library: offline.min.js - * @param callback - */ - _getTileInfoPrivate: function(url, callback){ - var req = new XMLHttpRequest(); - var finalUrl = this.offline.proxyPath != null? this.offline.proxyPath + "?" + url + "?f=pjson" : url + "?f=pjson"; - req.open("GET", finalUrl, true); - req.onload = function() - { - if( req.status === 200 && req.responseText !== "") - { - callback(this.response); - } - else - { - console.log("_getTileInfoPrivate failed"); - callback(false); - } - }; - req.onerror = function(e) - { - console.log("_getTileInfoPrivate failed: " + e); - callback(false); - }; - req.send(null); - } - }); // declare -}); // define -/** - * Creates a namespace for the non-AMD libraries in this directory - */ - -if(typeof O != "undefined"){ - O.esri.Tiles = {}; -} -else{ - O = {}; // jshint ignore:line - O.esri = { - Tiles: {} - }; -} - -//"use strict"; +/*! offline-editor-js - v2.12.0 - 2015-08-07 +* Copyright (c) 2015 Environmental Systems Research Institute, Inc. +* Apache License*/ +define([ + "dojo/query", + "dojo/request", + "dojo/_base/declare", + "esri/layers/LOD", + "esri/geometry/Point", + "esri/geometry/Extent", + "esri/layers/TileInfo", + "esri/SpatialReference", + "esri/geometry/Polygon", + "esri/layers/TiledMapServiceLayer" +], function(query, request, declare,LOD,Point,Extent,TileInfo,SpatialReference,Polygon,TiledMapServerLayer) +{ + "use strict"; + return declare("O.esri.Tiles.OfflineTileEnablerLayer",[TiledMapServerLayer],{ + + tileInfo: null, + _imageType: "", + _level: null, //current zoom level + _minZoom: null, + _maxZoom: null, + _tilesCore:null, + + constructor:function(url,callback,/* boolean */ state,/* Object */ dbConfig){ + + if(this._isLocalStorage() === false){ + alert("OfflineTiles Library not supported on this browser."); + callback(false); + } + + if( dbConfig === undefined || dbConfig === null){ + // Database properties + this.DB_NAME = "offline_tile_store"; // Sets the database name. + this.DB_OBJECTSTORE_NAME = "tilepath"; // Represents an object store that allows access to a set of data in the IndexedDB database + } + else { + this.DB_NAME = dbConfig.dbName; + this.DB_OBJECTSTORE_NAME = dbConfig.objectStoreName; + } + + this._tilesCore = new O.esri.Tiles.TilesCore(); + + //For calculating minZoom and maxZoom + Array.prototype.sortNumber = function(){return this.sort(function(a,b){return a - b;});}; + + this._self = this; + this._lastTileUrl = ""; + this._imageType = ""; + + /* we add some methods to the layer object */ + /* we don't want to extend the tiled layer class, as it is a capability that we want to add only to one instance */ + /* we also add some additional attributes inside an "offline" object */ + + this._getTileUrl = this.getTileUrl; + + var isOnline = true; + if(typeof state != "undefined" || state != null){ + isOnline = state; console.log("STATE IS: " + state); + } + + /** + * Option to show/hide blank tile images. When using multiple basemap layers, + * if one has no tiles, this will display and cover another basemap storage which may have tiles. + * @type {boolean} + */ + this.showBlankTiles = true; + + /** + * IMPORTANT! proxyPath is set to null by default since we assume Feature Service is CORS-enabled. + * All AGOL Feature Services are CORS-enabled. + * + * @type {{online: boolean, store: O.esri.Tiles.TilesStore, proxyPath: null}} + */ + this.offline = { + online: isOnline, + store: new O.esri.Tiles.TilesStore(), + proxyPath: null + }; + + if( /*false &&*/ this.offline.store.isSupported() ) + { + this.offline.store.dbName = this.DB_NAME; + this.offline.store.objectStoreName = this.DB_OBJECTSTORE_NAME; + this.offline.store.init(function(success){ + if(success){ + this._getTileInfoPrivate(url,function(result){ + + // Store the layerInfo locally so we have it when browser restarts or is reloaded. + // We need this info in order to properly rebuild the layer. + if(localStorage.__offlineTileInfo === undefined && result !== false){ + localStorage.__offlineTileInfo = result; + } + + // If library is offline then attempt to get layerInfo from localStorage. + if(this.offline.online === false && result === false && localStorage.__offlineTileInfo !== undefined){ + result = localStorage.__offlineTileInfo; + } + else if(this.offline.online === false && result === false && localStorage.__offlineTileInfo === undefined){ + alert("There was a problem retrieving tiled map info in OfflineTilesEnablerLayer."); + } + + this._tilesCore._parseGetTileInfo(result,function(tileResult){ + this.layerInfos = tileResult.resultObj.layers; + this.minScale = tileResult.resultObj.minScale; + this.maxScale = tileResult.resultObj.maxScale; + this.tileInfo = tileResult.tileInfo; + this._imageType = this.tileInfo.format.toLowerCase(); + this.fullExtent = tileResult.fullExtent; + this.spatialReference = this.tileInfo.spatialReference; + this.initialExtent = tileResult.initExtent; + this.loaded = true; + this.onLoad(this); + callback(true); + }.bind(this._self)); + }.bind(this._self)); + } + }.bind(this._self)); + } + else + { + return callback(false, "indexedDB not supported"); + } + }, + + /** + * Internal method that overrides the getTileUrl() method. + * If application is offline then tiles are written to IndexedDB. + * Retrieves tiles as requested by the ArcGIS API for JavaScript. + * If a tile is in cache it is returned. + * If it is not in cache then one is retrieved over the internet. + * @param level + * @param row + * @param col + * @returns {String} URL + */ + getTileUrl: function(level,row,col) + { + console.assert(!isNaN(level) && !isNaN(row) && !isNaN(col), "bad tile requested"); + console.log("looking for tile",level,row,col); + + this._level = level; + + var url = this.url + "/tile/" + level + "/" + row + "/" + col; + console.log("LIBRARY ONLINE " + this.offline.online); + if( this.offline.online ) + { + console.log("fetching url online: ", url); + this._lastTileUrl = url; + return url; + } + + url = url.split("?")[0]; + + /* temporary URL returned immediately, as we haven't retrieved the image from the indexeddb yet */ + var tileid = "void:/"+level+"/"+row+"/"+col; + var img = null; + this._tilesCore._getTiles(img,this._imageType,url,tileid,this.offline.store,query,this.showBlankTiles); + + return tileid; + }, + + /** + * Utility method to get the basemap layer reference + * @param map + * @returns {Number} layerId + */ + getBasemapLayer: function(map) + { + var layerId = map.layerIds[0]; + return map.getLayer(layerId); + }, + + /** + * Returns an object that contains the number of tiles that would need to be downloaded + * for the specified extent and zoom level, and the estimated byte size of such tiles. + * This method is useful to give the user an indication of the required time and space + * before launching the actual download operation. The byte size estimation is very rough. + * @param extent + * @param level + * @param tileSize + * @returns {{level: *, tileCount: Number, sizeBytes: number}} + */ + getLevelEstimation: function(extent, level, tileSize) + { + var tilingScheme = new O.esri.Tiles.TilingScheme(this); + var cellIds = tilingScheme.getAllCellIdsInExtent(extent,level); + + var levelEstimation = { + level: level, + tileCount: cellIds.length, + sizeBytes: cellIds.length * tileSize + }; + + return levelEstimation; + }, + + /** + * Returns the current zoom level + * @returns {number} + */ + getLevel: function(){ + return this._level; + }, + + /** + * Returns the maximum zoom level for this layer + * @param callback number + */ + getMaxZoom: function(callback){ + + if(this._maxZoom == null){ + this._maxZoom = this.tileInfo.lods[this.tileInfo.lods.length-1].level; + } + callback(this._maxZoom); + }, + + /** + * Returns the minimum zoom level for this layer + * @param callback number + */ + getMinZoom: function(callback){ + + if(this._minZoom == null){ + this._minZoom = this.tileInfo.lods[0].level; + } + callback(this._minZoom); + }, + + /** + * Utility method for bracketing above and below your current Level of Detail. Use + * this in conjunction with setting the minLevel and maxLevel in prepareForOffline(). + * @param minZoomAdjust An Integer specifying how far above the current layer you want to retrieve tiles + * @param maxZoomAdjust An Integer specifying how far below (closer to earth) the current layer you want to retrieve tiles + */ + getMinMaxLOD: function(minZoomAdjust,maxZoomAdjust){ + var zoom = {}; + var map = this.getMap(); + var min = map.getLevel() + minZoomAdjust; + var max = map.getLevel() + maxZoomAdjust; + if(this._maxZoom != null && this._minZoom != null){ + zoom.max = Math.min(this._maxZoom, max); //prevent errors by setting the tile layer floor + zoom.min = Math.max(this._minZoom, min); //prevent errors by setting the tile layer ceiling + } + else{ + this.getMinZoom(function(result){ + zoom.min = Math.max(result, min); //prevent errors by setting the tile layer ceiling + }); + + this.getMaxZoom(function(result){ + zoom.max = Math.min(result, max); //prevent errors by setting the tile layer floor + }); + } + + return zoom; + + }, + + /** + * Retrieves tiles and stores them in the local cache. + * @param minLevel + * @param maxLevel + * @param extent + * @param reportProgress + */ + prepareForOffline : function(minLevel, maxLevel, extent, reportProgress) + { + this._tilesCore._createCellsForOffline(this,minLevel,maxLevel,extent,function(cells){ + /* launch tile download */ + this._doNextTile(0, cells, reportProgress); + }.bind(this)); + }, + + /** + * This method puts the layer in offline mode. When in offline mode, + * the layer will not fetch any tile from the remote server. It + * will look up the tiles in the indexed db database and display them in the + * If the tile can't be found in the local database it will show up blank + * (even if there is actual connectivity). The pair of methods goOffline() and + * goOnline()allows the developer to manually control the behaviour of the + * Used in conjunction with the offline dectection library, you can put the layer in + * the appropriate mode when the offline condition changes. + */ + goOffline : function() + { + this.offline.online = false; + }, + + /** + * This method puts the layer in online mode. When in online mode, the layer will + * behave as regular layers, fetching all tiles from the remote server. + * If there is no internet connectivity the tiles may appear thanks to the browsers cache, + * but no attempt will be made to look up tiles in the local database. + */ + goOnline : function() + { + this.offline.online = true; + this.refresh(); + }, + + /** + * Determines if application is online or offline + * @returns {boolean} + */ + isOnline : function() + { + return this.offline.online; + }, + + /** + * Clears the local cache of tiles. + * @param callback callback(boolean, errors) + */ + deleteAllTiles : function(callback) // callback(success) or callback(false, error) + { + var store = this.offline.store; + store.deleteAll(callback); + }, + + /** + * Gets the size in bytes of the local tile cache. + * @param callback callback(size, error) + */ + getOfflineUsage : function(callback) // callback({size: <>, tileCount: <>}) or callback(null,error) + { + var store = this.offline.store; + store.usedSpace(callback); + }, + + /** + * Gets polygons representing all cached cell ids within a particular + * zoom level and bounded by an extent. + * @param callback callback(polygon, error) + */ + getTilePolygons : function(callback) // callback(Polygon polygon) or callback(null, error) + { + this._tilesCore._getTilePolygons(this.offline.store,this.url,this,callback); + }, + + /** + * Saves tile cache into a portable csv format. + * @param fileName + * @param callback callback( boolean, error) + */ + saveToFile : function(fileName, callback) // callback(success, msg) + { + this._tilesCore._saveToFile(fileName,this.offline.store,callback); + }, + + /** + * Reads a csv file into local tile cache. + * @param file + * @param callback callback( boolean, error) + */ + loadFromFile : function(file, callback) // callback(success,msg) + { + console.log("reading",file); + this._tilesCore._loadFromFile(file,this.offline.store,callback); + }, + + /** + * Makes a request to a tile url and uses that as a basis for the + * the average tile size. + * Future Iterations could call multiple tiles and do an actual average. + * @param callback + * @returns {Number} Returns NaN if there was a problem retrieving the tile + */ + estimateTileSize : function(callback) + { + this._tilesCore._estimateTileSize(request,this._lastTileUrl,this.offline.proxyPath,callback); + }, + + /** + * Helper method that returns a new extent buffered by a given measurement that's based on map units. + * E.g. If you are using mercator then buffer would be in meters + * @param buffer + * @returns {Extent} + */ + getExtentBuffer : function(/* int */ buffer, /* Extent */ extent){ + extent.xmin -= buffer; extent.ymin -= buffer; + extent.xmax += buffer; extent.ymax += buffer; + return extent; + }, + + /** + * Helper method that returns an array of tile urls within a given extent and level + * @returns Array + */ + getTileUrlsByExtent : function(extent,level){ + var tilingScheme = new O.esri.Tiles.TilingScheme(this); + var level_cell_ids = tilingScheme.getAllCellIdsInExtent(extent,level); + var cells = []; + + level_cell_ids.forEach(function(cell_id) + { + cells.push(this.url + "/" + level + "/" + cell_id[1] + "/" + cell_id[0]); + }.bind(this)); + + return cells; + }, + + /* internal methods */ + + _doNextTile : function(i, cells, reportProgress) + { + var cell = cells[i]; + + var url = this._getTileUrl(cell.level,cell.row,cell.col); + + this._tilesCore._storeTile(url,this.offline.proxyPath,this.offline.store,function(success, error) + { + if(!success) + { + console.log("error storing tile", cell, error); + error = { cell:cell, msg:error}; + } + + var cancelRequested = reportProgress({countNow:i, countMax:cells.length, cell: cell, error: error, finishedDownloading:false}); + + if( cancelRequested || i === cells.length-1 ) + { + reportProgress({ finishedDownloading: true, cancelRequested: cancelRequested}); + } + else + { + this._doNextTile(i+1, cells, reportProgress); + } + + }.bind(this)); + }, + + /** + * Test for localStorage functionality + * @returns {boolean} + * @private + */ + _isLocalStorage: function(){ + var test = "test"; + try { + localStorage.setItem(test, test); + localStorage.removeItem(test); + return true; + } catch(e) { + return false; + } + }, + + /** + * Attempts an http request to verify if app is online or offline. + * Use this in conjunction with the offline checker library: offline.min.js + * @param callback + */ + _getTileInfoPrivate: function(url, callback){ + var req = new XMLHttpRequest(); + var finalUrl = this.offline.proxyPath != null? this.offline.proxyPath + "?" + url + "?f=pjson" : url + "?f=pjson"; + req.open("GET", finalUrl, true); + req.onload = function() + { + if( req.status === 200 && req.responseText !== "") + { + callback(this.response); + } + else + { + console.log("_getTileInfoPrivate failed"); + callback(false); + } + }; + req.onerror = function(e) + { + console.log("_getTileInfoPrivate failed: " + e); + callback(false); + }; + req.send(null); + } + }); // declare +}); // define +/** + * Creates a namespace for the non-AMD libraries in this directory + */ + +if(typeof O != "undefined"){ + O.esri.Tiles = {}; +} +else{ + O = {}; // jshint ignore:line + O.esri = { + Tiles: {} + }; +} + +//"use strict"; /*jslint bitwise: true */ O.esri.Tiles.Base64Utils={}; @@ -573,935 +573,935 @@ O.esri.Tiles.Base64Utils.wordToBase64=function(/* word[] */wa){ return s.join(""); // string }; -/*jslint bitwise: false */ -/* FileSaver.js - * A saveAs() FileSaver implementation. - * 2013-10-21 - * - * By Eli Grey, http://eligrey.com - * License: X11/MIT - * See LICENSE.md - */ - -/*global self */ -/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true, - plusplus: true */ - -/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ - - -O.esri.Tiles.saveAs = -// IE 10 support, see Eli Grey's original source -// || (typeof navigator !== 'undefined' && navigator.msSaveOrOpenBlob && navigator.msSaveOrOpenBlob.bind(navigator)) - function(view) { - "use strict"; - var - doc = view.document - // only get URL when necessary in case BlobBuilder.js hasn't overridden it yet - , get_URL = function() { - return view.URL || view.webkitURL || view; - } - , URL = view.URL || view.webkitURL || view - , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a") - , can_use_save_link = !view.externalHost && "download" in save_link - , click = function(node) { - var event = doc.createEvent("MouseEvents"); - event.initMouseEvent( - "click", true, false, view, 0, 0, 0, 0, 0 - , false, false, false, false, 0, null - ); - node.dispatchEvent(event); - } - , webkit_req_fs = view.webkitRequestFileSystem - , req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem - , throw_outside = function (ex) { - (view.setImmediate || view.setTimeout)(function() { - throw ex; - }, 0); - } - , force_saveable_type = "application/octet-stream" - , fs_min_size = 0 - , deletion_queue = [] - , process_deletion_queue = function() { - var i = deletion_queue.length; - while (i--) { - var file = deletion_queue[i]; - if (typeof file === "string") { // file is an object URL - URL.revokeObjectURL(file); - } else { // file is a File - file.remove(); - } - } - deletion_queue.length = 0; // clear queue - } - , dispatch = function(filesaver, event_types, event) { - event_types = [].concat(event_types); - var i = event_types.length; - while (i--) { - var listener = filesaver["on" + event_types[i]]; - if (typeof listener === "function") { - try { - listener.call(filesaver, event || filesaver); - } catch (ex) { - throw_outside(ex); - } - } - } - } - , FileSaver = function(blob, name) { - // First try a.download, then web filesystem, then object URLs - var - filesaver = this - , type = blob.type - , blob_changed = false - , object_url - , target_view - , get_object_url = function() { - var object_url = get_URL().createObjectURL(blob); - deletion_queue.push(object_url); - return object_url; - } - , dispatch_all = function() { - dispatch(filesaver, "writestart progress write writeend".split(" ")); - } - // on any filesys errors revert to saving with object URLs - , fs_error = function() { - // don't create more object URLs than needed - if (blob_changed || !object_url) { - object_url = get_object_url(blob); - } - if (target_view) { - target_view.location.href = object_url; - } else { - window.open(object_url, "_blank"); - } - filesaver.readyState = filesaver.DONE; - dispatch_all(); - } - , abortable = function(func) { - return function() { - if (filesaver.readyState !== filesaver.DONE) { - return func.apply(this, arguments); - } - }; - } - , create_if_not_found = {create: true, exclusive: false} - , slice - ; - filesaver.readyState = filesaver.INIT; - if (!name) { - name = "download"; - } - if (can_use_save_link) { - object_url = get_object_url(blob); - // FF for Android has a nasty garbage collection mechanism - // that turns all objects that are not pure javascript into 'deadObject' - // this means `doc` and `save_link` are unusable and need to be recreated - // `view` is usable though: - doc = view.document; - save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a"); - save_link.href = object_url; - save_link.download = name; - var event = doc.createEvent("MouseEvents"); - event.initMouseEvent( - "click", true, false, view, 0, 0, 0, 0, 0 - , false, false, false, false, 0, null - ); - save_link.dispatchEvent(event); - filesaver.readyState = filesaver.DONE; - dispatch_all(); - return; - } - // Object and web filesystem URLs have a problem saving in Google Chrome when - // viewed in a tab, so I force save with application/octet-stream - // http://code.google.com/p/chromium/issues/detail?id=91158 - if (view.chrome && type && type !== force_saveable_type) { - slice = blob.slice || blob.webkitSlice; - blob = slice.call(blob, 0, blob.size, force_saveable_type); - blob_changed = true; - } - // Since I can't be sure that the guessed media type will trigger a download - // in WebKit, I append .download to the filename. - // https://bugs.webkit.org/show_bug.cgi?id=65440 - if (webkit_req_fs && name !== "download") { - name += ".download"; - } - if (type === force_saveable_type || webkit_req_fs) { - target_view = view; - } - if (!req_fs) { - fs_error(); - return; - } - fs_min_size += blob.size; - req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) { - fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) { - var save = function() { - dir.getFile(name, create_if_not_found, abortable(function(file) { - file.createWriter(abortable(function(writer) { - writer.onwriteend = function(event) { - target_view.location.href = file.toURL(); - deletion_queue.push(file); - filesaver.readyState = filesaver.DONE; - dispatch(filesaver, "writeend", event); - }; - writer.onerror = function() { - var error = writer.error; - if (error.code !== error.ABORT_ERR) { - fs_error(); - } - }; - "writestart progress write abort".split(" ").forEach(function(event) { - writer["on" + event] = filesaver["on" + event]; - }); - writer.write(blob); - filesaver.abort = function() { - writer.abort(); - filesaver.readyState = filesaver.DONE; - }; - filesaver.readyState = filesaver.WRITING; - }), fs_error); - }), fs_error); - }; - dir.getFile(name, {create: false}, abortable(function(file) { - // delete file if it already exists - file.remove(); - save(); - }), abortable(function(ex) { - if (ex.code === ex.NOT_FOUND_ERR) { - save(); - } else { - fs_error(); - } - })); - }), fs_error); - }), fs_error); - } - , FS_proto = FileSaver.prototype - , saveAs = function(blob, name) { - return new FileSaver(blob, name); - } - ; - FS_proto.abort = function() { - var filesaver = this; - filesaver.readyState = filesaver.DONE; - dispatch(filesaver, "abort"); - }; - FS_proto.readyState = FS_proto.INIT = 0; - FS_proto.WRITING = 1; - FS_proto.DONE = 2; - - FS_proto.error = - FS_proto.onwritestart = - FS_proto.onprogress = - FS_proto.onwrite = - FS_proto.onabort = - FS_proto.onerror = - FS_proto.onwriteend = - null; - - view.addEventListener("unload", process_deletion_queue, false); - return saveAs; - -}(this.self || this.window || this.content); -// `self` is undefined in Firefox for Android content script context -// while `this` is nsIContentFrameMessageManager -// with an attribute `content` that corresponds to the window - -//if (typeof module !== 'undefined') module.exports = saveAs; - - -/** - * This library contains common core code between offlineTilesEnabler.js - * and OfflineTilesEnablerLayer.js - */ - -O.esri.Tiles.TilesCore = function(){ - - /** - * Retrieves a tile from local store. - * @param image a holder for the image that is retrieved from storage. - * @param imageType - * @param url the url of the tile - * @param tileid a reference to the tile's unique level, row and column - * @param store - * @param query Dojo Query - * @param showBlankTiles - * @private - */ - this._getTiles = function(image,imageType,url,tileid,store,query,showBlankTiles){ - store.retrieve(url, function(success, offlineTile) - { console.log("TILE RETURN " + success + ", " + offlineTile.url); - /* when the .getTileUrl() callback is triggered we replace the temporary URL originally returned by the data:image url */ - // search for the img with src="void:"+level+"-"+row+"-"+col and replace with actual url - image = query("img[src="+tileid+"]")[0]; - var imgURL; - - console.assert(image !== "undefined", "undefined image detected"); - - if( success ) - { - image.style.borderColor = "blue"; - console.log("found tile offline", url); - imgURL = "data:image/" + imageType +";base64," + offlineTile.img; - } - else if( !showBlankTiles ) { - console.log("showBlankTiles = false"); - imgURL = "data:image/png;base64," + "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AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDDwAwMBPAABGrpAUwAAAABJRU5ErkJggg=="; - } - else - { - image.style.borderColor = "green"; - console.log("tile is not in the offline store", url); - imgURL = "data:image/png;base64,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pmk0TROPj48Hn3l4eIimaSJN06O3A4NJwDMxm82ibdtXo4D5fB6r1Sp+//4dz8/Pw5H+6ekpdrtdJEkS8/n8S/9f713ie3vaceo9x557QAB451Sgfyin34HKshweunk5HzAej2MymXz5+f9nbjJyI9L39Wu5XP55+XQZ39uxR4Z3u90wSXjqEV0wAjhjx47oaZq63Me/ZhIQBAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEAAbAJQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEAvqe/BwCeKjUweoA8pQAAAABJRU5ErkJggg=="; - } - // when we return a nonexistent url to the image, the TiledMapServiceLayer::_tileErrorHandler() method - // sets img visibility to 'hidden', so we need to show the image back once we have put the data:image - image.style.visibility = "visible"; - image.src = imgURL; - return ""; /* this result goes nowhere, seriously */ - }); - }; - - /** - * Retrieves an image from a tile url and then stores it locally. - * @param url The image's url - * @param proxyPath - * @param store - * @param callback - * @private - */ - this._storeTile= function(url,proxyPath,store,callback) // callback(success, msg) - { - url = url.split("?")[0]; - - /* download the tile */ - var imgurl = proxyPath ? proxyPath + "?" + url : url; - var req = new XMLHttpRequest(); - req.open("GET", imgurl, true); - req.overrideMimeType("text/plain; charset=x-user-defined"); // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest?redirectlocale=en-US&redirectslug=DOM%2FXMLHttpRequest%2FUsing_XMLHttpRequest#Handling_binary_data - - req.onload = function () { - if (req.status === 200 && req.responseText !== "") { - var img = O.esri.Tiles.Base64Utils.wordToBase64(O.esri.Tiles.Base64Utils.stringToWord(this.responseText)); - - var tile = { - url: url, - img: img - }; - - store.store(tile, callback); - } - else { - console.log("xhr failed for", imgurl); - callback(false, req.status + " " + req.statusText + ": " + req.response + " when downloading " + imgurl); - } - }; - req.onerror = function (e) { - console.log("xhr failed for", imgurl); - callback(false, e); - }; - req.send(null); - }; - - /** - * Retrieves all the cells within a certain extent - * @param context Layer - * @param minLevel minimum zoom level - * @param maxLevel maximum zoom level - * @param extent Esri.Extent - * @param callback - * @private - */ - this._createCellsForOffline = function(context,minLevel,maxLevel,extent,callback){ - var tilingScheme = new O.esri.Tiles.TilingScheme(context); - var cells = []; - - for(var level=minLevel; level<=maxLevel; level++) - { - var level_cell_ids = tilingScheme.getAllCellIdsInExtent(extent,level); - - level_cell_ids.forEach(function(cell_id) - { - cells.push({ level: level, row: cell_id[1], col: cell_id[0]}); - }); - - // if the number of requested tiles is excessive, we just stop - if( cells.length > 5000 && level !== maxLevel) - { - console.log("enough is enough!"); - break; - } - } - callback(cells); - }; - - /** - * Saves locally stored tiles to a csv - * @param fileName - * @param store - * @param callback - * @private - */ - this._saveToFile = function(fileName,store,callback){ - var csv = []; - - csv.push("url,img"); - store.getAllTiles(function(url,img,evt) - { - if(evt==="end") - { - var blob = new Blob([ csv.join("\r\n") ], {type:"text/plain;charset=utf-8"}); - var saver = O.esri.Tiles.saveAs(blob, fileName); - - if( saver.readyState === saver.DONE ) - { - if( saver.error ) - { - return callback(false,"Error saving file " + fileName); - } - return callback(true, "Saved " + (csv.length-1) + " tiles (" + Math.floor(blob.size / 1024 / 1024 * 100) / 100 + " Mb) into " + fileName); - } - saver.onerror = function() { - callback(false,"Error saving file " + fileName); - }; - saver.onwriteend = function() - { - callback(true, "Saved " + (csv.length-1) + " tiles (" + Math.floor(blob.size / 1024 / 1024 * 100) / 100 + " Mb) into " + fileName); - }; - } - else - { - csv.push(url+","+img); - } - }); - }; - - /** - * Makes a request to a tile url and uses that as a basis for the - * the average tile size. - * Future Iterations could call multiple tiles and do an actual average. - * @param request "dojo/request" - * @param lastTileUrl FQDN of a tile location - * @param proxyPath your local proxy - * @param callback - * @returns {Number} Returns NaN if there was a problem retrieving the tile - */ - this._estimateTileSize = function(request,lastTileUrl,proxyPath,callback) - { - if(lastTileUrl) - { - var url = proxyPath? proxyPath + "?" + lastTileUrl : lastTileUrl; - request.get(url,{ - handleAs: "text/plain; charset=x-user-defined", - headers: { - "X-Requested-With": "" //bypasses a dojo xhr bug - }, - timeout: 2000 - }).then(function(response){ - var img = O.esri.Tiles.Base64Utils.wordToBase64(O.esri.Tiles.Base64Utils.stringToWord(response)); - callback(img.length + url.length,null); - }, - function(err){ - callback(null,err); - }); - } - else{ - callback(NaN); - } - }; - - /** - * Loads a csv file into storage. - * Format is "url,img\r\n somebase64image,http://esri.com" - * @param file - * @param store - * @param callback - * @private - */ - this._loadFromFile = function(file,store,callback){ - if (window.File && window.FileReader && window.FileList && window.Blob) - { - // Great success! All the File APIs are supported. - var reader = new FileReader(); - reader.onload = function(evt) - { - var csvContent = evt.target.result; - var tiles = csvContent.split("\r\n"); - var tileCount = 0; - var pair, tile; - - if(tiles[0] !== "url,img") - { - return callback(false, "File " + file.name + " doesn't contain tiles that can be loaded"); - } - - for(var i=1; i 5000 && level !== maxLevel) + { + console.log("enough is enough!"); + break; + } + } + callback(cells); + }; + + /** + * Saves locally stored tiles to a csv + * @param fileName + * @param store + * @param callback + * @private + */ + this._saveToFile = function(fileName,store,callback){ + var csv = []; + + csv.push("url,img"); + store.getAllTiles(function(url,img,evt) + { + if(evt==="end") + { + var blob = new Blob([ csv.join("\r\n") ], {type:"text/plain;charset=utf-8"}); + var saver = O.esri.Tiles.saveAs(blob, fileName); + + if( saver.readyState === saver.DONE ) + { + if( saver.error ) + { + return callback(false,"Error saving file " + fileName); + } + return callback(true, "Saved " + (csv.length-1) + " tiles (" + Math.floor(blob.size / 1024 / 1024 * 100) / 100 + " Mb) into " + fileName); + } + saver.onerror = function() { + callback(false,"Error saving file " + fileName); + }; + saver.onwriteend = function() + { + callback(true, "Saved " + (csv.length-1) + " tiles (" + Math.floor(blob.size / 1024 / 1024 * 100) / 100 + " Mb) into " + fileName); + }; + } + else + { + csv.push(url+","+img); + } + }); + }; + + /** + * Makes a request to a tile url and uses that as a basis for the + * the average tile size. + * Future Iterations could call multiple tiles and do an actual average. + * @param request "dojo/request" + * @param lastTileUrl FQDN of a tile location + * @param proxyPath your local proxy + * @param callback + * @returns {Number} Returns NaN if there was a problem retrieving the tile + */ + this._estimateTileSize = function(request,lastTileUrl,proxyPath,callback) + { + if(lastTileUrl) + { + var url = proxyPath? proxyPath + "?" + lastTileUrl : lastTileUrl; + request.get(url,{ + handleAs: "text/plain; charset=x-user-defined", + headers: { + "X-Requested-With": "" //bypasses a dojo xhr bug + }, + timeout: 2000 + }).then(function(response){ + var img = O.esri.Tiles.Base64Utils.wordToBase64(O.esri.Tiles.Base64Utils.stringToWord(response)); + callback(img.length + url.length,null); + }, + function(err){ + callback(null,err); + }); + } + else{ + callback(NaN); + } + }; + + /** + * Loads a csv file into storage. + * Format is "url,img\r\n somebase64image,http://esri.com" + * @param file + * @param store + * @param callback + * @private + */ + this._loadFromFile = function(file,store,callback){ + if (window.File && window.FileReader && window.FileList && window.Blob) + { + // Great success! All the File APIs are supported. + var reader = new FileReader(); + reader.onload = function(evt) + { + var csvContent = evt.target.result; + var tiles = csvContent.split("\r\n"); + var tileCount = 0; + var pair, tile; + + if(tiles[0] !== "url,img") + { + return callback(false, "File " + file.name + " doesn't contain tiles that can be loaded"); + } + + for(var i=1; i>16)+(b>>16)+(c>>16);return d<<16|65535&c},O.esri.Tiles.Base64Utils.stringToWord=function(a){for(var b=8,c=(1<e;e+=b)d[e>>5]|=(a.charCodeAt(e/b)&c)<e;e+=b)d.push(String.fromCharCode(a[e>>5]>>>e%32&c));return d.join("")},O.esri.Tiles.Base64Utils.wordToHex=function(a){for(var b="0123456789abcdef",c=[],d=0,e=4*a.length;e>d;d++)c.push(b.charAt(a[d>>2]>>d%4*8+4&15)+b.charAt(a[d>>2]>>d%4*8&15));return c.join("")},O.esri.Tiles.Base64Utils.wordToBase64=function(a){for(var b="=",c="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",d=[],e=0,f=4*a.length;f>e;e+=3)for(var g=(a[e>>2]>>8*(e%4)&255)<<16|(a[e+1>>2]>>8*((e+1)%4)&255)<<8|a[e+2>>2]>>8*((e+2)%4)&255,h=0;4>h;h++)d.push(8*e+6*h>32*a.length?b:c.charAt(g>>6*(3-h)&63));return d.join("")},/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ -O.esri.Tiles.saveAs=function(a){"use strict";var b=a.document,c=function(){return a.URL||a.webkitURL||a},d=a.URL||a.webkitURL||a,e=b.createElementNS("http://www.w3.org/1999/xhtml","a"),f=!a.externalHost&&"download"in e,g=a.webkitRequestFileSystem,h=a.requestFileSystem||g||a.mozRequestFileSystem,i=function(b){(a.setImmediate||a.setTimeout)(function(){throw b},0)},j="application/octet-stream",k=0,l=[],m=function(){for(var a=l.length;a--;){var b=l[a];"string"==typeof b?d.revokeObjectURL(b):b.remove()}l.length=0},n=function(a,b,c){b=[].concat(b);for(var d=b.length;d--;){var e=a["on"+b[d]];if("function"==typeof e)try{e.call(a,c||a)}catch(f){i(f)}}},o=function(d,i){var m,o,p,q=this,r=d.type,s=!1,t=function(){var a=c().createObjectURL(d);return l.push(a),a},u=function(){n(q,"writestart progress write writeend".split(" "))},v=function(){(s||!m)&&(m=t(d)),o?o.location.href=m:window.open(m,"_blank"),q.readyState=q.DONE,u()},w=function(a){return function(){return q.readyState!==q.DONE?a.apply(this,arguments):void 0}},x={create:!0,exclusive:!1};if(q.readyState=q.INIT,i||(i="download"),f){m=t(d),b=a.document,e=b.createElementNS("http://www.w3.org/1999/xhtml","a"),e.href=m,e.download=i;var y=b.createEvent("MouseEvents");return y.initMouseEvent("click",!0,!1,a,0,0,0,0,0,!1,!1,!1,!1,0,null),e.dispatchEvent(y),q.readyState=q.DONE,void u()}return a.chrome&&r&&r!==j&&(p=d.slice||d.webkitSlice,d=p.call(d,0,d.size,j),s=!0),g&&"download"!==i&&(i+=".download"),(r===j||g)&&(o=a),h?(k+=d.size,void h(a.TEMPORARY,k,w(function(a){a.root.getDirectory("saved",x,w(function(a){var b=function(){a.getFile(i,x,w(function(a){a.createWriter(w(function(b){b.onwriteend=function(b){o.location.href=a.toURL(),l.push(a),q.readyState=q.DONE,n(q,"writeend",b)},b.onerror=function(){var a=b.error;a.code!==a.ABORT_ERR&&v()},"writestart progress write abort".split(" ").forEach(function(a){b["on"+a]=q["on"+a]}),b.write(d),q.abort=function(){b.abort(),q.readyState=q.DONE},q.readyState=q.WRITING}),v)}),v)};a.getFile(i,{create:!1},w(function(a){a.remove(),b()}),w(function(a){a.code===a.NOT_FOUND_ERR?b():v()}))}),v)}),v)):void v()},p=o.prototype,q=function(a,b){return new o(a,b)};return p.abort=function(){var a=this;a.readyState=a.DONE,n(a,"abort")},p.readyState=p.INIT=0,p.WRITING=1,p.DONE=2,p.error=p.onwritestart=p.onprogress=p.onwrite=p.onabort=p.onerror=p.onwriteend=null,a.addEventListener("unload",m,!1),q}(this.self||this.window||this.content),O.esri.Tiles.TilesCore=function(){this._getTiles=function(a,b,c,d,e,f,g){e.retrieve(c,function(c,e){a=f("img[src="+d+"]")[0];var h;return c?(a.style.borderColor="blue",h="data:image/"+b+";base64,"+e.img):g?(a.style.borderColor="green",h="data:image/png;base64,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pmk0TROPj48Hn3l4eIimaSJN06O3A4NJwDMxm82ibdtXo4D5fB6r1Sp+//4dz8/Pw5H+6ekpdrtdJEkS8/n8S/9f713ie3vaceo9x557QAB451Sgfyin34HKshweunk5HzAej2MymXz5+f9nbjJyI9L39Wu5XP55+XQZ39uxR4Z3u90wSXjqEV0wAjhjx47oaZq63Me/ZhIQBAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEAAbAJQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEAvqe/BwCeKjUweoA8pQAAAABJRU5ErkJggg=="):h="data:image/png;base64,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AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDDwAwMBPAABGrpAUwAAAABJRU5ErkJggg==",a.style.visibility="visible",a.src=h,""})},this._storeTile=function(a,b,c,d){a=a.split("?")[0];var e=b?b+"?"+a:a,f=new XMLHttpRequest;f.open("GET",e,!0),f.overrideMimeType("text/plain; charset=x-user-defined"),f.onload=function(){if(200===f.status&&""!==f.responseText){var b=O.esri.Tiles.Base64Utils.wordToBase64(O.esri.Tiles.Base64Utils.stringToWord(this.responseText)),g={url:a,img:b};c.store(g,d)}else d(!1,f.status+" "+f.statusText+": "+f.response+" when downloading "+e)},f.onerror=function(a){d(!1,a)},f.send(null)},this._createCellsForOffline=function(a,b,c,d,e){for(var f=new O.esri.Tiles.TilingScheme(a),g=[],h=b;c>=h;h++){var i=f.getAllCellIdsInExtent(d,h);if(i.forEach(function(a){g.push({level:h,row:a[1],col:a[0]})}),g.length>5e3&&h!==c)break}e(g)},this._saveToFile=function(a,b,c){var d=[];d.push("url,img"),b.getAllTiles(function(b,e,f){if("end"===f){var g=new Blob([d.join("\r\n")],{type:"text/plain;charset=utf-8"}),h=O.esri.Tiles.saveAs(g,a);if(h.readyState===h.DONE)return h.error?c(!1,"Error saving file "+a):c(!0,"Saved "+(d.length-1)+" tiles ("+Math.floor(g.size/1024/1024*100)/100+" Mb) into "+a);h.onerror=function(){c(!1,"Error saving file "+a)},h.onwriteend=function(){c(!0,"Saved "+(d.length-1)+" tiles ("+Math.floor(g.size/1024/1024*100)/100+" Mb) into "+a)}}else d.push(b+","+e)})},this._estimateTileSize=function(a,b,c,d){if(b){var e=c?c+"?"+b:b;a.get(e,{handleAs:"text/plain; charset=x-user-defined",headers:{"X-Requested-With":""},timeout:2e3}).then(function(a){var b=O.esri.Tiles.Base64Utils.wordToBase64(O.esri.Tiles.Base64Utils.stringToWord(a));d(b.length+e.length,null)},function(a){d(null,a)})}else d(0/0)},this._loadFromFile=function(a,b,c){if(window.File&&window.FileReader&&window.FileList&&window.Blob){var d=new FileReader;d.onload=function(d){var e,f,g=d.target.result,h=g.split("\r\n"),i=0;if("url,img"!==h[0])return c(!1,"File "+a.name+" doesn't contain tiles that can be loaded");for(var j=1;j=c;c++)for(d=i;j>=d;d++)k.push([c,d]);return k}}; \ No newline at end of file +define(["dojo/query","dojo/request","esri/geometry/Polygon","dojo/_base/declare"],function(a,b,c,d){"use strict";return d("O.esri.Tiles.OfflineTilesEnabler",[],{getBasemapLayer:function(a){var b=a.layerIds[0];return a.getLayer(b)},extend:function(c,d,e,f){c._tilesCore=new O.esri.Tiles.TilesCore,c._lastTileUrl="",c._imageType="",c._minZoom=null,c._maxZoom=null,void 0===f||null===f?(c.DB_NAME="offline_tile_store",c.DB_OBJECTSTORE_NAME="tilepath"):(c.DB_NAME=f.dbName,c.DB_OBJECTSTORE_NAME=f.objectStoreName),c._getTileUrl=c.getTileUrl;var g=!0;return"undefined"!=typeof e&&(g=e),c.showBlankTiles=!0,c.offline={online:g,store:new O.esri.Tiles.TilesStore,proxyPath:null},c.offline.store.isSupported()?(c.offline.store.dbName=c.DB_NAME,c.offline.store.objectStoreName=c.DB_OBJECTSTORE_NAME,c.offline.store.init(function(b){b&&(c.resampling=!1,c.getTileUrl=function(b,d,e){var f=this._getTileUrl(b,d,e);if(this.offline.online)return""===c._imageType&&(c._imageType=this.tileInfo.format.toLowerCase()),c._lastTileUrl=f,f;f=f.split("?")[0];var g="void:/"+b+"/"+d+"/"+e,h=null;return c._tilesCore._getTiles(h,this._imageType,f,g,this.offline.store,a,c.showBlankTiles),g},d&&d(!0))}.bind(this)),c.getLevelEstimation=function(a,b,c){var d=new O.esri.Tiles.TilingScheme(this),e=d.getAllCellIdsInExtent(a,b),f={level:b,tileCount:e.length,sizeBytes:e.length*c};return f},c.prepareForOffline=function(a,b,d,e){c._tilesCore._createCellsForOffline(this,a,b,d,function(a){this._doNextTile(0,a,e)}.bind(this))},c.goOffline=function(){this.offline.online=!1},c.goOnline=function(){this.offline.online=!0,this.refresh()},c.isOnline=function(){return this.offline.online},c.deleteAllTiles=function(a){var b=this.offline.store;b.deleteAll(a)},c.getOfflineUsage=function(a){var b=this.offline.store;b.usedSpace(a)},c.getTilePolygons=function(a){c._tilesCore._getTilePolygons(this.offline.store,c.url,this,a)},c.saveToFile=function(a,b){c._tilesCore._saveToFile(a,this.offline.store,b)},c.loadFromFile=function(a,b){c._tilesCore._loadFromFile(a,this.offline.store,b)},c.getMaxZoom=function(a){null==this._maxZoom&&(this._maxZoom=c.tileInfo.lods[c.tileInfo.lods.length-1].level),a(this._maxZoom)},c.getMinZoom=function(a){null==this._minZoom&&(this._minZoom=c.tileInfo.lods[0].level),a(this._minZoom)},c.getMinMaxLOD=function(a,b){var d={},e=c.getMap(),f=e.getLevel()+a,g=e.getLevel()+b;return null!=this._maxZoom&&null!=this._minZoom?(d.max=Math.min(this._maxZoom,g),d.min=Math.max(this._minZoom,f)):(c.getMinZoom(function(a){d.min=Math.max(a,f)}),c.getMaxZoom(function(a){d.max=Math.min(a,g)})),d},c.estimateTileSize=function(a){c._tilesCore._estimateTileSize(b,this._lastTileUrl,this.offline.proxyPath,a)},c.getExtentBuffer=function(a,b){return b.xmin-=a,b.ymin-=a,b.xmax+=a,b.ymax+=a,b},c.getTileUrlsByExtent=function(a,b){var d=new O.esri.Tiles.TilingScheme(c),e=d.getAllCellIdsInExtent(a,b),f=[];return e.forEach(function(a){f.push(c.url+"/"+b+"/"+a[1]+"/"+a[0])}.bind(this)),f},void(c._doNextTile=function(a,b,d){var e=b[a],f=this._getTileUrl(e.level,e.row,e.col);c._tilesCore._storeTile(f,this.offline.proxyPath,this.offline.store,function(c,f){c||(f={cell:e,msg:f});var g=d({countNow:a,countMax:b.length,cell:e,error:f,finishedDownloading:!1});g||a===b.length-1?d({finishedDownloading:!0,cancelRequested:g}):this._doNextTile(a+1,b,d)}.bind(this))})):d(!1,"indexedDB not supported")}})}),"undefined"!=typeof O?O.esri.Tiles={}:(O={},O.esri={Tiles:{}}),O.esri.Tiles.Base64Utils={},O.esri.Tiles.Base64Utils.outputTypes={Base64:0,Hex:1,String:2,Raw:3},O.esri.Tiles.Base64Utils.addWords=function(a,b){var c=(65535&a)+(65535&b),d=(a>>16)+(b>>16)+(c>>16);return d<<16|65535&c},O.esri.Tiles.Base64Utils.stringToWord=function(a){for(var b=8,c=(1<e;e+=b)d[e>>5]|=(a.charCodeAt(e/b)&c)<e;e+=b)d.push(String.fromCharCode(a[e>>5]>>>e%32&c));return d.join("")},O.esri.Tiles.Base64Utils.wordToHex=function(a){for(var b="0123456789abcdef",c=[],d=0,e=4*a.length;e>d;d++)c.push(b.charAt(a[d>>2]>>d%4*8+4&15)+b.charAt(a[d>>2]>>d%4*8&15));return c.join("")},O.esri.Tiles.Base64Utils.wordToBase64=function(a){for(var b="=",c="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",d=[],e=0,f=4*a.length;f>e;e+=3)for(var g=(a[e>>2]>>8*(e%4)&255)<<16|(a[e+1>>2]>>8*((e+1)%4)&255)<<8|a[e+2>>2]>>8*((e+2)%4)&255,h=0;4>h;h++)8*e+6*h>32*a.length?d.push(b):d.push(c.charAt(g>>6*(3-h)&63));return d.join("")},/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ +O.esri.Tiles.saveAs=function(a){"use strict";var b=a.document,c=function(){return a.URL||a.webkitURL||a},d=a.URL||a.webkitURL||a,e=b.createElementNS("http://www.w3.org/1999/xhtml","a"),f=!a.externalHost&&"download"in e,g=a.webkitRequestFileSystem,h=a.requestFileSystem||g||a.mozRequestFileSystem,i=function(b){(a.setImmediate||a.setTimeout)(function(){throw b},0)},j="application/octet-stream",k=0,l=[],m=function(){for(var a=l.length;a--;){var b=l[a];"string"==typeof b?d.revokeObjectURL(b):b.remove()}l.length=0},n=function(a,b,c){b=[].concat(b);for(var d=b.length;d--;){var e=a["on"+b[d]];if("function"==typeof e)try{e.call(a,c||a)}catch(f){i(f)}}},o=function(d,i){var m,o,p,q=this,r=d.type,s=!1,t=function(){var a=c().createObjectURL(d);return l.push(a),a},u=function(){n(q,"writestart progress write writeend".split(" "))},v=function(){(s||!m)&&(m=t(d)),o?o.location.href=m:window.open(m,"_blank"),q.readyState=q.DONE,u()},w=function(a){return function(){return q.readyState!==q.DONE?a.apply(this,arguments):void 0}},x={create:!0,exclusive:!1};if(q.readyState=q.INIT,i||(i="download"),f){m=t(d),b=a.document,e=b.createElementNS("http://www.w3.org/1999/xhtml","a"),e.href=m,e.download=i;var y=b.createEvent("MouseEvents");return y.initMouseEvent("click",!0,!1,a,0,0,0,0,0,!1,!1,!1,!1,0,null),e.dispatchEvent(y),q.readyState=q.DONE,void u()}return a.chrome&&r&&r!==j&&(p=d.slice||d.webkitSlice,d=p.call(d,0,d.size,j),s=!0),g&&"download"!==i&&(i+=".download"),(r===j||g)&&(o=a),h?(k+=d.size,void h(a.TEMPORARY,k,w(function(a){a.root.getDirectory("saved",x,w(function(a){var b=function(){a.getFile(i,x,w(function(a){a.createWriter(w(function(b){b.onwriteend=function(b){o.location.href=a.toURL(),l.push(a),q.readyState=q.DONE,n(q,"writeend",b)},b.onerror=function(){var a=b.error;a.code!==a.ABORT_ERR&&v()},"writestart progress write abort".split(" ").forEach(function(a){b["on"+a]=q["on"+a]}),b.write(d),q.abort=function(){b.abort(),q.readyState=q.DONE},q.readyState=q.WRITING}),v)}),v)};a.getFile(i,{create:!1},w(function(a){a.remove(),b()}),w(function(a){a.code===a.NOT_FOUND_ERR?b():v()}))}),v)}),v)):void v()},p=o.prototype,q=function(a,b){return new o(a,b)};return p.abort=function(){var a=this;a.readyState=a.DONE,n(a,"abort")},p.readyState=p.INIT=0,p.WRITING=1,p.DONE=2,p.error=p.onwritestart=p.onprogress=p.onwrite=p.onabort=p.onerror=p.onwriteend=null,a.addEventListener("unload",m,!1),q}(this.self||this.window||this.content),O.esri.Tiles.TilesCore=function(){this._getTiles=function(a,b,c,d,e,f,g){e.retrieve(c,function(c,e){a=f("img[src="+d+"]")[0];var h;return c?(a.style.borderColor="blue",h="data:image/"+b+";base64,"+e.img):g?(a.style.borderColor="green",h="data:image/png;base64,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pmk0TROPj48Hn3l4eIimaSJN06O3A4NJwDMxm82ibdtXo4D5fB6r1Sp+//4dz8/Pw5H+6ekpdrtdJEkS8/n8S/9f713ie3vaceo9x557QAB451Sgfyin34HKshweunk5HzAej2MymXz5+f9nbjJyI9L39Wu5XP55+XQZ39uxR4Z3u90wSXjqEV0wAjhjx47oaZq63Me/ZhIQBAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEAAbAJQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEAvqe/BwCeKjUweoA8pQAAAABJRU5ErkJggg=="):h="data:image/png;base64,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AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDDwAwMBPAABGrpAUwAAAABJRU5ErkJggg==",a.style.visibility="visible",a.src=h,""})},this._storeTile=function(a,b,c,d){a=a.split("?")[0];var e=b?b+"?"+a:a,f=new XMLHttpRequest;f.open("GET",e,!0),f.overrideMimeType("text/plain; charset=x-user-defined"),f.onload=function(){if(200===f.status&&""!==f.responseText){var b=O.esri.Tiles.Base64Utils.wordToBase64(O.esri.Tiles.Base64Utils.stringToWord(this.responseText)),g={url:a,img:b};c.store(g,d)}else d(!1,f.status+" "+f.statusText+": "+f.response+" when downloading "+e)},f.onerror=function(a){d(!1,a)},f.send(null)},this._createCellsForOffline=function(a,b,c,d,e){for(var f=new O.esri.Tiles.TilingScheme(a),g=[],h=b;c>=h;h++){var i=f.getAllCellIdsInExtent(d,h);if(i.forEach(function(a){g.push({level:h,row:a[1],col:a[0]})}),g.length>5e3&&h!==c)break}e(g)},this._saveToFile=function(a,b,c){var d=[];d.push("url,img"),b.getAllTiles(function(b,e,f){if("end"===f){var g=new Blob([d.join("\r\n")],{type:"text/plain;charset=utf-8"}),h=O.esri.Tiles.saveAs(g,a);if(h.readyState===h.DONE)return h.error?c(!1,"Error saving file "+a):c(!0,"Saved "+(d.length-1)+" tiles ("+Math.floor(g.size/1024/1024*100)/100+" Mb) into "+a);h.onerror=function(){c(!1,"Error saving file "+a)},h.onwriteend=function(){c(!0,"Saved "+(d.length-1)+" tiles ("+Math.floor(g.size/1024/1024*100)/100+" Mb) into "+a)}}else d.push(b+","+e)})},this._estimateTileSize=function(a,b,c,d){if(b){var e=c?c+"?"+b:b;a.get(e,{handleAs:"text/plain; charset=x-user-defined",headers:{"X-Requested-With":""},timeout:2e3}).then(function(a){var b=O.esri.Tiles.Base64Utils.wordToBase64(O.esri.Tiles.Base64Utils.stringToWord(a));d(b.length+e.length,null)},function(a){d(null,a)})}else d(NaN)},this._loadFromFile=function(a,b,c){if(window.File&&window.FileReader&&window.FileList&&window.Blob){var d=new FileReader;d.onload=function(d){var e,f,g=d.target.result,h=g.split("\r\n"),i=0;if("url,img"!==h[0])return c(!1,"File "+a.name+" doesn't contain tiles that can be loaded");for(var j=1;j=c;c++)for(d=i;j>=d;d++)k.push([c,d]);return k}}; \ No newline at end of file diff --git a/dist/offline-tiles-basic-src.js b/dist/offline-tiles-basic-src.js index 1e5eea8..5603086 100644 --- a/dist/offline-tiles-basic-src.js +++ b/dist/offline-tiles-basic-src.js @@ -1,415 +1,415 @@ -/*! offline-editor-js - v2.11.0 - 2015-07-30 -* Copyright (c) 2015 Environmental Systems Research Institute, Inc. -* Apache License*/ -define([ - "dojo/query", - "dojo/request", - "esri/geometry/Polygon", - "dojo/_base/declare" - ], function(query, request, Polygon,declare) - { - "use strict"; - return declare("O.esri.Tiles.OfflineTilesEnabler",[],{ - /** - * Utility method to get the basemap layer reference - * @param map - * @returns {Number} layerId - */ - getBasemapLayer: function(map) - { - var layerId = map.layerIds[0]; - return map.getLayer(layerId); - }, - - /** - * Method that extends a layer object with the offline capability. - * After extending one layer, you can call layer.goOffline() or layer.goOnline() - * @param layer - * @param callback - * @param state Optional Recommended. Pre-sets whether or not the application is online or offline. - * Specifically used for applications that need to protect against browser reload/restart while offline. - * @param dbConfig is an optional object that can be used to customize the database name (`dbName`) and - * the object store (`objectStoreName`) name. Example: `{dbName: "TILES_TEST", objectStoreName: "TILES"}`. - * @returns {callback} callback(boolean, string) - */ - extend: function(layer,callback,/* boolean */ state,/* Object */ dbConfig) - { - console.log("extending layer", layer.url); - - layer._tilesCore = new O.esri.Tiles.TilesCore(); - layer._lastTileUrl = ""; - layer._imageType = ""; - layer._minZoom = null; - layer._maxZoom = null; - - if( dbConfig === undefined || dbConfig === null){ - // Database properties - layer.DB_NAME = "offline_tile_store"; // Sets the database name. - layer.DB_OBJECTSTORE_NAME = "tilepath"; // Represents an object store that allows access to a set of data in the IndexedDB database - } - else { - layer.DB_NAME = dbConfig.dbName; - layer.DB_OBJECTSTORE_NAME = dbConfig.objectStoreName; - } - - /* we add some methods to the layer object */ - /* we don't want to extend the tiled layer class, as it is a capability that we want to add only to one instance */ - /* we also add some additional attributes inside an "offline" object */ - - layer._getTileUrl = layer.getTileUrl; - - var isOnline = true; - if(typeof state != "undefined"){ - isOnline = state; console.log("STATE IS: " + state); - } - - /** - * Option to show/hide blank tile images. When using multiple basemap layers, - * if one has no tiles, this will display and cover another basemap storage which may have tiles. - * @type {boolean} - */ - layer.showBlankTiles = true; - - /** - * IMPORTANT! proxyPath is set to null by default since we assume Feature Service is CORS-enabled. - * All AGOL Feature Services are CORS-enabled. - * - * @type {{online: boolean, store: O.esri.Tiles.TilesStore, proxyPath: null}} - */ - layer.offline = { - online: isOnline, - store: new O.esri.Tiles.TilesStore(), - proxyPath: null - }; - - if( /*false &&*/ layer.offline.store.isSupported() ) - { - layer.offline.store.dbName = layer.DB_NAME; - layer.offline.store.objectStoreName = layer.DB_OBJECTSTORE_NAME; - // Important: wait to load tiles until after database has initialized! - layer.offline.store.init(function(success){ - if(success){ -// callback(true); - layer.resampling = false; - - /** - * Internal method that overrides the getTileUrl() method. - * If application is offline then tiles are written to local storage. - * Retrieves tiles as requested by the ArcGIS API for JavaScript. - * If a tile is in cache it is returned. - * If it is not in cache then one is retrieved over the internet. - * @param level - * @param row - * @param col - * @returns {String} URL - */ - layer.getTileUrl = function(level,row,col) - { - console.assert(!isNaN(level) && !isNaN(row) && !isNaN(col), "bad tile requested"); - - console.log("looking for tile",level,row,col); - var url = this._getTileUrl(level,row,col); - console.log("LIBRARY ONLINE " + this.offline.online); - if( this.offline.online ) - { - if(layer._imageType === "") { - layer._imageType = this.tileInfo.format.toLowerCase(); - } - console.log("fetching url online: ", url); - layer._lastTileUrl = url; - return url; - } - - url = url.split("?")[0]; - - /* temporary URL returned immediately, as we haven't retrieved the image from the indexeddb yet */ - var tileid = "void:/"+level+"/"+row+"/"+col; - - var img = null; - - layer._tilesCore._getTiles(img,this._imageType,url,tileid,this.offline.store,query,layer.showBlankTiles); - - return tileid; - }; - - callback && callback(true); // jshint ignore:line - } - }.bind(this)); - } - else - { - return callback(false, "indexedDB not supported"); - } - - /** - * Returns an object that contains the number of tiles that would need to be downloaded - * for the specified extent and zoom level, and the estimated byte size of such tiles. - * This method is useful to give the user an indication of the required time and space - * before launching the actual download operation. The byte size estimation is very rough. - * @param extent - * @param level - * @param tileSize - * @returns {{level: *, tileCount: Number, sizeBytes: number}} - */ - layer.getLevelEstimation = function(extent, level, tileSize) - { - var tilingScheme = new O.esri.Tiles.TilingScheme(this); - var cellIds = tilingScheme.getAllCellIdsInExtent(extent,level); - - var levelEstimation = { - level: level, - tileCount: cellIds.length, - sizeBytes: cellIds.length * tileSize - }; - - return levelEstimation; - }; - - /** - * Retrieves tiles and stores them in the local cache. - * @param minLevel - * @param maxLevel - * @param extent - * @param reportProgress - */ - layer.prepareForOffline = function(minLevel, maxLevel, extent, reportProgress) - { - layer._tilesCore._createCellsForOffline(this,minLevel,maxLevel,extent,function(cells){ - /* launch tile download */ - this._doNextTile(0, cells, reportProgress); - }.bind(this)); - }; - - /** - * This method puts the layer in offline mode. When in offline mode, - * the layer will not fetch any tile from the remote server. It - * will look up the tiles in the indexed db database and display them in the layer. - * If the tile can't be found in the local database it will show up blank - * (even if there is actual connectivity). The pair of methods goOffline() and - * goOnline()allows the developer to manually control the behaviour of the layer. - * Used in conjunction with the offline dectection library, you can put the layer in - * the appropriate mode when the offline condition changes. - */ - layer.goOffline = function() - { - this.offline.online = false; - }; - - /** - * This method puts the layer in online mode. When in online mode, the layer will - * behave as regular layers, fetching all tiles from the remote server. - * If there is no internet connectivity the tiles may appear thanks to the browsers cache, - * but no attempt will be made to look up tiles in the local database. - */ - layer.goOnline = function() - { - this.offline.online = true; - this.refresh(); - }; - - /** - * Determines if application is online or offline - * @returns {boolean} - */ - layer.isOnline = function() - { - return this.offline.online; - }; - - /** - * Clears the local cache of tiles. - * @param callback callback(boolean, errors) - */ - layer.deleteAllTiles = function(callback) // callback(success) or callback(false, error) - { - var store = this.offline.store; - store.deleteAll(callback); - }; - - /** - * Gets the size in bytes of the local tile cache. - * @param callback callback(size, error) - */ - layer.getOfflineUsage = function(callback) // callback({size: <>, tileCount: <>}) or callback(null,error) - { - var store = this.offline.store; - store.usedSpace(callback); - }; - - /** - * Gets polygons representing all cached cell ids within a particular - * zoom level and bounded by an extent. - * @param callback callback(polygon, error) - */ - layer.getTilePolygons = function(callback) // callback(Polygon polygon) or callback(null, error) - { - layer._tilesCore._getTilePolygons(this.offline.store,layer.url,this,callback); - }; - - /** - * Saves tile cache into a portable csv format. - * @param fileName - * @param callback callback( boolean, error) - */ - layer.saveToFile = function(fileName, callback) // callback(success, msg) - { - layer._tilesCore._saveToFile(fileName,this.offline.store,callback); - }; - - /** - * Reads a csv file into local tile cache. - * @param file - * @param callback callback( boolean, error) - */ - layer.loadFromFile = function(file, callback) // callback(success,msg) - { - console.log("reading",file); - layer._tilesCore._loadFromFile(file,this.offline.store,callback); - }; - - /** - * Returns the maximum zoom level for this layer - * @param callback number - */ - layer.getMaxZoom = function(callback){ - // TO-DO make this a simple return rather than a callback - if(this._maxZoom == null){ - this._maxZoom = layer.tileInfo.lods[layer.tileInfo.lods.length-1].level; - } - callback(this._maxZoom); - }; - - /** - * Returns the minimum zoom level for this layer - * @param callback number - */ - layer.getMinZoom = function(callback){ - // TO-DO make this a simple return rather than a callback - if(this._minZoom == null){ - this._minZoom = layer.tileInfo.lods[0].level; - } - callback(this._minZoom); - }; - - /** - * Utility method for bracketing above and below your current Level of Detail. Use - * this in conjunction with setting the minLevel and maxLevel in prepareForOffline(). - * @param minZoomAdjust An Integer specifying how far above the current layer you want to retrieve tiles - * @param maxZoomAdjust An Integer specifying how far below (closer to earth) the current layer you want to retrieve tiles - */ - layer.getMinMaxLOD = function(minZoomAdjust,maxZoomAdjust){ - var zoom = {}; - var map = layer.getMap(); - var min = map.getLevel() + minZoomAdjust; - var max = map.getLevel() + maxZoomAdjust; - if(this._maxZoom != null && this._minZoom != null){ - zoom.max = Math.min(this._maxZoom, max); //prevent errors by setting the tile layer floor - zoom.min = Math.max(this._minZoom, min); //prevent errors by setting the tile layer ceiling - } - else{ - layer.getMinZoom(function(result){ - zoom.min = Math.max(result, min); //prevent errors by setting the tile layer ceiling - }); - - layer.getMaxZoom(function(result){ - zoom.max = Math.min(result, max); //prevent errors by setting the tile layer floor - }); - } - - return zoom; - - }; - - /* internal methods */ - - /** - * Makes a request to a tile url and uses that as a basis for the - * the average tile size. - * Future Iterations could call multiple tiles and do an actual average. - * @param callback - * @returns {Number} Returns NaN if there was a problem retrieving the tile - */ - layer.estimateTileSize = function(callback) - { - layer._tilesCore._estimateTileSize(request,this._lastTileUrl,this.offline.proxyPath,callback); - }; - - /** - * Helper method that returns a new extent buffered by a given measurement that's based on map units. - * E.g. If you are using mercator then buffer would be in meters - * @param buffer - * @returns {Extent} - */ - layer.getExtentBuffer = function(/* int */ buffer, /* Extent */ extent){ - extent.xmin -= buffer; extent.ymin -= buffer; - extent.xmax += buffer; extent.ymax += buffer; - return extent; - }; - - /** - * Helper method that returns an array of tile urls within a given extent and level - * @returns Array - */ - layer.getTileUrlsByExtent = function(extent,level){ - var tilingScheme = new O.esri.Tiles.TilingScheme(layer); - var level_cell_ids = tilingScheme.getAllCellIdsInExtent(extent,level); - var cells = []; - - level_cell_ids.forEach(function(cell_id) - { - cells.push(layer.url + "/" + level + "/" + cell_id[1] + "/" + cell_id[0]); - }.bind(this)); - - return cells; - }; - - layer._doNextTile = function(i, cells, reportProgress) - { - var cell = cells[i]; - - var url = this._getTileUrl(cell.level,cell.row,cell.col); - - layer._tilesCore._storeTile(url,this.offline.proxyPath,this.offline.store, function(success, error) - { - if(!success) - { - console.log("error storing tile", cell, error); - error = { cell:cell, msg:error}; - } - - var cancelRequested = reportProgress({countNow:i, countMax:cells.length, cell: cell, error: error, finishedDownloading:false}); - - if( cancelRequested || i === cells.length-1 ) - { - reportProgress({ finishedDownloading: true, cancelRequested: cancelRequested}); - } - else - { - this._doNextTile(i+1, cells, reportProgress); - } - - }.bind(this)); - }; - } - }); // declare -}); // define - - -/** - * Creates a namespace for the non-AMD libraries in this directory - */ - -if(typeof O != "undefined"){ - O.esri.Tiles = {}; -} -else{ - O = {}; // jshint ignore:line - O.esri = { - Tiles: {} - }; -} - -//"use strict"; +/*! offline-editor-js - v2.12.0 - 2015-08-07 +* Copyright (c) 2015 Environmental Systems Research Institute, Inc. +* Apache License*/ +define([ + "dojo/query", + "dojo/request", + "esri/geometry/Polygon", + "dojo/_base/declare" + ], function(query, request, Polygon,declare) + { + "use strict"; + return declare("O.esri.Tiles.OfflineTilesEnabler",[],{ + /** + * Utility method to get the basemap layer reference + * @param map + * @returns {Number} layerId + */ + getBasemapLayer: function(map) + { + var layerId = map.layerIds[0]; + return map.getLayer(layerId); + }, + + /** + * Method that extends a layer object with the offline capability. + * After extending one layer, you can call layer.goOffline() or layer.goOnline() + * @param layer + * @param callback + * @param state Optional Recommended. Pre-sets whether or not the application is online or offline. + * Specifically used for applications that need to protect against browser reload/restart while offline. + * @param dbConfig is an optional object that can be used to customize the database name (`dbName`) and + * the object store (`objectStoreName`) name. Example: `{dbName: "TILES_TEST", objectStoreName: "TILES"}`. + * @returns {callback} callback(boolean, string) + */ + extend: function(layer,callback,/* boolean */ state,/* Object */ dbConfig) + { + console.log("extending layer", layer.url); + + layer._tilesCore = new O.esri.Tiles.TilesCore(); + layer._lastTileUrl = ""; + layer._imageType = ""; + layer._minZoom = null; + layer._maxZoom = null; + + if( dbConfig === undefined || dbConfig === null){ + // Database properties + layer.DB_NAME = "offline_tile_store"; // Sets the database name. + layer.DB_OBJECTSTORE_NAME = "tilepath"; // Represents an object store that allows access to a set of data in the IndexedDB database + } + else { + layer.DB_NAME = dbConfig.dbName; + layer.DB_OBJECTSTORE_NAME = dbConfig.objectStoreName; + } + + /* we add some methods to the layer object */ + /* we don't want to extend the tiled layer class, as it is a capability that we want to add only to one instance */ + /* we also add some additional attributes inside an "offline" object */ + + layer._getTileUrl = layer.getTileUrl; + + var isOnline = true; + if(typeof state != "undefined"){ + isOnline = state; console.log("STATE IS: " + state); + } + + /** + * Option to show/hide blank tile images. When using multiple basemap layers, + * if one has no tiles, this will display and cover another basemap storage which may have tiles. + * @type {boolean} + */ + layer.showBlankTiles = true; + + /** + * IMPORTANT! proxyPath is set to null by default since we assume Feature Service is CORS-enabled. + * All AGOL Feature Services are CORS-enabled. + * + * @type {{online: boolean, store: O.esri.Tiles.TilesStore, proxyPath: null}} + */ + layer.offline = { + online: isOnline, + store: new O.esri.Tiles.TilesStore(), + proxyPath: null + }; + + if( /*false &&*/ layer.offline.store.isSupported() ) + { + layer.offline.store.dbName = layer.DB_NAME; + layer.offline.store.objectStoreName = layer.DB_OBJECTSTORE_NAME; + // Important: wait to load tiles until after database has initialized! + layer.offline.store.init(function(success){ + if(success){ +// callback(true); + layer.resampling = false; + + /** + * Internal method that overrides the getTileUrl() method. + * If application is offline then tiles are written to local storage. + * Retrieves tiles as requested by the ArcGIS API for JavaScript. + * If a tile is in cache it is returned. + * If it is not in cache then one is retrieved over the internet. + * @param level + * @param row + * @param col + * @returns {String} URL + */ + layer.getTileUrl = function(level,row,col) + { + console.assert(!isNaN(level) && !isNaN(row) && !isNaN(col), "bad tile requested"); + + console.log("looking for tile",level,row,col); + var url = this._getTileUrl(level,row,col); + console.log("LIBRARY ONLINE " + this.offline.online); + if( this.offline.online ) + { + if(layer._imageType === "") { + layer._imageType = this.tileInfo.format.toLowerCase(); + } + console.log("fetching url online: ", url); + layer._lastTileUrl = url; + return url; + } + + url = url.split("?")[0]; + + /* temporary URL returned immediately, as we haven't retrieved the image from the indexeddb yet */ + var tileid = "void:/"+level+"/"+row+"/"+col; + + var img = null; + + layer._tilesCore._getTiles(img,this._imageType,url,tileid,this.offline.store,query,layer.showBlankTiles); + + return tileid; + }; + + callback && callback(true); // jshint ignore:line + } + }.bind(this)); + } + else + { + return callback(false, "indexedDB not supported"); + } + + /** + * Returns an object that contains the number of tiles that would need to be downloaded + * for the specified extent and zoom level, and the estimated byte size of such tiles. + * This method is useful to give the user an indication of the required time and space + * before launching the actual download operation. The byte size estimation is very rough. + * @param extent + * @param level + * @param tileSize + * @returns {{level: *, tileCount: Number, sizeBytes: number}} + */ + layer.getLevelEstimation = function(extent, level, tileSize) + { + var tilingScheme = new O.esri.Tiles.TilingScheme(this); + var cellIds = tilingScheme.getAllCellIdsInExtent(extent,level); + + var levelEstimation = { + level: level, + tileCount: cellIds.length, + sizeBytes: cellIds.length * tileSize + }; + + return levelEstimation; + }; + + /** + * Retrieves tiles and stores them in the local cache. + * @param minLevel + * @param maxLevel + * @param extent + * @param reportProgress + */ + layer.prepareForOffline = function(minLevel, maxLevel, extent, reportProgress) + { + layer._tilesCore._createCellsForOffline(this,minLevel,maxLevel,extent,function(cells){ + /* launch tile download */ + this._doNextTile(0, cells, reportProgress); + }.bind(this)); + }; + + /** + * This method puts the layer in offline mode. When in offline mode, + * the layer will not fetch any tile from the remote server. It + * will look up the tiles in the indexed db database and display them in the layer. + * If the tile can't be found in the local database it will show up blank + * (even if there is actual connectivity). The pair of methods goOffline() and + * goOnline()allows the developer to manually control the behaviour of the layer. + * Used in conjunction with the offline dectection library, you can put the layer in + * the appropriate mode when the offline condition changes. + */ + layer.goOffline = function() + { + this.offline.online = false; + }; + + /** + * This method puts the layer in online mode. When in online mode, the layer will + * behave as regular layers, fetching all tiles from the remote server. + * If there is no internet connectivity the tiles may appear thanks to the browsers cache, + * but no attempt will be made to look up tiles in the local database. + */ + layer.goOnline = function() + { + this.offline.online = true; + this.refresh(); + }; + + /** + * Determines if application is online or offline + * @returns {boolean} + */ + layer.isOnline = function() + { + return this.offline.online; + }; + + /** + * Clears the local cache of tiles. + * @param callback callback(boolean, errors) + */ + layer.deleteAllTiles = function(callback) // callback(success) or callback(false, error) + { + var store = this.offline.store; + store.deleteAll(callback); + }; + + /** + * Gets the size in bytes of the local tile cache. + * @param callback callback(size, error) + */ + layer.getOfflineUsage = function(callback) // callback({size: <>, tileCount: <>}) or callback(null,error) + { + var store = this.offline.store; + store.usedSpace(callback); + }; + + /** + * Gets polygons representing all cached cell ids within a particular + * zoom level and bounded by an extent. + * @param callback callback(polygon, error) + */ + layer.getTilePolygons = function(callback) // callback(Polygon polygon) or callback(null, error) + { + layer._tilesCore._getTilePolygons(this.offline.store,layer.url,this,callback); + }; + + /** + * Saves tile cache into a portable csv format. + * @param fileName + * @param callback callback( boolean, error) + */ + layer.saveToFile = function(fileName, callback) // callback(success, msg) + { + layer._tilesCore._saveToFile(fileName,this.offline.store,callback); + }; + + /** + * Reads a csv file into local tile cache. + * @param file + * @param callback callback( boolean, error) + */ + layer.loadFromFile = function(file, callback) // callback(success,msg) + { + console.log("reading",file); + layer._tilesCore._loadFromFile(file,this.offline.store,callback); + }; + + /** + * Returns the maximum zoom level for this layer + * @param callback number + */ + layer.getMaxZoom = function(callback){ + // TO-DO make this a simple return rather than a callback + if(this._maxZoom == null){ + this._maxZoom = layer.tileInfo.lods[layer.tileInfo.lods.length-1].level; + } + callback(this._maxZoom); + }; + + /** + * Returns the minimum zoom level for this layer + * @param callback number + */ + layer.getMinZoom = function(callback){ + // TO-DO make this a simple return rather than a callback + if(this._minZoom == null){ + this._minZoom = layer.tileInfo.lods[0].level; + } + callback(this._minZoom); + }; + + /** + * Utility method for bracketing above and below your current Level of Detail. Use + * this in conjunction with setting the minLevel and maxLevel in prepareForOffline(). + * @param minZoomAdjust An Integer specifying how far above the current layer you want to retrieve tiles + * @param maxZoomAdjust An Integer specifying how far below (closer to earth) the current layer you want to retrieve tiles + */ + layer.getMinMaxLOD = function(minZoomAdjust,maxZoomAdjust){ + var zoom = {}; + var map = layer.getMap(); + var min = map.getLevel() + minZoomAdjust; + var max = map.getLevel() + maxZoomAdjust; + if(this._maxZoom != null && this._minZoom != null){ + zoom.max = Math.min(this._maxZoom, max); //prevent errors by setting the tile layer floor + zoom.min = Math.max(this._minZoom, min); //prevent errors by setting the tile layer ceiling + } + else{ + layer.getMinZoom(function(result){ + zoom.min = Math.max(result, min); //prevent errors by setting the tile layer ceiling + }); + + layer.getMaxZoom(function(result){ + zoom.max = Math.min(result, max); //prevent errors by setting the tile layer floor + }); + } + + return zoom; + + }; + + /* internal methods */ + + /** + * Makes a request to a tile url and uses that as a basis for the + * the average tile size. + * Future Iterations could call multiple tiles and do an actual average. + * @param callback + * @returns {Number} Returns NaN if there was a problem retrieving the tile + */ + layer.estimateTileSize = function(callback) + { + layer._tilesCore._estimateTileSize(request,this._lastTileUrl,this.offline.proxyPath,callback); + }; + + /** + * Helper method that returns a new extent buffered by a given measurement that's based on map units. + * E.g. If you are using mercator then buffer would be in meters + * @param buffer + * @returns {Extent} + */ + layer.getExtentBuffer = function(/* int */ buffer, /* Extent */ extent){ + extent.xmin -= buffer; extent.ymin -= buffer; + extent.xmax += buffer; extent.ymax += buffer; + return extent; + }; + + /** + * Helper method that returns an array of tile urls within a given extent and level + * @returns Array + */ + layer.getTileUrlsByExtent = function(extent,level){ + var tilingScheme = new O.esri.Tiles.TilingScheme(layer); + var level_cell_ids = tilingScheme.getAllCellIdsInExtent(extent,level); + var cells = []; + + level_cell_ids.forEach(function(cell_id) + { + cells.push(layer.url + "/" + level + "/" + cell_id[1] + "/" + cell_id[0]); + }.bind(this)); + + return cells; + }; + + layer._doNextTile = function(i, cells, reportProgress) + { + var cell = cells[i]; + + var url = this._getTileUrl(cell.level,cell.row,cell.col); + + layer._tilesCore._storeTile(url,this.offline.proxyPath,this.offline.store, function(success, error) + { + if(!success) + { + console.log("error storing tile", cell, error); + error = { cell:cell, msg:error}; + } + + var cancelRequested = reportProgress({countNow:i, countMax:cells.length, cell: cell, error: error, finishedDownloading:false}); + + if( cancelRequested || i === cells.length-1 ) + { + reportProgress({ finishedDownloading: true, cancelRequested: cancelRequested}); + } + else + { + this._doNextTile(i+1, cells, reportProgress); + } + + }.bind(this)); + }; + } + }); // declare +}); // define + + +/** + * Creates a namespace for the non-AMD libraries in this directory + */ + +if(typeof O != "undefined"){ + O.esri.Tiles = {}; +} +else{ + O = {}; // jshint ignore:line + O.esri = { + Tiles: {} + }; +} + +//"use strict"; /*jslint bitwise: true */ O.esri.Tiles.Base64Utils={}; @@ -491,935 +491,935 @@ O.esri.Tiles.Base64Utils.wordToBase64=function(/* word[] */wa){ return s.join(""); // string }; -/*jslint bitwise: false */ -/* FileSaver.js - * A saveAs() FileSaver implementation. - * 2013-10-21 - * - * By Eli Grey, http://eligrey.com - * License: X11/MIT - * See LICENSE.md - */ - -/*global self */ -/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true, - plusplus: true */ - -/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ - - -O.esri.Tiles.saveAs = -// IE 10 support, see Eli Grey's original source -// || (typeof navigator !== 'undefined' && navigator.msSaveOrOpenBlob && navigator.msSaveOrOpenBlob.bind(navigator)) - function(view) { - "use strict"; - var - doc = view.document - // only get URL when necessary in case BlobBuilder.js hasn't overridden it yet - , get_URL = function() { - return view.URL || view.webkitURL || view; - } - , URL = view.URL || view.webkitURL || view - , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a") - , can_use_save_link = !view.externalHost && "download" in save_link - , click = function(node) { - var event = doc.createEvent("MouseEvents"); - event.initMouseEvent( - "click", true, false, view, 0, 0, 0, 0, 0 - , false, false, false, false, 0, null - ); - node.dispatchEvent(event); - } - , webkit_req_fs = view.webkitRequestFileSystem - , req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem - , throw_outside = function (ex) { - (view.setImmediate || view.setTimeout)(function() { - throw ex; - }, 0); - } - , force_saveable_type = "application/octet-stream" - , fs_min_size = 0 - , deletion_queue = [] - , process_deletion_queue = function() { - var i = deletion_queue.length; - while (i--) { - var file = deletion_queue[i]; - if (typeof file === "string") { // file is an object URL - URL.revokeObjectURL(file); - } else { // file is a File - file.remove(); - } - } - deletion_queue.length = 0; // clear queue - } - , dispatch = function(filesaver, event_types, event) { - event_types = [].concat(event_types); - var i = event_types.length; - while (i--) { - var listener = filesaver["on" + event_types[i]]; - if (typeof listener === "function") { - try { - listener.call(filesaver, event || filesaver); - } catch (ex) { - throw_outside(ex); - } - } - } - } - , FileSaver = function(blob, name) { - // First try a.download, then web filesystem, then object URLs - var - filesaver = this - , type = blob.type - , blob_changed = false - , object_url - , target_view - , get_object_url = function() { - var object_url = get_URL().createObjectURL(blob); - deletion_queue.push(object_url); - return object_url; - } - , dispatch_all = function() { - dispatch(filesaver, "writestart progress write writeend".split(" ")); - } - // on any filesys errors revert to saving with object URLs - , fs_error = function() { - // don't create more object URLs than needed - if (blob_changed || !object_url) { - object_url = get_object_url(blob); - } - if (target_view) { - target_view.location.href = object_url; - } else { - window.open(object_url, "_blank"); - } - filesaver.readyState = filesaver.DONE; - dispatch_all(); - } - , abortable = function(func) { - return function() { - if (filesaver.readyState !== filesaver.DONE) { - return func.apply(this, arguments); - } - }; - } - , create_if_not_found = {create: true, exclusive: false} - , slice - ; - filesaver.readyState = filesaver.INIT; - if (!name) { - name = "download"; - } - if (can_use_save_link) { - object_url = get_object_url(blob); - // FF for Android has a nasty garbage collection mechanism - // that turns all objects that are not pure javascript into 'deadObject' - // this means `doc` and `save_link` are unusable and need to be recreated - // `view` is usable though: - doc = view.document; - save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a"); - save_link.href = object_url; - save_link.download = name; - var event = doc.createEvent("MouseEvents"); - event.initMouseEvent( - "click", true, false, view, 0, 0, 0, 0, 0 - , false, false, false, false, 0, null - ); - save_link.dispatchEvent(event); - filesaver.readyState = filesaver.DONE; - dispatch_all(); - return; - } - // Object and web filesystem URLs have a problem saving in Google Chrome when - // viewed in a tab, so I force save with application/octet-stream - // http://code.google.com/p/chromium/issues/detail?id=91158 - if (view.chrome && type && type !== force_saveable_type) { - slice = blob.slice || blob.webkitSlice; - blob = slice.call(blob, 0, blob.size, force_saveable_type); - blob_changed = true; - } - // Since I can't be sure that the guessed media type will trigger a download - // in WebKit, I append .download to the filename. - // https://bugs.webkit.org/show_bug.cgi?id=65440 - if (webkit_req_fs && name !== "download") { - name += ".download"; - } - if (type === force_saveable_type || webkit_req_fs) { - target_view = view; - } - if (!req_fs) { - fs_error(); - return; - } - fs_min_size += blob.size; - req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) { - fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) { - var save = function() { - dir.getFile(name, create_if_not_found, abortable(function(file) { - file.createWriter(abortable(function(writer) { - writer.onwriteend = function(event) { - target_view.location.href = file.toURL(); - deletion_queue.push(file); - filesaver.readyState = filesaver.DONE; - dispatch(filesaver, "writeend", event); - }; - writer.onerror = function() { - var error = writer.error; - if (error.code !== error.ABORT_ERR) { - fs_error(); - } - }; - "writestart progress write abort".split(" ").forEach(function(event) { - writer["on" + event] = filesaver["on" + event]; - }); - writer.write(blob); - filesaver.abort = function() { - writer.abort(); - filesaver.readyState = filesaver.DONE; - }; - filesaver.readyState = filesaver.WRITING; - }), fs_error); - }), fs_error); - }; - dir.getFile(name, {create: false}, abortable(function(file) { - // delete file if it already exists - file.remove(); - save(); - }), abortable(function(ex) { - if (ex.code === ex.NOT_FOUND_ERR) { - save(); - } else { - fs_error(); - } - })); - }), fs_error); - }), fs_error); - } - , FS_proto = FileSaver.prototype - , saveAs = function(blob, name) { - return new FileSaver(blob, name); - } - ; - FS_proto.abort = function() { - var filesaver = this; - filesaver.readyState = filesaver.DONE; - dispatch(filesaver, "abort"); - }; - FS_proto.readyState = FS_proto.INIT = 0; - FS_proto.WRITING = 1; - FS_proto.DONE = 2; - - FS_proto.error = - FS_proto.onwritestart = - FS_proto.onprogress = - FS_proto.onwrite = - FS_proto.onabort = - FS_proto.onerror = - FS_proto.onwriteend = - null; - - view.addEventListener("unload", process_deletion_queue, false); - return saveAs; - -}(this.self || this.window || this.content); -// `self` is undefined in Firefox for Android content script context -// while `this` is nsIContentFrameMessageManager -// with an attribute `content` that corresponds to the window - -//if (typeof module !== 'undefined') module.exports = saveAs; - - -/** - * This library contains common core code between offlineTilesEnabler.js - * and OfflineTilesEnablerLayer.js - */ - -O.esri.Tiles.TilesCore = function(){ - - /** - * Retrieves a tile from local store. - * @param image a holder for the image that is retrieved from storage. - * @param imageType - * @param url the url of the tile - * @param tileid a reference to the tile's unique level, row and column - * @param store - * @param query Dojo Query - * @param showBlankTiles - * @private - */ - this._getTiles = function(image,imageType,url,tileid,store,query,showBlankTiles){ - store.retrieve(url, function(success, offlineTile) - { console.log("TILE RETURN " + success + ", " + offlineTile.url); - /* when the .getTileUrl() callback is triggered we replace the temporary URL originally returned by the data:image url */ - // search for the img with src="void:"+level+"-"+row+"-"+col and replace with actual url - image = query("img[src="+tileid+"]")[0]; - var imgURL; - - console.assert(image !== "undefined", "undefined image detected"); - - if( success ) - { - image.style.borderColor = "blue"; - console.log("found tile offline", url); - imgURL = "data:image/" + imageType +";base64," + offlineTile.img; - } - else if( !showBlankTiles ) { - console.log("showBlankTiles = false"); - imgURL = "data:image/png;base64," + "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AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDDwAwMBPAABGrpAUwAAAABJRU5ErkJggg=="; - } - else - { - image.style.borderColor = "green"; - console.log("tile is not in the offline store", url); - imgURL = "data:image/png;base64,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pmk0TROPj48Hn3l4eIimaSJN06O3A4NJwDMxm82ibdtXo4D5fB6r1Sp+//4dz8/Pw5H+6ekpdrtdJEkS8/n8S/9f713ie3vaceo9x557QAB451Sgfyin34HKshweunk5HzAej2MymXz5+f9nbjJyI9L39Wu5XP55+XQZ39uxR4Z3u90wSXjqEV0wAjhjx47oaZq63Me/ZhIQBAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEAAbAJQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEAvqe/BwCeKjUweoA8pQAAAABJRU5ErkJggg=="; - } - // when we return a nonexistent url to the image, the TiledMapServiceLayer::_tileErrorHandler() method - // sets img visibility to 'hidden', so we need to show the image back once we have put the data:image - image.style.visibility = "visible"; - image.src = imgURL; - return ""; /* this result goes nowhere, seriously */ - }); - }; - - /** - * Retrieves an image from a tile url and then stores it locally. - * @param url The image's url - * @param proxyPath - * @param store - * @param callback - * @private - */ - this._storeTile= function(url,proxyPath,store,callback) // callback(success, msg) - { - url = url.split("?")[0]; - - /* download the tile */ - var imgurl = proxyPath ? proxyPath + "?" + url : url; - var req = new XMLHttpRequest(); - req.open("GET", imgurl, true); - req.overrideMimeType("text/plain; charset=x-user-defined"); // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest?redirectlocale=en-US&redirectslug=DOM%2FXMLHttpRequest%2FUsing_XMLHttpRequest#Handling_binary_data - - req.onload = function () { - if (req.status === 200 && req.responseText !== "") { - var img = O.esri.Tiles.Base64Utils.wordToBase64(O.esri.Tiles.Base64Utils.stringToWord(this.responseText)); - - var tile = { - url: url, - img: img - }; - - store.store(tile, callback); - } - else { - console.log("xhr failed for", imgurl); - callback(false, req.status + " " + req.statusText + ": " + req.response + " when downloading " + imgurl); - } - }; - req.onerror = function (e) { - console.log("xhr failed for", imgurl); - callback(false, e); - }; - req.send(null); - }; - - /** - * Retrieves all the cells within a certain extent - * @param context Layer - * @param minLevel minimum zoom level - * @param maxLevel maximum zoom level - * @param extent Esri.Extent - * @param callback - * @private - */ - this._createCellsForOffline = function(context,minLevel,maxLevel,extent,callback){ - var tilingScheme = new O.esri.Tiles.TilingScheme(context); - var cells = []; - - for(var level=minLevel; level<=maxLevel; level++) - { - var level_cell_ids = tilingScheme.getAllCellIdsInExtent(extent,level); - - level_cell_ids.forEach(function(cell_id) - { - cells.push({ level: level, row: cell_id[1], col: cell_id[0]}); - }); - - // if the number of requested tiles is excessive, we just stop - if( cells.length > 5000 && level !== maxLevel) - { - console.log("enough is enough!"); - break; - } - } - callback(cells); - }; - - /** - * Saves locally stored tiles to a csv - * @param fileName - * @param store - * @param callback - * @private - */ - this._saveToFile = function(fileName,store,callback){ - var csv = []; - - csv.push("url,img"); - store.getAllTiles(function(url,img,evt) - { - if(evt==="end") - { - var blob = new Blob([ csv.join("\r\n") ], {type:"text/plain;charset=utf-8"}); - var saver = O.esri.Tiles.saveAs(blob, fileName); - - if( saver.readyState === saver.DONE ) - { - if( saver.error ) - { - return callback(false,"Error saving file " + fileName); - } - return callback(true, "Saved " + (csv.length-1) + " tiles (" + Math.floor(blob.size / 1024 / 1024 * 100) / 100 + " Mb) into " + fileName); - } - saver.onerror = function() { - callback(false,"Error saving file " + fileName); - }; - saver.onwriteend = function() - { - callback(true, "Saved " + (csv.length-1) + " tiles (" + Math.floor(blob.size / 1024 / 1024 * 100) / 100 + " Mb) into " + fileName); - }; - } - else - { - csv.push(url+","+img); - } - }); - }; - - /** - * Makes a request to a tile url and uses that as a basis for the - * the average tile size. - * Future Iterations could call multiple tiles and do an actual average. - * @param request "dojo/request" - * @param lastTileUrl FQDN of a tile location - * @param proxyPath your local proxy - * @param callback - * @returns {Number} Returns NaN if there was a problem retrieving the tile - */ - this._estimateTileSize = function(request,lastTileUrl,proxyPath,callback) - { - if(lastTileUrl) - { - var url = proxyPath? proxyPath + "?" + lastTileUrl : lastTileUrl; - request.get(url,{ - handleAs: "text/plain; charset=x-user-defined", - headers: { - "X-Requested-With": "" //bypasses a dojo xhr bug - }, - timeout: 2000 - }).then(function(response){ - var img = O.esri.Tiles.Base64Utils.wordToBase64(O.esri.Tiles.Base64Utils.stringToWord(response)); - callback(img.length + url.length,null); - }, - function(err){ - callback(null,err); - }); - } - else{ - callback(NaN); - } - }; - - /** - * Loads a csv file into storage. - * Format is "url,img\r\n somebase64image,http://esri.com" - * @param file - * @param store - * @param callback - * @private - */ - this._loadFromFile = function(file,store,callback){ - if (window.File && window.FileReader && window.FileList && window.Blob) - { - // Great success! All the File APIs are supported. - var reader = new FileReader(); - reader.onload = function(evt) - { - var csvContent = evt.target.result; - var tiles = csvContent.split("\r\n"); - var tileCount = 0; - var pair, tile; - - if(tiles[0] !== "url,img") - { - return callback(false, "File " + file.name + " doesn't contain tiles that can be loaded"); - } - - for(var i=1; i 5000 && level !== maxLevel) + { + console.log("enough is enough!"); + break; + } + } + callback(cells); + }; + + /** + * Saves locally stored tiles to a csv + * @param fileName + * @param store + * @param callback + * @private + */ + this._saveToFile = function(fileName,store,callback){ + var csv = []; + + csv.push("url,img"); + store.getAllTiles(function(url,img,evt) + { + if(evt==="end") + { + var blob = new Blob([ csv.join("\r\n") ], {type:"text/plain;charset=utf-8"}); + var saver = O.esri.Tiles.saveAs(blob, fileName); + + if( saver.readyState === saver.DONE ) + { + if( saver.error ) + { + return callback(false,"Error saving file " + fileName); + } + return callback(true, "Saved " + (csv.length-1) + " tiles (" + Math.floor(blob.size / 1024 / 1024 * 100) / 100 + " Mb) into " + fileName); + } + saver.onerror = function() { + callback(false,"Error saving file " + fileName); + }; + saver.onwriteend = function() + { + callback(true, "Saved " + (csv.length-1) + " tiles (" + Math.floor(blob.size / 1024 / 1024 * 100) / 100 + " Mb) into " + fileName); + }; + } + else + { + csv.push(url+","+img); + } + }); + }; + + /** + * Makes a request to a tile url and uses that as a basis for the + * the average tile size. + * Future Iterations could call multiple tiles and do an actual average. + * @param request "dojo/request" + * @param lastTileUrl FQDN of a tile location + * @param proxyPath your local proxy + * @param callback + * @returns {Number} Returns NaN if there was a problem retrieving the tile + */ + this._estimateTileSize = function(request,lastTileUrl,proxyPath,callback) + { + if(lastTileUrl) + { + var url = proxyPath? proxyPath + "?" + lastTileUrl : lastTileUrl; + request.get(url,{ + handleAs: "text/plain; charset=x-user-defined", + headers: { + "X-Requested-With": "" //bypasses a dojo xhr bug + }, + timeout: 2000 + }).then(function(response){ + var img = O.esri.Tiles.Base64Utils.wordToBase64(O.esri.Tiles.Base64Utils.stringToWord(response)); + callback(img.length + url.length,null); + }, + function(err){ + callback(null,err); + }); + } + else{ + callback(NaN); + } + }; + + /** + * Loads a csv file into storage. + * Format is "url,img\r\n somebase64image,http://esri.com" + * @param file + * @param store + * @param callback + * @private + */ + this._loadFromFile = function(file,store,callback){ + if (window.File && window.FileReader && window.FileList && window.Blob) + { + // Great success! All the File APIs are supported. + var reader = new FileReader(); + reader.onload = function(evt) + { + var csvContent = evt.target.result; + var tiles = csvContent.split("\r\n"); + var tileCount = 0; + var pair, tile; + + if(tiles[0] !== "url,img") + { + return callback(false, "File " + file.name + " doesn't contain tiles that can be loaded"); + } + + for(var i=1; ithis.MAX_DB_SIZE&&this.emit(this.DATABASE_ERROR_EVENT,{msg:this.DB_FULL_ERROR,err:b}),this.emit(this.VALIDATION_EVENT,{msg:this.DB_VALIDATED,err:null}),this._isDBValid=!0}.bind(this))}.bind(this)):this.emit(this.VALIDATION_EVENT,{msg:this.NO_SUPPORT_ERROR,err:null})},_parseInMemFiles:function(a,b){var c=this._fileEntriesLength;this._zeroLengthFileCounter=0;for(var d=[],e=0;c>e;e++){var f=new g,i=a[e].filename.toLocaleUpperCase(),j=i.indexOf("_ALLLAYERS",0);-1!=j&&(this.TILE_PATH=i.slice(0,j)),0===a[e].compressedSize&&this._zeroLengthFileCounter++;var k=i.indexOf("CONF.CDI",0),l=i.indexOf("CONF.XML",0),m=i.indexOf("BUNDLE",0),n=i.indexOf("BUNDLX",0);-1!=k||-1!=l?this._unzipConfFiles(a,e,f,function(a,b){a.resolve(b)}):-1!=m||-1!=n?this._unzipTileFiles(a,e,f,function(a,b){a.resolve(b)}):f.resolve(e),d.push(f)}h(d).then(function(a){b&&b(a)})},ObjectSize:function(a){var b,c=0;for(b in a)a.hasOwnProperty(b)&&c++;return c},_unzipConfFiles:function(a,b,c,d){a[b].getData(new O.esri.zip.TextWriter(b),function(b){this._inMemTilesIndex.push("blank");var e=a[b.token].filename.toLocaleUpperCase();this._inMemTilesObject[e]=b.string;var f=this.ObjectSize(this._inMemTilesObject);f>0&&d(c,b.token)}.bind(this))},_unzipTileFiles:function(a,b,c,d){var e=this;a[b].getData(new O.esri.zip.BlobWriter(b),function(b){if(0!==b.size){var f=new FileReader;f.token=b.token,f.onerror=function(a){e.emit(e.PARSING_ERROR,{msg:"Error parsing file: ",err:a.target.error})},f.onloadend=function(g){if(void 0!==f.token){e._inMemTilesIndex.push("blank");var h=a[f.token].filename.toLocaleUpperCase();e._inMemTilesObject[h]=f.result;var i=e.ObjectSize(e._inMemTilesObject);i>0&&d(c,b.token)}},f.readAsArrayBuffer(b)}})},_parseConfCdi:function(a){var c=this._inMemTilesObject[this.TILE_PATH+"CONF.CDI"],e=new O.esri.TPK.X2JS,f=e.xml_str2json(c),g=f.EnvelopeN,h=parseFloat(g.XMin),i=parseFloat(g.YMin),j=parseFloat(g.XMax),k=parseFloat(g.YMax),l=parseInt(g.SpatialReference.WKID),m=new b(h,i,j,k,new d({wkid:l}));a(m)},_parseConfXml:function(a){var b=this._inMemTilesObject[this.TILE_PATH+"CONF.XML"],c=new O.esri.TPK.X2JS,d=c.xml_str2json(b),e=d.CacheInfo,f={};f.rows=parseInt(e.TileCacheInfo.TileRows),f.cols=parseInt(e.TileCacheInfo.TileCols),f.dpi=parseInt(e.TileCacheInfo.DPI),f.format=e.TileImageInfo.CacheTileFormat,f.compressionQuality=parseInt(e.TileImageInfo.CompressionQuality),f.origin={x:parseInt(e.TileCacheInfo.TileOrigin.X),y:parseInt(e.TileCacheInfo.TileOrigin.Y)},f.spatialReference={wkid:parseInt(e.TileCacheInfo.SpatialReference.WKID)};for(var g=e.TileCacheInfo.LODInfos.LODInfo,h=[],i=0;im;m+=3)f=i[m]<<16|i[m+1]<<8|i[m+2],b=(16515072&f)>>18,c=(258048&f)>>12,d=(4032&f)>>6,e=63&f,g+=h[b]+h[c]+h[d]+h[e];return 1==k?(f=i[l],b=(252&f)>>2,c=(3&f)<<4,g+=h[b]+h[c]+"=="):2==k&&(f=i[l]<<8|i[l+1],b=(64512&f)>>10,c=(1008&f)>>4,d=(15&f)<<2,g+=h[b]+h[c]+h[d]+"="),g},_buffer2Base64:function(a,b,c){var d=new DataView(a,b),e=d.getInt32(0,!0),f=d.buffer.slice(b+4,b+4+e),g=this._base64ArrayBuffer(f);c(g)},_int2HexString:function(a){var b=a.toString(16).toUpperCase();return 1===b.length?"000"+b:2===b.length?"00"+b:3===b.length?"0"+b:b.substr(0,b.length)},_getOffset:function(a,b,c,d,e){var f=128*(c-e)+(b-d);return 16+5*f},_getCacheFilePath:function(a,b,c,d){var e=[];return e.push(a),e.push("/"),e.push("L"),e.push(10>b?"0"+b:b),e.push("/"),e.push("R"),e.push(this._int2HexString(c)),e.push("C"),e.push(this._int2HexString(d)),e.join("")},_bytes2MBs:function(a){return(a>>>20)+"."+(2046&a)}})}),"undefined"!=typeof O?O.esri.TPK={}:(O={},O.esri={TPK:{},Tiles:{}}),O.esri.Tiles.TilesStore=function(){this._db=null,this.dbName="offline_tile_store",this.objectStoreName="tilepath",this.isSupported=function(){return window.indexedDB||window.openDatabase?!0:!1},this.store=function(a,b){try{var c=this._db.transaction([this.objectStoreName],"readwrite");c.oncomplete=function(){b(!0)},c.onerror=function(a){b(!1,a.target.error.message)};var d=c.objectStore(this.objectStoreName),e=d.put(a);e.onsuccess=function(){}}catch(f){b(!1,f.stack)}},this.retrieve=function(a,b){if(null!==this._db){var c=this._db.transaction([this.objectStoreName]).objectStore(this.objectStoreName),d=c.get(a);d.onsuccess=function(a){var c=a.target.result;void 0===c?b(!1,"not found"):b(!0,c)},d.onerror=function(a){b(!1,a)}}},this.deleteAll=function(a){if(null!==this._db){var b=this._db.transaction([this.objectStoreName],"readwrite").objectStore(this.objectStoreName).clear();b.onsuccess=function(){a(!0)},b.onerror=function(b){a(!1,b)}}else a(!1,null)},this["delete"]=function(a,b){if(null!==this._db){var c=this._db.transaction([this.objectStoreName],"readwrite").objectStore(this.objectStoreName)["delete"](a);c.onsuccess=function(){b(!0)},c.onerror=function(a){b(!1,a)}}else b(!1,null)},this.getAllTiles=function(a){if(null!==this._db){var b=this._db.transaction([this.objectStoreName]).objectStore(this.objectStoreName).openCursor();b.onsuccess=function(b){var c=b.target.result;if(c){var d=c.value.url,e=c.value.img;a(d,e,null),c["continue"]()}else a(null,null,"end")}.bind(this),b.onerror=function(b){a(null,null,b)}}else a(null,null,"no db")},this.usedSpace=function(a){if(null!==this._db){var b={sizeBytes:0,tileCount:0},c=this._db.transaction([this.objectStoreName]).objectStore(this.objectStoreName).openCursor();c.onsuccess=function(c){var d=c.target.result;if(d){var e=d.value,f=JSON.stringify(e);b.sizeBytes+=this._stringBytes(f),b.tileCount+=1,d["continue"]()}else a(b,null)}.bind(this),c.onerror=function(b){a(null,b)}}else a(null,null)},this._stringBytes=function(a){return a.length},this.init=function(a){var b=indexedDB.open(this.dbName,4);a=a||function(a){}.bind(this),b.onerror=function(b){a(!1,b.target.errorCode)}.bind(this),b.onupgradeneeded=function(a){var b=a.target.result;b.objectStoreNames.contains(this.objectStoreName)&&b.deleteObjectStore(this.objectStoreName),b.createObjectStore(this.objectStoreName,{keyPath:"url"})}.bind(this),b.onsuccess=function(b){this._db=b.target.result,a(!0)}.bind(this)}},function(a){function b(){var a=-1,b=this;b.append=function(c){var d,e=b.table;for(d=0;d>>8^e[255&(a^c[d])]},b.get=function(){return~a}}function c(a,b,c){return a.slice?a.slice(b,b+c):a.webkitSlice?a.webkitSlice(b,b+c):a.mozSlice?a.mozSlice(b,b+c):a.msSlice?a.msSlice(b,b+c):void 0}function d(a,b){var c,d;return c=new ArrayBuffer(a),d=new Uint8Array(c),b&&d.set(b,0),{buffer:c,array:d,view:new DataView(c)}}function e(){}function f(a){function b(b,c){var f=new Blob([a],{type:M});d=new h(f),d.init(function(){e.size=d.size,b()},c)}function c(a,b,c,e){d.readUint8Array(a,b,c,e)}var d,e=this;e.size=0,e.init=b,e.readUint8Array=c}function g(b){function c(a){for(var c=b.length;"="==b.charAt(c-1);)c--;f=b.indexOf(",")+1,g.size=Math.floor(.75*(c-f)),a()}function e(c,e,g){var h,i=d(e),j=4*Math.floor(c/3),k=4*Math.ceil((c+e)/3),l=a.atob(b.substring(j+f,k+f)),m=c-3*Math.floor(j/4);for(h=m;m+e>h;h++)i.array[h-m]=l.charCodeAt(h);g(i.array)}var f,g=this;g.size=0,g.init=c,g.readUint8Array=e}function h(a){function b(b){this.size=a.size,b()}function d(b,d,e,f){var g=new FileReader;g.onload=function(a){e(new Uint8Array(a.target.result))},g.onerror=f,g.readAsArrayBuffer(c(a,b,d))}var e=this;e.size=0,e.init=b,e.readUint8Array=d}function i(){}function j(a,b){function c(a){f=new Blob([],{type:M}),a()}function d(a,b){f=new Blob([f,A?a:a.buffer],{type:M}),b()}function e(c,d){var e=new FileReader;e.onload=function(b){var d={string:b.target.result,token:a};c(d)},e.onerror=d,e.readAsText(f,b)}var f,g=this;g.init=c,g.writeUint8Array=d,g.getData=e}function k(b){function c(a){g+="data:"+(b||"")+";base64,",a()}function d(b,c){var d,e=h.length,f=h;for(h="",d=0;d<3*Math.floor((e+b.length)/3)-e;d++)f+=String.fromCharCode(b[d]);for(;d2?g+=a.btoa(f):h=f,c()}function e(b){b(g+a.btoa(h))}var f=this,g="",h="";f.init=c,f.writeUint8Array=d,f.getData=e}function l(a,b){function c(a){f=new Blob([],{type:b}),a()}function d(c,d){f=new Blob([f,A?c:c.buffer],{type:b}),f.token=a,d()}function e(a){a(f)}var f,g=this;g.init=c,g.writeUint8Array=d,g.getData=e}function m(a,b,c,d,e,f,g,h,i,j){function k(){a.removeEventListener(N,l,!1),h(o)}function l(a){var b=a.data,d=b.data;b.onappend&&(o+=d.length,c.writeUint8Array(d,function(){f(!1,d),m()},j)),b.onflush&&(d?(o+=d.length,c.writeUint8Array(d,function(){f(!1,d),k()},j)):k()),b.progress&&g&&g(n+b.current,e)}function m(){n=p*J,e>n?b.readUint8Array(d+n,Math.min(J,e-n),function(b){a.postMessage({append:!0,data:b}),p++,g&&g(n,e),f(!0,b)},i):a.postMessage({flush:!0})}var n,o,p=0;o=0,a.addEventListener(N,l,!1),m()}function n(a,b,c,d,e,f,g,h,i,j){function k(){var o;l=m*J,e>l?b.readUint8Array(d+l,Math.min(J,e-l),function(b){var h=a.append(b,function(){g&&g(d+l,e)});n+=h.length,f(!0,b),c.writeUint8Array(h,function(){f(!1,h),m++,setTimeout(k,1)},j),g&&g(l,e)},i):(o=a.flush(),o?(n+=o.length,c.writeUint8Array(o,function(){f(!1,o),h(n)},j)):h(n))}var l,m=0,n=0;k()}function o(c,d,e,f,g,h,i,j,k){function l(a,b){g&&!a&&q.append(b)}function o(a){h(a,q.get())}var p,q=new b;return a.zip.useWebWorkers?(p=new Worker(a.zip.workerScriptsPath+K),m(p,c,d,e,f,l,i,o,j,k)):n(new a.zip.Inflater,c,d,e,f,l,i,o,j,k),p}function p(c,d,e,f,g,h,i){function j(a,b){a&&p.append(b)}function k(a){f(a,p.get())}function l(){o.removeEventListener(N,l,!1),m(o,c,d,0,c.size,j,g,k,h,i)}var o,p=new b;return a.zip.useWebWorkers?(o=new Worker(a.zip.workerScriptsPath+L),o.addEventListener(N,l,!1),o.postMessage({init:!0,level:e})):n(new a.zip.Deflater,c,d,0,c.size,j,g,k,h,i),o}function q(a,c,d,e,f,g,h,i,j){function k(){var b=l*J;e>b?a.readUint8Array(d+b,Math.min(J,e-b),function(a){f&&m.append(a),h&&h(b,e,a),c.writeUint8Array(a,function(){l++,k()},j)},i):g(e,m.get())}var l=0,m=new b;k()}function r(a){var b,c,d="",e=["Ç","ü","é","â","ä","à","å","ç","ê","ë","è","ï","î","ì","Ä","Å","É","æ","Æ","ô","ö","ò","û","ù","ÿ","Ö","Ü","ø","£","Ø","×","ƒ","á","í","ó","ú","ñ","Ñ","ª","º","¿","®","¬","½","¼","¡","«","»","_","_","_","¦","¦","Á","Â","À","©","¦","¦","+","+","¢","¥","+","+","-","-","+","-","+","ã","Ã","+","+","-","-","¦","-","+","¤","ð","Ð","Ê","Ë","È","i","Í","Î","Ï","+","+","_","_","¦","Ì","_","Ó","ß","Ô","Ò","õ","Õ","µ","þ","Þ","Ú","Û","Ù","ý","Ý","¯","´","­","±","_","¾","¶","§","÷","¸","°","¨","·","¹","³","²","_"," "];for(b=0;b127?e[c-128]:String.fromCharCode(c);return d}function s(a){return decodeURIComponent(escape(a))}function t(a){var b,c="";for(b=0;b>16,c=65535&a;try{return new Date(1980+((65024&b)>>9),((480&b)>>5)-1,31&b,(63488&c)>>11,(2016&c)>>5,2*(31&c),0)}catch(d){}}function v(a,b,c,d,e){return a.version=b.view.getUint16(c,!0),a.bitFlag=b.view.getUint16(c+2,!0),a.compressionMethod=b.view.getUint16(c+4,!0),a.lastModDateRaw=b.view.getUint32(c+6,!0),a.lastModDate=u(a.lastModDateRaw),1===(1&a.bitFlag)?void e(C):((d||8!=(8&a.bitFlag))&&(a.crc32=b.view.getUint32(c+10,!0),a.compressedSize=b.view.getUint32(c+14,!0),a.uncompressedSize=b.view.getUint32(c+18,!0)),4294967295===a.compressedSize||4294967295===a.uncompressedSize?void e(D):(a.filenameLength=b.view.getUint16(c+22,!0),void(a.extraFieldLength=b.view.getUint16(c+24,!0))))}function w(a,b){function c(){}function e(c,f){a.readUint8Array(a.size-c,c,function(a){var b=d(a.length,a).view;1347093766!=b.getUint32(0)?e(c+1,f):f(b)},function(){b(E)})}return c.prototype.getData=function(c,e,f,g){function h(a,b){m&&m.terminate(),m=null,a&&a(b)}function i(a){var b=d(4);return b.view.setUint32(0,a),n.crc32==b.view.getUint32(0)}function j(a,b){g&&!i(b)?k():c.getData(function(a){h(e,a)})}function k(){h(b,H)}function l(){h(b,G)}var m,n=this;a.readUint8Array(n.offset,30,function(e){var h,i=d(e.length,e);return 1347093252!=i.view.getUint32(0)?void b(B):(v(n,i,4,!1,b),h=n.offset+30+n.filenameLength+n.extraFieldLength,void c.init(function(){0===n.compressionMethod?q(a,c,h,n.compressedSize,g,j,f,k,l):m=o(a,c,h,n.compressedSize,g,j,f,k,l)},l))},k)},{getEntries:function(f){return a.size<22?void b(B):void e(22,function(e){var g,h;g=e.getUint32(16,!0),h=e.getUint16(8,!0),a.readUint8Array(g,a.size-g,function(a){var e,g,i,j,k=0,l=[],m=d(a.length,a);for(e=0;h>e;e++){if(g=new c,1347092738!=m.view.getUint32(k))return void b(B);v(g,m,k+6,!0,b),g.commentLength=m.view.getUint16(k+32,!0),g.directory=16==(16&m.view.getUint8(k+38)),g.offset=m.view.getUint32(k+42,!0),i=t(m.array.subarray(k+46,k+46+g.filenameLength)),g.filename=2048===(2048&g.bitFlag)?s(i):r(i),g.directory||"/"!=g.filename.charAt(g.filename.length-1)||(g.directory=!0),j=t(m.array.subarray(k+46+g.filenameLength+g.extraFieldLength,k+46+g.filenameLength+g.extraFieldLength+g.commentLength)),g.comment=2048===(2048&g.bitFlag)?s(j):r(j),l.push(g),k+=46+g.filenameLength+g.extraFieldLength+g.commentLength}f(l)},function(){b(E)})})},close:function(a){a&&a()}}}function x(a){return unescape(encodeURIComponent(a))}function y(a){var b,c=[];for(b=0;ba;a++){for(c=a,b=0;8>b;b++)1&c?c=c>>>1^3988292384:c>>>=1;d[a]=c}return d}(),f.prototype=new e,f.prototype.constructor=f,g.prototype=new e,g.prototype.constructor=g,h.prototype=new e,h.prototype.constructor=h,i.prototype.getData=function(a){a(this.data)},j.prototype=new i,j.prototype.constructor=j,k.prototype=new i,k.prototype.constructor=k,l.prototype=new i,l.prototype.constructor=l,a.zip={Reader:e,Writer:i,BlobReader:h,Data64URIReader:g,TextReader:f,BlobWriter:l,Data64URIWriter:k,TextWriter:j,createReader:function(a,b,c){a.init(function(){b(w(a,c))},c)},createWriter:function(a,b,c,d){a.init(function(){b(z(a,c,d))},c)},workerScriptsPath:"",useWebWorkers:!0}}(O.esri),O.esri.TPK.autoCenterMap=function(a,b){function c(a){var b="onorientationchange"in window,c=b?"orientationchange":"resize";window.addEventListener(c,e(function(){d()},a))}function d(){require(["esri/geometry/Point","esri/SpatialReference"],function(b,c){var d=i().split(","),e=a.spatialReference.wkid,f=null;4326==e?f=new b(d[1],d[0]):102100==e&&(f=new b(d[0],d[1],new c({wkid:e}))),a.centerAt(f)})}function e(a,b,c){var d;return function(){var e=this,f=arguments;clearTimeout(d),d=setTimeout(function(){d=null,c||a.apply(e,f)},b),c&&!d&&a.apply(e,f)}}function f(){a.on("pan-end",function(){var b=a.extent.getCenter();h(b.x,b.y,a.spatialReference.wkid)})}function g(){a.on("zoom-end",function(){var b=a.extent.getCenter();h(b.x,b.y,a.spatialReference.wkid),a.setZoom(a.getZoom())})}function h(a,b,c){localStorage.setItem("_centerPtX",a),localStorage.setItem("_centerPtY",b),localStorage.setItem("_spatialReference",c)}function i(){var a=null;try{a=localStorage.getItem("_centerPtX")+","+localStorage.getItem("_centerPtY")+","+localStorage.getItem("_spatialReference")}catch(b){}return a}this.init=function(){f(),g(),c(b);var d=a.extent.getCenter();h(d.x,d.y,a.spatialReference.wkid)}},O.esri.TPK.inflate=function(a){function b(){function a(a,b,c,d,j,k,l,n,p,r,s){var t,u,v,w,x,y,z,A,C,D,E,F,G,H,I;D=0,x=c;do e[a[b+D]]++,D++,x--;while(0!==x);if(e[0]==c)return l[0]=-1,n[0]=0,i;for(A=n[0],y=1;B>=y&&0===e[y];y++);for(z=y,y>A&&(A=y),x=B;0!==x&&0===e[x];x--);for(v=x,A>x&&(A=x),n[0]=A,H=1<y;y++,H<<=1)if((H-=e[y])<0)return m;if((H-=e[x])<0)return m;for(e[x]+=H,h[1]=y=0,D=1,G=2;0!==--x;)h[G]=y+=e[D],G++,D++;x=0,D=0;do 0!==(y=a[b+D])&&(s[h[y]++]=x),D++;while(++x=z;z++)for(t=e[z];0!==t--;){for(;z>F+A;){if(w++,F+=A,I=v-F,I=I>A?A:I,(u=1<<(y=z-F))>t+1&&(u-=t+1,G=z,I>y))for(;++yq)return m;g[w]=E=r[0],r[0]+=I,0!==w?(h[w]=x,f[0]=y,f[1]=A,y=x>>>F-A,f[2]=E-g[w-1]-y,p.set(f,3*(g[w-1]+y))):l[0]=E}for(f[1]=z-F,D>=c?f[0]=192:s[D]>>F;I>y;y+=u)p.set(f,3*(E+y));for(y=1<>>=1)x^=y;for(x^=y,C=(1<b;b++)d[b]=0;for(b=0;B+1>b;b++)e[b]=0;for(b=0;3>b;b++)f[b]=0;g.set(e.subarray(0,B),0),h.set(e.subarray(0,B+1),0)}var c,d,e,f,g,h,j=this;j.inflate_trees_bits=function(e,f,g,h,i){var j;return b(19),c[0]=0,j=a(e,0,19,19,null,null,g,f,h,c,d),j==m?i.msg="oversubscribed dynamic bit lengths tree":(j==o||0===f[0])&&(i.msg="incomplete dynamic bit lengths tree",j=m),j},j.inflate_trees_dynamic=function(e,f,g,h,j,k,l,p,q){var r;return b(288),c[0]=0,r=a(g,0,e,257,x,y,k,h,p,c,d),r!=i||0===h[0]?(r==m?q.msg="oversubscribed literal/length tree":r!=n&&(q.msg="incomplete literal/length tree",r=m),r):(b(288),r=a(g,e,f,0,z,A,l,j,p,c,d),r!=i||0===j[0]&&e>257?(r==m?q.msg="oversubscribed distance tree":r==o?(q.msg="incomplete distance tree",r=m):r!=n&&(q.msg="empty distance tree with lengths",r=m),r):i)}}function c(){function a(a,b,c,d,e,f,g,h){var k,l,n,o,q,r,s,t,u,v,w,x,y,z,A,B;s=h.next_in_index,t=h.avail_in,q=g.bitb,r=g.bitk,u=g.write,v=ur;)t--,q|=(255&h.read_byte(s++))<>=l[B+1],r-=l[B+1],0!==(16&o)){for(o&=15,y=l[B+2]+(q&p[o]),q>>=o,r-=o;15>r;)t--,q|=(255&h.read_byte(s++))<>=l[B+1],r-=l[B+1],0!==(16&o)){for(o&=15;o>r;)t--,q|=(255&h.read_byte(s++))<>=o,r-=o,v-=y,u>=z)A=u-z,u-A>0&&2>u-A?(g.window[u++]=g.window[A++],g.window[u++]=g.window[A++],y-=2):(g.window.set(g.window.subarray(A,A+2),u),u+=2,A+=2,y-=2);else{A=u-z;do A+=g.end;while(0>A);if(o=g.end-A,y>o){if(y-=o,u-A>0&&o>u-A){do g.window[u++]=g.window[A++];while(0!==--o)}else g.window.set(g.window.subarray(A,A+o),u),u+=o,A+=o,o=0;A=0}}if(u-A>0&&y>u-A){do g.window[u++]=g.window[A++];while(0!==--y)}else g.window.set(g.window.subarray(A,A+y),u),u+=y,A+=y,y=0;break}if(0!==(64&o))return h.msg="invalid distance code",y=h.avail_in-t,y=y>r>>3?r>>3:y,t+=y,s-=y,r-=y<<3,g.bitb=q,g.bitk=r,h.avail_in=t,h.total_in+=s-h.next_in_index,h.next_in_index=s,g.write=u,m;k+=l[B+2],k+=q&p[o],B=3*(n+k),o=l[B]}break}if(0!==(64&o))return 0!==(32&o)?(y=h.avail_in-t,y=y>r>>3?r>>3:y,t+=y,s-=y,r-=y<<3,g.bitb=q,g.bitk=r,h.avail_in=t,h.total_in+=s-h.next_in_index,h.next_in_index=s,g.write=u,j):(h.msg="invalid literal/length code",y=h.avail_in-t,y=y>r>>3?r>>3:y,t+=y,s-=y,r-=y<<3,g.bitb=q,g.bitk=r,h.avail_in=t,h.total_in+=s-h.next_in_index,h.next_in_index=s,g.write=u,m);if(k+=l[B+2],k+=q&p[o],B=3*(n+k),0===(o=l[B])){q>>=l[B+1],r-=l[B+1],g.window[u++]=l[B+2],v--;break}}else q>>=l[B+1],r-=l[B+1],g.window[u++]=l[B+2],v--}while(v>=258&&t>=10);return y=h.avail_in-t,y=y>r>>3?r>>3:y,t+=y,s-=y,r-=y<<3,g.bitb=q,g.bitk=r,h.avail_in=t,h.total_in+=s-h.next_in_index,h.next_in_index=s,g.write=u,i}var b,c,d,e,f=this,g=0,h=0,k=0,n=0,o=0,q=0,r=0,s=0,t=0,u=0;f.init=function(a,f,g,h,i,j){b=C,r=a,s=f,d=g,t=h,e=i,u=j,c=null},f.proc=function(f,v,w){var x,y,z,A,B,M,N,O=0,P=0,Q=0;for(Q=v.next_in_index,A=v.avail_in,O=f.bitb,P=f.bitk,B=f.write,M=B=258&&A>=10&&(f.bitb=O,f.bitk=P,v.avail_in=A,v.total_in+=Q-v.next_in_index,v.next_in_index=Q,f.write=B,w=a(r,s,d,t,e,u,f,v),Q=v.next_in_index,A=v.avail_in,O=f.bitb,P=f.bitk,B=f.write,M=BP;){if(0===A)return f.bitb=O,f.bitk=P,v.avail_in=A,v.total_in+=Q-v.next_in_index,v.next_in_index=Q,f.write=B,f.inflate_flush(v,w);w=i,A--,O|=(255&v.read_byte(Q++))<>>=c[y+1],P-=c[y+1],z=c[y],0===z){n=c[y+2],b=I;break}if(0!==(16&z)){o=15&z, -g=c[y+2],b=E;break}if(0===(64&z)){k=z,h=y/3+c[y+2];break}if(0!==(32&z)){b=J;break}return b=L,v.msg="invalid literal/length code",w=m,f.bitb=O,f.bitk=P,v.avail_in=A,v.total_in+=Q-v.next_in_index,v.next_in_index=Q,f.write=B,f.inflate_flush(v,w);case E:for(x=o;x>P;){if(0===A)return f.bitb=O,f.bitk=P,v.avail_in=A,v.total_in+=Q-v.next_in_index,v.next_in_index=Q,f.write=B,f.inflate_flush(v,w);w=i,A--,O|=(255&v.read_byte(Q++))<>=x,P-=x,k=s,c=e,h=u,b=F;case F:for(x=k;x>P;){if(0===A)return f.bitb=O,f.bitk=P,v.avail_in=A,v.total_in+=Q-v.next_in_index,v.next_in_index=Q,f.write=B,f.inflate_flush(v,w);w=i,A--,O|=(255&v.read_byte(Q++))<>=c[y+1],P-=c[y+1],z=c[y],0!==(16&z)){o=15&z,q=c[y+2],b=G;break}if(0===(64&z)){k=z,h=y/3+c[y+2];break}return b=L,v.msg="invalid distance code",w=m,f.bitb=O,f.bitk=P,v.avail_in=A,v.total_in+=Q-v.next_in_index,v.next_in_index=Q,f.write=B,f.inflate_flush(v,w);case G:for(x=o;x>P;){if(0===A)return f.bitb=O,f.bitk=P,v.avail_in=A,v.total_in+=Q-v.next_in_index,v.next_in_index=Q,f.write=B,f.inflate_flush(v,w);w=i,A--,O|=(255&v.read_byte(Q++))<>=x,P-=x,b=H;case H:for(N=B-q;0>N;)N+=f.end;for(;0!==g;){if(0===M&&(B==f.end&&0!==f.read&&(B=0,M=B7&&(P-=8,A++,Q--),f.write=B,w=f.inflate_flush(v,w),B=f.write,M=Ba.avail_out&&(c=a.avail_out),0!==c&&b==o&&(b=i),a.avail_out-=c,a.total_out+=c,a.next_out.set(f.window.subarray(e,e+c),d),d+=c,e+=c,e==f.end&&(e=0,f.write==f.end&&(f.write=0),c=f.write-e,c>a.avail_out&&(c=a.avail_out),0!==c&&b==o&&(b=i),a.avail_out-=c,a.total_out+=c,a.next_out.set(f.window.subarray(e,e+c),d),d+=c,e+=c),a.next_out_index=d,f.read=e,b},f.proc=function(a,c){var d,o,q,w,y,z,A,B;for(w=a.next_in_index,y=a.avail_in,o=f.bitb,q=f.bitk,z=f.write,A=zq;){if(0===y)return f.bitb=o,f.bitk=q,a.avail_in=y,a.total_in+=w-a.next_in_index,a.next_in_index=w,f.write=z,f.inflate_flush(a,c);c=i,y--,o|=(255&a.read_byte(w++))<>>1){case 0:o>>>=3,q-=3,d=7&q,o>>>=d,q-=d,g=O;break;case 1:var C=[],D=[],E=[[]],F=[[]];b.inflate_trees_fixed(C,D,E,F),t.init(C[0],D[0],E[0],0,F[0],0),o>>>=3,q-=3,g=T;break;case 2:o>>>=3,q-=3,g=Q;break;case 3:return o>>>=3,q-=3,g=W,a.msg="invalid block type",c=m,f.bitb=o,f.bitk=q,a.avail_in=y,a.total_in+=w-a.next_in_index,a.next_in_index=w,f.write=z,f.inflate_flush(a,c)}break;case O:for(;32>q;){if(0===y)return f.bitb=o,f.bitk=q,a.avail_in=y,a.total_in+=w-a.next_in_index,a.next_in_index=w,f.write=z,f.inflate_flush(a,c);c=i,y--,o|=(255&a.read_byte(w++))<>>16&65535)!=(65535&o))return g=W,a.msg="invalid stored block lengths",c=m,f.bitb=o,f.bitk=q,a.avail_in=y,a.total_in+=w-a.next_in_index,a.next_in_index=w,f.write=z,f.inflate_flush(a,c);h=65535&o,o=q=0,g=0!==h?P:0!==u?U:N;break;case P:if(0===y)return f.bitb=o,f.bitk=q,a.avail_in=y,a.total_in+=w-a.next_in_index,a.next_in_index=w,f.write=z,f.inflate_flush(a,c);if(0===A&&(z==f.end&&0!==f.read&&(z=0,A=zy&&(d=y),d>A&&(d=A),f.window.set(a.read_buf(w,d),z),w+=d,y-=d,z+=d,A-=d,0!==(h-=d))break;g=0!==u?U:N;break;case Q:for(;14>q;){if(0===y)return f.bitb=o,f.bitk=q,a.avail_in=y,a.total_in+=w-a.next_in_index,a.next_in_index=w,f.write=z,f.inflate_flush(a,c);c=i,y--,o|=(255&a.read_byte(w++))<29||(d>>5&31)>29)return g=W,a.msg="too many length or distance symbols",c=m,f.bitb=o,f.bitk=q,a.avail_in=y,a.total_in+=w-a.next_in_index,a.next_in_index=w,f.write=z,f.inflate_flush(a,c);if(d=258+(31&d)+(d>>5&31),!e||e.lengthB;B++)e[B]=0;o>>>=14,q-=14,n=0,g=R;case R:for(;4+(k>>>10)>n;){for(;3>q;){if(0===y)return f.bitb=o,f.bitk=q,a.avail_in=y,a.total_in+=w-a.next_in_index,a.next_in_index=w,f.write=z,f.inflate_flush(a,c);c=i,y--,o|=(255&a.read_byte(w++))<>>=3,q-=3}for(;19>n;)e[M[n++]]=0;if(r[0]=7,d=x.inflate_trees_bits(e,r,s,v,a),d!=i)return c=d,c==m&&(e=null,g=W),f.bitb=o,f.bitk=q,a.avail_in=y,a.total_in+=w-a.next_in_index,a.next_in_index=w,f.write=z,f.inflate_flush(a,c);n=0,g=S;case S:for(;;){if(d=k,!(258+(31&d)+(d>>5&31)>n))break;var G,H;for(d=r[0];d>q;){if(0===y)return f.bitb=o,f.bitk=q,a.avail_in=y,a.total_in+=w-a.next_in_index,a.next_in_index=w,f.write=z,f.inflate_flush(a,c);c=i,y--,o|=(255&a.read_byte(w++))<H)o>>>=d,q-=d,e[n++]=H;else{for(B=18==H?7:H-14,G=18==H?11:3;d+B>q;){if(0===y)return f.bitb=o,f.bitk=q,a.avail_in=y,a.total_in+=w-a.next_in_index,a.next_in_index=w,f.write=z,f.inflate_flush(a,c);c=i,y--,o|=(255&a.read_byte(w++))<>>=d,q-=d,G+=o&p[B],o>>>=B,q-=B,B=n,d=k,B+G>258+(31&d)+(d>>5&31)||16==H&&1>B)return e=null,g=W,a.msg="invalid bit length repeat",c=m,f.bitb=o,f.bitk=q,a.avail_in=y,a.total_in+=w-a.next_in_index,a.next_in_index=w,f.write=z,f.inflate_flush(a,c);H=16==H?e[B-1]:0;do e[B++]=H;while(0!==--G);n=B}}s[0]=-1;var I=[],J=[],K=[],L=[];if(I[0]=9,J[0]=6,d=k,d=x.inflate_trees_dynamic(257+(31&d),1+(d>>5&31),e,I,J,K,L,v,a),d!=i)return d==m&&(e=null,g=W),c=d,f.bitb=o,f.bitk=q,a.avail_in=y,a.total_in+=w-a.next_in_index,a.next_in_index=w,f.write=z,f.inflate_flush(a,c);t.init(I[0],J[0],v,K[0],v,L[0]),g=T;case T:if(f.bitb=o,f.bitk=q,a.avail_in=y,a.total_in+=w-a.next_in_index,a.next_in_index=w,f.write=z,(c=t.proc(f,a,c))!=j)return f.inflate_flush(a,c);if(c=i,t.free(a),w=a.next_in_index,y=a.avail_in,o=f.bitb,q=f.bitk,z=f.write,A=ze||e>15?(b.inflateEnd(c),l):(b.wbits=e,c.istate.blocks=new d(c,1<>4)+8>a.istate.wbits){a.istate.mode=ga,a.msg="invalid window size",a.istate.marker=5;break}a.istate.mode=$;case $:if(0===a.avail_in)return c;if(c=b,a.avail_in--,a.total_in++,d=255&a.read_byte(a.next_in_index++),((a.istate.method<<8)+d)%31!==0){a.istate.mode=ga,a.msg="incorrect header check",a.istate.marker=5;break}if(0===(d&X)){a.istate.mode=ea;break}a.istate.mode=_;case _:if(0===a.avail_in)return c;c=b,a.avail_in--,a.total_in++,a.istate.need=(255&a.read_byte(a.next_in_index++))<<24&4278190080,a.istate.mode=aa;case aa:if(0===a.avail_in)return c;c=b,a.avail_in--,a.total_in++,a.istate.need+=(255&a.read_byte(a.next_in_index++))<<16&16711680,a.istate.mode=ba;case ba:if(0===a.avail_in)return c;c=b,a.avail_in--,a.total_in++,a.istate.need+=(255&a.read_byte(a.next_in_index++))<<8&65280,a.istate.mode=ca;case ca:return 0===a.avail_in?c:(c=b,a.avail_in--,a.total_in++,a.istate.need+=255&a.read_byte(a.next_in_index++),a.istate.mode=da,k);case da:return a.istate.mode=ga,a.msg="need dictionary",a.istate.marker=0,l;case ea:if(c=a.istate.blocks.proc(a,c),c==m){a.istate.mode=ga,a.istate.marker=0;break}if(c==i&&(c=b),c!=j)return c;c=b,a.istate.blocks.reset(a,a.istate.was),a.istate.mode=fa;case fa:return j;case ga:return m;default:return l}},b.inflateSetDictionary=function(a,b,c){var d=0,e=c;return a&&a.istate&&a.istate.mode==da?(e>=1<e;)b.read_byte(d)==ha[e]?e++:e=0!==b.read_byte(d)?0:4-e,d++,c--;return b.total_in+=d-b.next_in_index,b.next_in_index=d,b.avail_in=c,b.istate.marker=e,4!=e?m:(f=b.total_in,g=b.total_out,a(b),b.total_in=f,b.total_out=g,b.istate.mode=ea,i)},b.inflateSyncPoint=function(a){return a&&a.istate&&a.istate.blocks?a.istate.blocks.sync_point():l}}function f(){}function g(){var a=this,b=new f,c=512,d=r,e=new Uint8Array(c),g=!1;b.inflateInit(),b.next_out=e,a.append=function(a,f){var h,k,l=[],m=0,n=0,p=0;if(0!==a.length){b.next_in_index=0,b.next_in=a,b.avail_in=a.length;do{if(b.next_out_index=0,b.avail_out=c,0!==b.avail_in||g||(b.next_in_index=0,g=!0),h=b.inflate(d),g&&h==o)return-1;if(h!=i&&h!=j)throw"inflating: "+b.msg;if((g||h==j)&&b.avail_in==a.length)return-1;b.next_out_index&&l.push(b.next_out_index==c?new Uint8Array(e):new Uint8Array(e.subarray(0,b.next_out_index))),p+=b.next_out_index,f&&b.next_in_index>0&&b.next_in_index!=m&&(f(b.next_in_index),m=b.next_in_index)}while(b.avail_in>0||0===b.avail_out);return k=new Uint8Array(p),l.forEach(function(a){k.set(a,n),n+=a.length}),k}},a.flush=function(){b.inflateEnd()}}var h=15,i=0,j=1,k=2,l=-2,m=-3,n=-4,o=-5,p=[0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535],q=1440,r=0,s=4,t=9,u=5,v=[96,7,256,0,8,80,0,8,16,84,8,115,82,7,31,0,8,112,0,8,48,0,9,192,80,7,10,0,8,96,0,8,32,0,9,160,0,8,0,0,8,128,0,8,64,0,9,224,80,7,6,0,8,88,0,8,24,0,9,144,83,7,59,0,8,120,0,8,56,0,9,208,81,7,17,0,8,104,0,8,40,0,9,176,0,8,8,0,8,136,0,8,72,0,9,240,80,7,4,0,8,84,0,8,20,85,8,227,83,7,43,0,8,116,0,8,52,0,9,200,81,7,13,0,8,100,0,8,36,0,9,168,0,8,4,0,8,132,0,8,68,0,9,232,80,7,8,0,8,92,0,8,28,0,9,152,84,7,83,0,8,124,0,8,60,0,9,216,82,7,23,0,8,108,0,8,44,0,9,184,0,8,12,0,8,140,0,8,76,0,9,248,80,7,3,0,8,82,0,8,18,85,8,163,83,7,35,0,8,114,0,8,50,0,9,196,81,7,11,0,8,98,0,8,34,0,9,164,0,8,2,0,8,130,0,8,66,0,9,228,80,7,7,0,8,90,0,8,26,0,9,148,84,7,67,0,8,122,0,8,58,0,9,212,82,7,19,0,8,106,0,8,42,0,9,180,0,8,10,0,8,138,0,8,74,0,9,244,80,7,5,0,8,86,0,8,22,192,8,0,83,7,51,0,8,118,0,8,54,0,9,204,81,7,15,0,8,102,0,8,38,0,9,172,0,8,6,0,8,134,0,8,70,0,9,236,80,7,9,0,8,94,0,8,30,0,9,156,84,7,99,0,8,126,0,8,62,0,9,220,82,7,27,0,8,110,0,8,46,0,9,188,0,8,14,0,8,142,0,8,78,0,9,252,96,7,256,0,8,81,0,8,17,85,8,131,82,7,31,0,8,113,0,8,49,0,9,194,80,7,10,0,8,97,0,8,33,0,9,162,0,8,1,0,8,129,0,8,65,0,9,226,80,7,6,0,8,89,0,8,25,0,9,146,83,7,59,0,8,121,0,8,57,0,9,210,81,7,17,0,8,105,0,8,41,0,9,178,0,8,9,0,8,137,0,8,73,0,9,242,80,7,4,0,8,85,0,8,21,80,8,258,83,7,43,0,8,117,0,8,53,0,9,202,81,7,13,0,8,101,0,8,37,0,9,170,0,8,5,0,8,133,0,8,69,0,9,234,80,7,8,0,8,93,0,8,29,0,9,154,84,7,83,0,8,125,0,8,61,0,9,218,82,7,23,0,8,109,0,8,45,0,9,186,0,8,13,0,8,141,0,8,77,0,9,250,80,7,3,0,8,83,0,8,19,85,8,195,83,7,35,0,8,115,0,8,51,0,9,198,81,7,11,0,8,99,0,8,35,0,9,166,0,8,3,0,8,131,0,8,67,0,9,230,80,7,7,0,8,91,0,8,27,0,9,150,84,7,67,0,8,123,0,8,59,0,9,214,82,7,19,0,8,107,0,8,43,0,9,182,0,8,11,0,8,139,0,8,75,0,9,246,80,7,5,0,8,87,0,8,23,192,8,0,83,7,51,0,8,119,0,8,55,0,9,206,81,7,15,0,8,103,0,8,39,0,9,174,0,8,7,0,8,135,0,8,71,0,9,238,80,7,9,0,8,95,0,8,31,0,9,158,84,7,99,0,8,127,0,8,63,0,9,222,82,7,27,0,8,111,0,8,47,0,9,190,0,8,15,0,8,143,0,8,79,0,9,254,96,7,256,0,8,80,0,8,16,84,8,115,82,7,31,0,8,112,0,8,48,0,9,193,80,7,10,0,8,96,0,8,32,0,9,161,0,8,0,0,8,128,0,8,64,0,9,225,80,7,6,0,8,88,0,8,24,0,9,145,83,7,59,0,8,120,0,8,56,0,9,209,81,7,17,0,8,104,0,8,40,0,9,177,0,8,8,0,8,136,0,8,72,0,9,241,80,7,4,0,8,84,0,8,20,85,8,227,83,7,43,0,8,116,0,8,52,0,9,201,81,7,13,0,8,100,0,8,36,0,9,169,0,8,4,0,8,132,0,8,68,0,9,233,80,7,8,0,8,92,0,8,28,0,9,153,84,7,83,0,8,124,0,8,60,0,9,217,82,7,23,0,8,108,0,8,44,0,9,185,0,8,12,0,8,140,0,8,76,0,9,249,80,7,3,0,8,82,0,8,18,85,8,163,83,7,35,0,8,114,0,8,50,0,9,197,81,7,11,0,8,98,0,8,34,0,9,165,0,8,2,0,8,130,0,8,66,0,9,229,80,7,7,0,8,90,0,8,26,0,9,149,84,7,67,0,8,122,0,8,58,0,9,213,82,7,19,0,8,106,0,8,42,0,9,181,0,8,10,0,8,138,0,8,74,0,9,245,80,7,5,0,8,86,0,8,22,192,8,0,83,7,51,0,8,118,0,8,54,0,9,205,81,7,15,0,8,102,0,8,38,0,9,173,0,8,6,0,8,134,0,8,70,0,9,237,80,7,9,0,8,94,0,8,30,0,9,157,84,7,99,0,8,126,0,8,62,0,9,221,82,7,27,0,8,110,0,8,46,0,9,189,0,8,14,0,8,142,0,8,78,0,9,253,96,7,256,0,8,81,0,8,17,85,8,131,82,7,31,0,8,113,0,8,49,0,9,195,80,7,10,0,8,97,0,8,33,0,9,163,0,8,1,0,8,129,0,8,65,0,9,227,80,7,6,0,8,89,0,8,25,0,9,147,83,7,59,0,8,121,0,8,57,0,9,211,81,7,17,0,8,105,0,8,41,0,9,179,0,8,9,0,8,137,0,8,73,0,9,243,80,7,4,0,8,85,0,8,21,80,8,258,83,7,43,0,8,117,0,8,53,0,9,203,81,7,13,0,8,101,0,8,37,0,9,171,0,8,5,0,8,133,0,8,69,0,9,235,80,7,8,0,8,93,0,8,29,0,9,155,84,7,83,0,8,125,0,8,61,0,9,219,82,7,23,0,8,109,0,8,45,0,9,187,0,8,13,0,8,141,0,8,77,0,9,251,80,7,3,0,8,83,0,8,19,85,8,195,83,7,35,0,8,115,0,8,51,0,9,199,81,7,11,0,8,99,0,8,35,0,9,167,0,8,3,0,8,131,0,8,67,0,9,231,80,7,7,0,8,91,0,8,27,0,9,151,84,7,67,0,8,123,0,8,59,0,9,215,82,7,19,0,8,107,0,8,43,0,9,183,0,8,11,0,8,139,0,8,75,0,9,247,80,7,5,0,8,87,0,8,23,192,8,0,83,7,51,0,8,119,0,8,55,0,9,207,81,7,15,0,8,103,0,8,39,0,9,175,0,8,7,0,8,135,0,8,71,0,9,239,80,7,9,0,8,95,0,8,31,0,9,159,84,7,99,0,8,127,0,8,63,0,9,223,82,7,27,0,8,111,0,8,47,0,9,191,0,8,15,0,8,143,0,8,79,0,9,255],w=[80,5,1,87,5,257,83,5,17,91,5,4097,81,5,5,89,5,1025,85,5,65,93,5,16385,80,5,3,88,5,513,84,5,33,92,5,8193,82,5,9,90,5,2049,86,5,129,192,5,24577,80,5,2,87,5,385,83,5,25,91,5,6145,81,5,7,89,5,1537,85,5,97,93,5,24577,80,5,4,88,5,769,84,5,49,92,5,12289,82,5,13,90,5,3073,86,5,193,192,5,24577],x=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,0,0],y=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,112,112],z=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577],A=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],B=15;b.inflate_trees_fixed=function(a,b,c,d){return a[0]=t,b[0]=u,c[0]=v,d[0]=w,i};var C=0,D=1,E=2,F=3,G=4,H=5,I=6,J=7,K=8,L=9,M=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],N=0,O=1,P=2,Q=3,R=4,S=5,T=6,U=7,V=8,W=9,X=32,Y=8,Z=0,$=1,_=2,aa=3,ba=4,ca=5,da=6,ea=7,fa=12,ga=13,ha=[0,0,255,255];f.prototype={inflateInit:function(a){var b=this;return b.istate=new e,a||(a=h),b.istate.inflateInit(b,a)},inflate:function(a){var b=this;return b.istate?b.istate.inflate(b,a):l},inflateEnd:function(){var a=this;if(!a.istate)return l;var b=a.istate.inflateEnd(a);return a.istate=null,b},inflateSync:function(){var a=this;return a.istate?a.istate.inflateSync(a):l},inflateSetDictionary:function(a,b){var c=this;return c.istate?c.istate.inflateSetDictionary(c,a,b):l},read_byte:function(a){var b=this;return b.next_in.subarray(a,a+1)[0]},read_buf:function(a,b){var c=this;return c.next_in.subarray(a,a+b)}};var ia;a.zip?a.zip.Inflater=g:(ia=new g,a.addEventListener("message",function(b){var c=b.data;c.append&&a.postMessage({onappend:!0,data:ia.append(c.data,function(b){a.postMessage({progress:!0,current:b})})}),c.flush&&(ia.flush(),a.postMessage({onflush:!0}))},!1))},O.esri.TPK.___test=O.esri.TPK.inflate.toString(),O.esri.TPK.___blobURL=URL.createObjectURL(new Blob(["(",O.esri.TPK.___test,")(this)"],{type:"application/javascript"})),O.esri.zip.workerScriptsPath=O.esri.TPK.___blobURL,O.esri.TPK.X2JS=function(a){"use strict";function b(){void 0===a.escapeMode&&(a.escapeMode=!0),a.attributePrefix=a.attributePrefix||"_",a.arrayAccessForm=a.arrayAccessForm||"none",a.emptyNodeForm=a.emptyNodeForm||"text",void 0===a.enableToStringFunc&&(a.enableToStringFunc=!0),a.arrayAccessFormPaths=a.arrayAccessFormPaths||[],void 0===a.skipEmptyTextNodesForObj&&(a.skipEmptyTextNodesForObj=!0),void 0===a.stripWhitespaces&&(a.stripWhitespaces=!0),a.datetimeAccessFormPaths=a.datetimeAccessFormPaths||[]}function c(){function a(a){var b=String(a);return 1===b.length&&(b="0"+b),b}"function"!=typeof String.prototype.trim&&(String.prototype.trim=function(){return this.replace(/^\s+|^\n+|(\s|\n)+$/g,"")}),"function"!=typeof Date.prototype.toISOString&&(Date.prototype.toISOString=function(){return this.getUTCFullYear()+"-"+a(this.getUTCMonth()+1)+"-"+a(this.getUTCDate())+"T"+a(this.getUTCHours())+":"+a(this.getUTCMinutes())+":"+a(this.getUTCSeconds())+"."+String((this.getUTCMilliseconds()/1e3).toFixed(3)).slice(2,5)+"Z"})}function d(a){var b=a.localName;return null==b&&(b=a.baseName),(null==b||""==b)&&(b=a.nodeName),b}function e(a){return a.prefix}function f(a){return"string"==typeof a?a.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/"):a}function g(a){return a.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'").replace(///g,"/")}function h(b,c,d){switch(a.arrayAccessForm){case"property":b[c+"_asArray"]=b[c]instanceof Array?b[c]:[b[c]]}if(!(b[c]instanceof Array)&&a.arrayAccessFormPaths.length>0){for(var e=0;e1&&c.setMilliseconds(d[1]),b[6]&&b[7]){var e=60*b[6]+Number(b[7]),f=/\d\d-\d\d:\d\d$/.test(a)?"-":"+";e=0+("-"==f?-1*e:e),c.setMinutes(c.getMinutes()-e-c.getTimezoneOffset())}else-1!==a.indexOf("Z",a.length-1)&&(c=new Date(Date.UTC(c.getFullYear(),c.getMonth(),c.getDate(),c.getHours(),c.getMinutes(),c.getSeconds(),c.getMilliseconds())));return c}function j(b,c,d){if(a.datetimeAccessFormPaths.length>0){for(var e=d.split(".#")[0],f=0;f1&&null!=f.__text&&a.skipEmptyTextNodesForObj&&(a.stripWhitespaces&&""==f.__text||""==f.__text.trim())&&delete f.__text,delete f.__cnt,!a.enableToStringFunc||null==f.__text&&null==f.__cdata||(f.toString=function(){return(null!=this.__text?this.__text:"")+(null!=this.__cdata?this.__cdata:"")}),f}return b.nodeType==w.TEXT_NODE||b.nodeType==w.CDATA_SECTION_NODE?b.nodeValue:void 0}function l(b,c,d,e){var g="<"+(null!=b&&null!=b.__prefix?b.__prefix+":":"")+c;if(null!=d)for(var h=0;h":">"}function m(a,b){return""}function n(a,b){return-1!==a.indexOf(b,a.length-b.length)}function o(b,c){return"property"==a.arrayAccessForm&&n(c.toString(),"_asArray")||0==c.toString().indexOf(a.attributePrefix)||0==c.toString().indexOf("__")||b[c]instanceof Function?!0:!1}function p(a){var b=0;if(a instanceof Object)for(var c in a)o(a,c)||b++;return b}function q(b){var c=[];if(b instanceof Object)for(var d in b)-1==d.toString().indexOf("__")&&0==d.toString().indexOf(a.attributePrefix)&&c.push(d);return c}function r(b){var c="";return null!=b.__cdata&&(c+=""),null!=b.__text&&(c+=a.escapeMode?f(b.__text):b.__text),c}function s(b){var c="";return b instanceof Object?c+=r(b):null!=b&&(c+=a.escapeMode?f(b):b),c}function t(a,b,c){var d="";if(0==a.length)d+=l(a,b,c,!0);else for(var e=0;e0)for(var d in a)if(!o(a,d)){var e=a[d],f=q(e);if(null==e||void 0==e)b+=l(e,d,f,!0);else if(e instanceof Object)if(e instanceof Array)b+=t(e,d,f);else if(e instanceof Date)b+=l(e,d,f,!1),b+=e.toISOString(),b+=m(e,d);else{var g=p(e);g>0||null!=e.__text||null!=e.__cdata?(b+=l(e,d,f,!1),b+=u(e),b+=m(e,d)):b+=l(e,d,f,!0)}else b+=l(e,d,f,!1),b+=s(e),b+=m(e,d)}return b+=s(a)}var v="1.1.5",a=a||{};b(),c();var w={ELEMENT_NODE:1,TEXT_NODE:3,CDATA_SECTION_NODE:4,COMMENT_NODE:8,DOCUMENT_NODE:9};this.parseXmlString=function(a){var b=window.ActiveXObject||"ActiveXObject"in window;if(void 0===a)return null;var c;if(window.DOMParser){var d=new window.DOMParser,e=null;if(!b)try{e=d.parseFromString("INVALID","text/xml").childNodes[0].namespaceURI}catch(f){e=null}try{c=d.parseFromString(a,"text/xml"),null!=e&&c.getElementsByTagNameNS(e,"parsererror").length>0&&(c=null)}catch(f){c=null}}else 0==a.indexOf("")+2)),c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(a);return c},this.asArray=function(a){return a instanceof Array?a:[a]},this.toXmlDateTime=function(a){return a instanceof Date?a.toISOString():"number"==typeof a?new Date(a).toISOString():null},this.asDateTime=function(a){return"string"==typeof a?i(a):a},this.xml2json=function(a){return k(a)},this.xml_str2json=function(a){var b=this.parseXmlString(a);return null!=b?this.xml2json(b):null},this.json2xml_str=function(a){return u(a)},this.json2xml=function(a){var b=this.json2xml_str(a);return this.parseXmlString(b)},this.getVersion=function(){return v}}; \ No newline at end of file +g=c[y+2],b=E;break}if(0===(64&z)){k=z,h=y/3+c[y+2];break}if(0!==(32&z)){b=J;break}return b=L,v.msg="invalid literal/length code",w=m,f.bitb=O,f.bitk=P,v.avail_in=A,v.total_in+=Q-v.next_in_index,v.next_in_index=Q,f.write=B,f.inflate_flush(v,w);case E:for(x=o;x>P;){if(0===A)return f.bitb=O,f.bitk=P,v.avail_in=A,v.total_in+=Q-v.next_in_index,v.next_in_index=Q,f.write=B,f.inflate_flush(v,w);w=i,A--,O|=(255&v.read_byte(Q++))<>=x,P-=x,k=s,c=e,h=u,b=F;case F:for(x=k;x>P;){if(0===A)return f.bitb=O,f.bitk=P,v.avail_in=A,v.total_in+=Q-v.next_in_index,v.next_in_index=Q,f.write=B,f.inflate_flush(v,w);w=i,A--,O|=(255&v.read_byte(Q++))<>=c[y+1],P-=c[y+1],z=c[y],0!==(16&z)){o=15&z,q=c[y+2],b=G;break}if(0===(64&z)){k=z,h=y/3+c[y+2];break}return b=L,v.msg="invalid distance code",w=m,f.bitb=O,f.bitk=P,v.avail_in=A,v.total_in+=Q-v.next_in_index,v.next_in_index=Q,f.write=B,f.inflate_flush(v,w);case G:for(x=o;x>P;){if(0===A)return f.bitb=O,f.bitk=P,v.avail_in=A,v.total_in+=Q-v.next_in_index,v.next_in_index=Q,f.write=B,f.inflate_flush(v,w);w=i,A--,O|=(255&v.read_byte(Q++))<>=x,P-=x,b=H;case H:for(N=B-q;0>N;)N+=f.end;for(;0!==g;){if(0===M&&(B==f.end&&0!==f.read&&(B=0,M=B7&&(P-=8,A++,Q--),f.write=B,w=f.inflate_flush(v,w),B=f.write,M=Ba.avail_out&&(c=a.avail_out),0!==c&&b==o&&(b=i),a.avail_out-=c,a.total_out+=c,a.next_out.set(f.window.subarray(e,e+c),d),d+=c,e+=c,e==f.end&&(e=0,f.write==f.end&&(f.write=0),c=f.write-e,c>a.avail_out&&(c=a.avail_out),0!==c&&b==o&&(b=i),a.avail_out-=c,a.total_out+=c,a.next_out.set(f.window.subarray(e,e+c),d),d+=c,e+=c),a.next_out_index=d,f.read=e,b},f.proc=function(a,c){var d,o,q,w,y,z,A,B;for(w=a.next_in_index,y=a.avail_in,o=f.bitb,q=f.bitk,z=f.write,A=zq;){if(0===y)return f.bitb=o,f.bitk=q,a.avail_in=y,a.total_in+=w-a.next_in_index,a.next_in_index=w,f.write=z,f.inflate_flush(a,c);c=i,y--,o|=(255&a.read_byte(w++))<>>1){case 0:o>>>=3,q-=3,d=7&q,o>>>=d,q-=d,g=O;break;case 1:var C=[],D=[],E=[[]],F=[[]];b.inflate_trees_fixed(C,D,E,F),t.init(C[0],D[0],E[0],0,F[0],0),o>>>=3,q-=3,g=T;break;case 2:o>>>=3,q-=3,g=Q;break;case 3:return o>>>=3,q-=3,g=W,a.msg="invalid block type",c=m,f.bitb=o,f.bitk=q,a.avail_in=y,a.total_in+=w-a.next_in_index,a.next_in_index=w,f.write=z,f.inflate_flush(a,c)}break;case O:for(;32>q;){if(0===y)return f.bitb=o,f.bitk=q,a.avail_in=y,a.total_in+=w-a.next_in_index,a.next_in_index=w,f.write=z,f.inflate_flush(a,c);c=i,y--,o|=(255&a.read_byte(w++))<>>16&65535)!=(65535&o))return g=W,a.msg="invalid stored block lengths",c=m,f.bitb=o,f.bitk=q,a.avail_in=y,a.total_in+=w-a.next_in_index,a.next_in_index=w,f.write=z,f.inflate_flush(a,c);h=65535&o,o=q=0,g=0!==h?P:0!==u?U:N;break;case P:if(0===y)return f.bitb=o,f.bitk=q,a.avail_in=y,a.total_in+=w-a.next_in_index,a.next_in_index=w,f.write=z,f.inflate_flush(a,c);if(0===A&&(z==f.end&&0!==f.read&&(z=0,A=zy&&(d=y),d>A&&(d=A),f.window.set(a.read_buf(w,d),z),w+=d,y-=d,z+=d,A-=d,0!==(h-=d))break;g=0!==u?U:N;break;case Q:for(;14>q;){if(0===y)return f.bitb=o,f.bitk=q,a.avail_in=y,a.total_in+=w-a.next_in_index,a.next_in_index=w,f.write=z,f.inflate_flush(a,c);c=i,y--,o|=(255&a.read_byte(w++))<29||(d>>5&31)>29)return g=W,a.msg="too many length or distance symbols",c=m,f.bitb=o,f.bitk=q,a.avail_in=y,a.total_in+=w-a.next_in_index,a.next_in_index=w,f.write=z,f.inflate_flush(a,c);if(d=258+(31&d)+(d>>5&31),!e||e.lengthB;B++)e[B]=0;o>>>=14,q-=14,n=0,g=R;case R:for(;4+(k>>>10)>n;){for(;3>q;){if(0===y)return f.bitb=o,f.bitk=q,a.avail_in=y,a.total_in+=w-a.next_in_index,a.next_in_index=w,f.write=z,f.inflate_flush(a,c);c=i,y--,o|=(255&a.read_byte(w++))<>>=3,q-=3}for(;19>n;)e[M[n++]]=0;if(r[0]=7,d=x.inflate_trees_bits(e,r,s,v,a),d!=i)return c=d,c==m&&(e=null,g=W),f.bitb=o,f.bitk=q,a.avail_in=y,a.total_in+=w-a.next_in_index,a.next_in_index=w,f.write=z,f.inflate_flush(a,c);n=0,g=S;case S:for(;;){if(d=k,!(258+(31&d)+(d>>5&31)>n))break;var G,H;for(d=r[0];d>q;){if(0===y)return f.bitb=o,f.bitk=q,a.avail_in=y,a.total_in+=w-a.next_in_index,a.next_in_index=w,f.write=z,f.inflate_flush(a,c);c=i,y--,o|=(255&a.read_byte(w++))<H)o>>>=d,q-=d,e[n++]=H;else{for(B=18==H?7:H-14,G=18==H?11:3;d+B>q;){if(0===y)return f.bitb=o,f.bitk=q,a.avail_in=y,a.total_in+=w-a.next_in_index,a.next_in_index=w,f.write=z,f.inflate_flush(a,c);c=i,y--,o|=(255&a.read_byte(w++))<>>=d,q-=d,G+=o&p[B],o>>>=B,q-=B,B=n,d=k,B+G>258+(31&d)+(d>>5&31)||16==H&&1>B)return e=null,g=W,a.msg="invalid bit length repeat",c=m,f.bitb=o,f.bitk=q,a.avail_in=y,a.total_in+=w-a.next_in_index,a.next_in_index=w,f.write=z,f.inflate_flush(a,c);H=16==H?e[B-1]:0;do e[B++]=H;while(0!==--G);n=B}}s[0]=-1;var I=[],J=[],K=[],L=[];if(I[0]=9,J[0]=6,d=k,d=x.inflate_trees_dynamic(257+(31&d),1+(d>>5&31),e,I,J,K,L,v,a),d!=i)return d==m&&(e=null,g=W),c=d,f.bitb=o,f.bitk=q,a.avail_in=y,a.total_in+=w-a.next_in_index,a.next_in_index=w,f.write=z,f.inflate_flush(a,c);t.init(I[0],J[0],v,K[0],v,L[0]),g=T;case T:if(f.bitb=o,f.bitk=q,a.avail_in=y,a.total_in+=w-a.next_in_index,a.next_in_index=w,f.write=z,(c=t.proc(f,a,c))!=j)return f.inflate_flush(a,c);if(c=i,t.free(a),w=a.next_in_index,y=a.avail_in,o=f.bitb,q=f.bitk,z=f.write,A=ze||e>15?(b.inflateEnd(c),l):(b.wbits=e,c.istate.blocks=new d(c,1<>4)+8>a.istate.wbits){a.istate.mode=ga,a.msg="invalid window size",a.istate.marker=5;break}a.istate.mode=$;case $:if(0===a.avail_in)return c;if(c=b,a.avail_in--,a.total_in++,d=255&a.read_byte(a.next_in_index++),((a.istate.method<<8)+d)%31!==0){a.istate.mode=ga,a.msg="incorrect header check",a.istate.marker=5;break}if(0===(d&X)){a.istate.mode=ea;break}a.istate.mode=_;case _:if(0===a.avail_in)return c;c=b,a.avail_in--,a.total_in++,a.istate.need=(255&a.read_byte(a.next_in_index++))<<24&4278190080,a.istate.mode=aa;case aa:if(0===a.avail_in)return c;c=b,a.avail_in--,a.total_in++,a.istate.need+=(255&a.read_byte(a.next_in_index++))<<16&16711680,a.istate.mode=ba;case ba:if(0===a.avail_in)return c;c=b,a.avail_in--,a.total_in++,a.istate.need+=(255&a.read_byte(a.next_in_index++))<<8&65280,a.istate.mode=ca;case ca:return 0===a.avail_in?c:(c=b,a.avail_in--,a.total_in++,a.istate.need+=255&a.read_byte(a.next_in_index++),a.istate.mode=da,k);case da:return a.istate.mode=ga,a.msg="need dictionary",a.istate.marker=0,l;case ea:if(c=a.istate.blocks.proc(a,c),c==m){a.istate.mode=ga,a.istate.marker=0;break}if(c==i&&(c=b),c!=j)return c;c=b,a.istate.blocks.reset(a,a.istate.was),a.istate.mode=fa;case fa:return j;case ga:return m;default:return l}},b.inflateSetDictionary=function(a,b,c){var d=0,e=c;return a&&a.istate&&a.istate.mode==da?(e>=1<e;)b.read_byte(d)==ha[e]?e++:e=0!==b.read_byte(d)?0:4-e,d++,c--;return b.total_in+=d-b.next_in_index,b.next_in_index=d,b.avail_in=c,b.istate.marker=e,4!=e?m:(f=b.total_in,g=b.total_out,a(b),b.total_in=f,b.total_out=g,b.istate.mode=ea,i)},b.inflateSyncPoint=function(a){return a&&a.istate&&a.istate.blocks?a.istate.blocks.sync_point():l}}function f(){}function g(){var a=this,b=new f,c=512,d=r,e=new Uint8Array(c),g=!1;b.inflateInit(),b.next_out=e,a.append=function(a,f){var h,k,l=[],m=0,n=0,p=0;if(0!==a.length){b.next_in_index=0,b.next_in=a,b.avail_in=a.length;do{if(b.next_out_index=0,b.avail_out=c,0!==b.avail_in||g||(b.next_in_index=0,g=!0),h=b.inflate(d),g&&h==o)return-1;if(h!=i&&h!=j)throw"inflating: "+b.msg;if((g||h==j)&&b.avail_in==a.length)return-1;b.next_out_index&&(b.next_out_index==c?l.push(new Uint8Array(e)):l.push(new Uint8Array(e.subarray(0,b.next_out_index)))),p+=b.next_out_index,f&&b.next_in_index>0&&b.next_in_index!=m&&(f(b.next_in_index),m=b.next_in_index)}while(b.avail_in>0||0===b.avail_out);return k=new Uint8Array(p),l.forEach(function(a){k.set(a,n),n+=a.length}),k}},a.flush=function(){b.inflateEnd()}}var h=15,i=0,j=1,k=2,l=-2,m=-3,n=-4,o=-5,p=[0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535],q=1440,r=0,s=4,t=9,u=5,v=[96,7,256,0,8,80,0,8,16,84,8,115,82,7,31,0,8,112,0,8,48,0,9,192,80,7,10,0,8,96,0,8,32,0,9,160,0,8,0,0,8,128,0,8,64,0,9,224,80,7,6,0,8,88,0,8,24,0,9,144,83,7,59,0,8,120,0,8,56,0,9,208,81,7,17,0,8,104,0,8,40,0,9,176,0,8,8,0,8,136,0,8,72,0,9,240,80,7,4,0,8,84,0,8,20,85,8,227,83,7,43,0,8,116,0,8,52,0,9,200,81,7,13,0,8,100,0,8,36,0,9,168,0,8,4,0,8,132,0,8,68,0,9,232,80,7,8,0,8,92,0,8,28,0,9,152,84,7,83,0,8,124,0,8,60,0,9,216,82,7,23,0,8,108,0,8,44,0,9,184,0,8,12,0,8,140,0,8,76,0,9,248,80,7,3,0,8,82,0,8,18,85,8,163,83,7,35,0,8,114,0,8,50,0,9,196,81,7,11,0,8,98,0,8,34,0,9,164,0,8,2,0,8,130,0,8,66,0,9,228,80,7,7,0,8,90,0,8,26,0,9,148,84,7,67,0,8,122,0,8,58,0,9,212,82,7,19,0,8,106,0,8,42,0,9,180,0,8,10,0,8,138,0,8,74,0,9,244,80,7,5,0,8,86,0,8,22,192,8,0,83,7,51,0,8,118,0,8,54,0,9,204,81,7,15,0,8,102,0,8,38,0,9,172,0,8,6,0,8,134,0,8,70,0,9,236,80,7,9,0,8,94,0,8,30,0,9,156,84,7,99,0,8,126,0,8,62,0,9,220,82,7,27,0,8,110,0,8,46,0,9,188,0,8,14,0,8,142,0,8,78,0,9,252,96,7,256,0,8,81,0,8,17,85,8,131,82,7,31,0,8,113,0,8,49,0,9,194,80,7,10,0,8,97,0,8,33,0,9,162,0,8,1,0,8,129,0,8,65,0,9,226,80,7,6,0,8,89,0,8,25,0,9,146,83,7,59,0,8,121,0,8,57,0,9,210,81,7,17,0,8,105,0,8,41,0,9,178,0,8,9,0,8,137,0,8,73,0,9,242,80,7,4,0,8,85,0,8,21,80,8,258,83,7,43,0,8,117,0,8,53,0,9,202,81,7,13,0,8,101,0,8,37,0,9,170,0,8,5,0,8,133,0,8,69,0,9,234,80,7,8,0,8,93,0,8,29,0,9,154,84,7,83,0,8,125,0,8,61,0,9,218,82,7,23,0,8,109,0,8,45,0,9,186,0,8,13,0,8,141,0,8,77,0,9,250,80,7,3,0,8,83,0,8,19,85,8,195,83,7,35,0,8,115,0,8,51,0,9,198,81,7,11,0,8,99,0,8,35,0,9,166,0,8,3,0,8,131,0,8,67,0,9,230,80,7,7,0,8,91,0,8,27,0,9,150,84,7,67,0,8,123,0,8,59,0,9,214,82,7,19,0,8,107,0,8,43,0,9,182,0,8,11,0,8,139,0,8,75,0,9,246,80,7,5,0,8,87,0,8,23,192,8,0,83,7,51,0,8,119,0,8,55,0,9,206,81,7,15,0,8,103,0,8,39,0,9,174,0,8,7,0,8,135,0,8,71,0,9,238,80,7,9,0,8,95,0,8,31,0,9,158,84,7,99,0,8,127,0,8,63,0,9,222,82,7,27,0,8,111,0,8,47,0,9,190,0,8,15,0,8,143,0,8,79,0,9,254,96,7,256,0,8,80,0,8,16,84,8,115,82,7,31,0,8,112,0,8,48,0,9,193,80,7,10,0,8,96,0,8,32,0,9,161,0,8,0,0,8,128,0,8,64,0,9,225,80,7,6,0,8,88,0,8,24,0,9,145,83,7,59,0,8,120,0,8,56,0,9,209,81,7,17,0,8,104,0,8,40,0,9,177,0,8,8,0,8,136,0,8,72,0,9,241,80,7,4,0,8,84,0,8,20,85,8,227,83,7,43,0,8,116,0,8,52,0,9,201,81,7,13,0,8,100,0,8,36,0,9,169,0,8,4,0,8,132,0,8,68,0,9,233,80,7,8,0,8,92,0,8,28,0,9,153,84,7,83,0,8,124,0,8,60,0,9,217,82,7,23,0,8,108,0,8,44,0,9,185,0,8,12,0,8,140,0,8,76,0,9,249,80,7,3,0,8,82,0,8,18,85,8,163,83,7,35,0,8,114,0,8,50,0,9,197,81,7,11,0,8,98,0,8,34,0,9,165,0,8,2,0,8,130,0,8,66,0,9,229,80,7,7,0,8,90,0,8,26,0,9,149,84,7,67,0,8,122,0,8,58,0,9,213,82,7,19,0,8,106,0,8,42,0,9,181,0,8,10,0,8,138,0,8,74,0,9,245,80,7,5,0,8,86,0,8,22,192,8,0,83,7,51,0,8,118,0,8,54,0,9,205,81,7,15,0,8,102,0,8,38,0,9,173,0,8,6,0,8,134,0,8,70,0,9,237,80,7,9,0,8,94,0,8,30,0,9,157,84,7,99,0,8,126,0,8,62,0,9,221,82,7,27,0,8,110,0,8,46,0,9,189,0,8,14,0,8,142,0,8,78,0,9,253,96,7,256,0,8,81,0,8,17,85,8,131,82,7,31,0,8,113,0,8,49,0,9,195,80,7,10,0,8,97,0,8,33,0,9,163,0,8,1,0,8,129,0,8,65,0,9,227,80,7,6,0,8,89,0,8,25,0,9,147,83,7,59,0,8,121,0,8,57,0,9,211,81,7,17,0,8,105,0,8,41,0,9,179,0,8,9,0,8,137,0,8,73,0,9,243,80,7,4,0,8,85,0,8,21,80,8,258,83,7,43,0,8,117,0,8,53,0,9,203,81,7,13,0,8,101,0,8,37,0,9,171,0,8,5,0,8,133,0,8,69,0,9,235,80,7,8,0,8,93,0,8,29,0,9,155,84,7,83,0,8,125,0,8,61,0,9,219,82,7,23,0,8,109,0,8,45,0,9,187,0,8,13,0,8,141,0,8,77,0,9,251,80,7,3,0,8,83,0,8,19,85,8,195,83,7,35,0,8,115,0,8,51,0,9,199,81,7,11,0,8,99,0,8,35,0,9,167,0,8,3,0,8,131,0,8,67,0,9,231,80,7,7,0,8,91,0,8,27,0,9,151,84,7,67,0,8,123,0,8,59,0,9,215,82,7,19,0,8,107,0,8,43,0,9,183,0,8,11,0,8,139,0,8,75,0,9,247,80,7,5,0,8,87,0,8,23,192,8,0,83,7,51,0,8,119,0,8,55,0,9,207,81,7,15,0,8,103,0,8,39,0,9,175,0,8,7,0,8,135,0,8,71,0,9,239,80,7,9,0,8,95,0,8,31,0,9,159,84,7,99,0,8,127,0,8,63,0,9,223,82,7,27,0,8,111,0,8,47,0,9,191,0,8,15,0,8,143,0,8,79,0,9,255],w=[80,5,1,87,5,257,83,5,17,91,5,4097,81,5,5,89,5,1025,85,5,65,93,5,16385,80,5,3,88,5,513,84,5,33,92,5,8193,82,5,9,90,5,2049,86,5,129,192,5,24577,80,5,2,87,5,385,83,5,25,91,5,6145,81,5,7,89,5,1537,85,5,97,93,5,24577,80,5,4,88,5,769,84,5,49,92,5,12289,82,5,13,90,5,3073,86,5,193,192,5,24577],x=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,0,0],y=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,112,112],z=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577],A=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],B=15;b.inflate_trees_fixed=function(a,b,c,d){return a[0]=t,b[0]=u,c[0]=v,d[0]=w,i};var C=0,D=1,E=2,F=3,G=4,H=5,I=6,J=7,K=8,L=9,M=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],N=0,O=1,P=2,Q=3,R=4,S=5,T=6,U=7,V=8,W=9,X=32,Y=8,Z=0,$=1,_=2,aa=3,ba=4,ca=5,da=6,ea=7,fa=12,ga=13,ha=[0,0,255,255];f.prototype={inflateInit:function(a){var b=this;return b.istate=new e,a||(a=h),b.istate.inflateInit(b,a)},inflate:function(a){var b=this;return b.istate?b.istate.inflate(b,a):l},inflateEnd:function(){var a=this;if(!a.istate)return l;var b=a.istate.inflateEnd(a);return a.istate=null,b},inflateSync:function(){var a=this;return a.istate?a.istate.inflateSync(a):l},inflateSetDictionary:function(a,b){var c=this;return c.istate?c.istate.inflateSetDictionary(c,a,b):l},read_byte:function(a){var b=this;return b.next_in.subarray(a,a+1)[0]},read_buf:function(a,b){var c=this;return c.next_in.subarray(a,a+b)}};var ia;a.zip?a.zip.Inflater=g:(ia=new g,a.addEventListener("message",function(b){var c=b.data;c.append&&a.postMessage({onappend:!0,data:ia.append(c.data,function(b){a.postMessage({progress:!0,current:b})})}),c.flush&&(ia.flush(),a.postMessage({onflush:!0}))},!1))},O.esri.TPK.___test=O.esri.TPK.inflate.toString(),O.esri.TPK.___blobURL=URL.createObjectURL(new Blob(["(",O.esri.TPK.___test,")(this)"],{type:"application/javascript"})),O.esri.zip.workerScriptsPath=O.esri.TPK.___blobURL,O.esri.TPK.X2JS=function(a){"use strict";function b(){void 0===a.escapeMode&&(a.escapeMode=!0),a.attributePrefix=a.attributePrefix||"_",a.arrayAccessForm=a.arrayAccessForm||"none",a.emptyNodeForm=a.emptyNodeForm||"text",void 0===a.enableToStringFunc&&(a.enableToStringFunc=!0),a.arrayAccessFormPaths=a.arrayAccessFormPaths||[],void 0===a.skipEmptyTextNodesForObj&&(a.skipEmptyTextNodesForObj=!0),void 0===a.stripWhitespaces&&(a.stripWhitespaces=!0),a.datetimeAccessFormPaths=a.datetimeAccessFormPaths||[]}function c(){function a(a){var b=String(a);return 1===b.length&&(b="0"+b),b}"function"!=typeof String.prototype.trim&&(String.prototype.trim=function(){return this.replace(/^\s+|^\n+|(\s|\n)+$/g,"")}),"function"!=typeof Date.prototype.toISOString&&(Date.prototype.toISOString=function(){return this.getUTCFullYear()+"-"+a(this.getUTCMonth()+1)+"-"+a(this.getUTCDate())+"T"+a(this.getUTCHours())+":"+a(this.getUTCMinutes())+":"+a(this.getUTCSeconds())+"."+String((this.getUTCMilliseconds()/1e3).toFixed(3)).slice(2,5)+"Z"})}function d(a){var b=a.localName;return null==b&&(b=a.baseName),(null==b||""==b)&&(b=a.nodeName),b}function e(a){return a.prefix}function f(a){return"string"==typeof a?a.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/"):a}function g(a){return a.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'").replace(///g,"/")}function h(b,c,d){switch(a.arrayAccessForm){case"property":b[c]instanceof Array?b[c+"_asArray"]=b[c]:b[c+"_asArray"]=[b[c]]}if(!(b[c]instanceof Array)&&a.arrayAccessFormPaths.length>0){for(var e=0;e1&&c.setMilliseconds(d[1]),b[6]&&b[7]){var e=60*b[6]+Number(b[7]),f=/\d\d-\d\d:\d\d$/.test(a)?"-":"+";e=0+("-"==f?-1*e:e),c.setMinutes(c.getMinutes()-e-c.getTimezoneOffset())}else-1!==a.indexOf("Z",a.length-1)&&(c=new Date(Date.UTC(c.getFullYear(),c.getMonth(),c.getDate(),c.getHours(),c.getMinutes(),c.getSeconds(),c.getMilliseconds())));return c}function j(b,c,d){if(a.datetimeAccessFormPaths.length>0){for(var e=d.split(".#")[0],f=0;f1&&null!=f.__text&&a.skipEmptyTextNodesForObj&&(a.stripWhitespaces&&""==f.__text||""==f.__text.trim())&&delete f.__text,delete f.__cnt,!a.enableToStringFunc||null==f.__text&&null==f.__cdata||(f.toString=function(){return(null!=this.__text?this.__text:"")+(null!=this.__cdata?this.__cdata:"")}),f}return b.nodeType==w.TEXT_NODE||b.nodeType==w.CDATA_SECTION_NODE?b.nodeValue:void 0}function l(b,c,d,e){var g="<"+(null!=b&&null!=b.__prefix?b.__prefix+":":"")+c;if(null!=d)for(var h=0;h":">"}function m(a,b){return""}function n(a,b){return-1!==a.indexOf(b,a.length-b.length)}function o(b,c){return"property"==a.arrayAccessForm&&n(c.toString(),"_asArray")||0==c.toString().indexOf(a.attributePrefix)||0==c.toString().indexOf("__")||b[c]instanceof Function?!0:!1}function p(a){var b=0;if(a instanceof Object)for(var c in a)o(a,c)||b++;return b}function q(b){var c=[];if(b instanceof Object)for(var d in b)-1==d.toString().indexOf("__")&&0==d.toString().indexOf(a.attributePrefix)&&c.push(d);return c}function r(b){var c="";return null!=b.__cdata&&(c+=""),null!=b.__text&&(c+=a.escapeMode?f(b.__text):b.__text),c}function s(b){var c="";return b instanceof Object?c+=r(b):null!=b&&(c+=a.escapeMode?f(b):b),c}function t(a,b,c){var d="";if(0==a.length)d+=l(a,b,c,!0);else for(var e=0;e0)for(var d in a)if(!o(a,d)){var e=a[d],f=q(e);if(null==e||void 0==e)b+=l(e,d,f,!0);else if(e instanceof Object)if(e instanceof Array)b+=t(e,d,f);else if(e instanceof Date)b+=l(e,d,f,!1),b+=e.toISOString(),b+=m(e,d);else{var g=p(e);g>0||null!=e.__text||null!=e.__cdata?(b+=l(e,d,f,!1),b+=u(e),b+=m(e,d)):b+=l(e,d,f,!0)}else b+=l(e,d,f,!1),b+=s(e),b+=m(e,d)}return b+=s(a)}var v="1.1.5",a=a||{};b(),c();var w={ELEMENT_NODE:1,TEXT_NODE:3,CDATA_SECTION_NODE:4,COMMENT_NODE:8,DOCUMENT_NODE:9};this.parseXmlString=function(a){var b=window.ActiveXObject||"ActiveXObject"in window;if(void 0===a)return null;var c;if(window.DOMParser){var d=new window.DOMParser,e=null;if(!b)try{e=d.parseFromString("INVALID","text/xml").childNodes[0].namespaceURI}catch(f){e=null}try{c=d.parseFromString(a,"text/xml"),null!=e&&c.getElementsByTagNameNS(e,"parsererror").length>0&&(c=null)}catch(f){c=null}}else 0==a.indexOf("")+2)),c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(a);return c},this.asArray=function(a){return a instanceof Array?a:[a]},this.toXmlDateTime=function(a){return a instanceof Date?a.toISOString():"number"==typeof a?new Date(a).toISOString():null},this.asDateTime=function(a){return"string"==typeof a?i(a):a},this.xml2json=function(a){return k(a)},this.xml_str2json=function(a){var b=this.parseXmlString(a);return null!=b?this.xml2json(b):null},this.json2xml_str=function(a){return u(a)},this.json2xml=function(a){var b=this.json2xml_str(a);return this.parseXmlString(b)},this.getVersion=function(){return v}}; \ No newline at end of file diff --git a/dist/offline-tpk-src.js b/dist/offline-tpk-src.js index 2172b94..cdc61ec 100644 --- a/dist/offline-tpk-src.js +++ b/dist/offline-tpk-src.js @@ -1,4126 +1,4126 @@ -/*! offline-editor-js - v2.11.0 - 2015-07-30 -* Copyright (c) 2015 Environmental Systems Research Institute, Inc. -* Apache License*/ -/** - * Library for reading an ArcGIS Tile Package (.tpk) file and displaying the tiles - * as a map that can be used both online and offline. - * - * Note: you may have to rename your .tpk file to use .zip in order for it to be recognized. - * - * Author: Andy Gup - * Credits: Mansour Raad for his ArcGIS API for Flex TPKLayer, - * and Jon leighton for his super fast ArrayBuffer to Base64 convert. - */ -define([ - "dojo/_base/declare","esri/geometry/Extent","dojo/query","esri/SpatialReference", - "esri/layers/TileInfo","esri/layers/TiledMapServiceLayer", - "dojo/Deferred","dojo/promise/all","dojo/Evented"], - function(declare,Extent,query,SpatialReference,TileInfo,TiledMapServiceLayer, - Deferred,all,Evented){ - return declare("O.esri.TPK.TPKLayer",[TiledMapServiceLayer,Evented],{ - - // - // Public Properties - // - map: null, - store: null, // Reference to the local database store and hooks to it's functionality - MAX_DB_SIZE: 75, // Recommended maximum size in MBs - TILE_PATH:"", // The absolute path to the root of bundle/bundleX files e.g. V101/YOSEMITE_MAP/ - RECENTER_DELAY: 350, // Millisecond delay before attempting to recent map after an orientation change - PARSING_ERROR: "parsingError", // An error was encountered while parsing a TPK file. - DB_INIT_ERROR: "dbInitError", // An error occurred while initializing the database. - DB_FULL_ERROR: "dbFullError", // No space left in the database. - NO_SUPPORT_ERROR: "libNotSupportedError", // Error indicating this library is not supported in a particular browser. - PROGRESS_START: "start", - PROGRESS_END: "end", - WINDOW_VALIDATED: "windowValidated", // All window functionality checks have passed - DB_VALIDATED: "dbValidated", // All database functionality checks have passed - - // - // Events - // - DATABASE_ERROR_EVENT: "databaseErrorEvent", // An error thrown by the database. - VALIDATION_EVENT: "validationEvent", // Library validation checks. - PROGRESS_EVENT: "progress", // Event dispatched while parsing a bundle file. - - // - // Private properties - // - _maxDBSize: 75, // User configurable maximum size in MBs. - _isDBWriteable: true, // Manually allow or stop writing to the database. - _isDBValid: false, // Does the browser support IndexedDB or IndexedDBShim - _autoCenter: null, // Auto center the map - _fileEntriesLength: 0, // Number of files in zip - _inMemTilesObject: null, // Stores unzipped files from tpk - _inMemTilesObjectLength: 0, - _zeroLengthFileCounter: 0, // For counting the number of zero length files in the tpk (e.g. directories) - - constructor:function(){ - this._self = this; - this._inMemTilesIndex = []; - this._inMemTilesObject = {}; - this.store = new O.esri.Tiles.TilesStore(); - this._validate(); - }, - - extend: function(files){ - this._fileEntriesLength = files.length; - this.emit(this.PROGRESS_EVENT,this.PROGRESS_START); - - this._parseInMemFiles(files,function (){ - //Parse conf.xml and conf.cdi to get the required setup info - this._parseConfCdi(function(initExtent){ - this.initialExtent = (this.fullExtent = initExtent); - this._parseConfXml(function(result){ - this.tileInfo = new TileInfo(result); - this.spatialReference = new SpatialReference({wkid:this.tileInfo.spatialReference.wkid}); - this.loaded = true; - this.onLoad(this); - this.emit(this.PROGRESS_EVENT,this.PROGRESS_END); - }.bind(this._self)); - }.bind(this._self)); - }.bind(this._self)); - }, - - /** - * Overrides getTileUrl method - * @param level - * @param row - * @param col - * @returns {string} - */ - getTileUrl:function(level,row,col){ - this.emit(this.PROGRESS_EVENT,this.PROGRESS_START); - var layersDir = this._self.TILE_PATH + "_alllayers"; - var url = this._getCacheFilePath(layersDir,level,row,col); - - if(this._inMemTilesObject != {}) { - /* temporary URL returned immediately, as we haven't retrieved the image from the indexeddb yet */ - var tileid = "void:/" + level + "/" + row + "/" + col; - - if(this.map == null) { - this.map = this.getMap(); - } - if(this._autoCenter == null) { - this._autoCenter = new O.esri.TPK.autoCenterMap(this.map,this.RECENTER_DELAY); - this._autoCenter.init(); - } - - this._getInMemTiles(url,layersDir, level, row, col,tileid,function (result,tileid,url) { - var img = query("img[src=" + tileid + "]")[0]; - if (typeof img == "undefined") { - img = new Image(); - } //create a blank place holder for undefined images - var imgURL; - - if (result) { - console.log("found tile offline", url); - var png = "data:image/png;base64,"; - switch(this.tileInfo.format) { - case "JPEG": - imgURL = "data:image/jpg;base64," + result; - break; - case "PNG": - imgURL = png + result; - break; - case "PNG8": - imgURL = png + result; - break; - case "PNG24": - imgURL = png + result; - break; - case "PNG32": - imgURL = png + result; - break; - default: - imgURL = "data:image/jpg;base64," + result; - - } - img.style.borderColor = "blue"; - } - else { - img.style.borderColor = "green"; - console.log("tile is not in the offline store", url); - imgURL = "data:image/png;base64,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pmk0TROPj48Hn3l4eIimaSJN06O3A4NJwDMxm82ibdtXo4D5fB6r1Sp+//4dz8/Pw5H+6ekpdrtdJEkS8/n8S/9f713ie3vaceo9x557QAB451Sgfyin34HKshweunk5HzAej2MymXz5+f9nbjJyI9L39Wu5XP55+XQZ39uxR4Z3u90wSXjqEV0wAjhjx47oaZq63Me/ZhIQBAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEAAbAJQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEAvqe/BwCeKjUweoA8pQAAAABJRU5ErkJggg=="; - } - // when we return a nonexistent url to the image, the TiledMapServiceLayer::_tileErrorHandler() method - // sets img visibility to 'hidden', so we need to show the image back once we have put the data:image - img.style.visibility = "visible"; - img.src = imgURL; - console.log("URL length " + imgURL.length + ", image: " + imgURL); - this.emit(this.PROGRESS_EVENT,this.PROGRESS_END); - return ""; - /* this result goes nowhere, seriously */ - }.bind(this._self)); - - return tileid; - } - }, - - /** - * Optional. Set the maximum database size. Recommended maximum for mobile devices is 100MBs. - * Making the database too large can result in browser crashes and slow performance. - * TPKs can contain a lot of data! - * @param size - */ - setMaxDBSize: function(size){ - //Make sure the entry is an integer. - var testRegex = /^\d+$/; - if(testRegex.test(size) && size <= this.MAX_DB_SIZE){ - this._maxDBSize = size; - } - else{ - console.log("setMaxDBSize Error: invalid entry. Integers only and less than " + this.MAX_DB_SIZE + "MBs"); - } - }, - - /** - * Returns the size of the tiles database. - * @param callback {size , error}. Note, size is in bytes. - */ - getDBSize: function(callback){ - this.store.usedSpace(function(size,err){ - callback(size,err); - }.bind(this)); - }, - - /** - * Sets whether or not tiles can be written to the database. This function - * can help you manage the size of the tiles database. - * Use this in conjunction with getDBSize() on a map pan or zoom event listener. - * @param value - */ - setDBWriteable: function(/* Boolean */ value){ - this._isDBWriteable = value; - }, - - /** - * Validates whether or not the browser supports this library - * @returns {boolean} - */ - isDBValid: function(){ - this._validate(); - return this._isDBValid; - }, - - /** - * Reads a tile into tile database. Works with offlineTilesEnabler.js and OfflineTilesEnablerLayer.js - * saveToFile() functionality. - * IMPORTANT! The tile must confirm to an object using the pattern shown in _storeTile(). - * @param file - * @param callback callback( boolean, error) - */ - loadFromURL: function (tile, callback) // callback(success,msg) - { - if (this.isDBValid()) { - this.store.store(tile, function (success,err) { - //Check the result - if (success) { - console.log("loadFromURL() success."); - callback(true, ""); - } - else { - console.log("loadFromURL() Failed."); - callback(false, err); - } - }); - } - else { - callback(false, "not supported"); - } - }, - - /** - * Runs specific validation tasks. Reserved for future use. - * Currently only throws console errors. Does not stop execution of the library! - * @private - */ - _validate: function(){ - //Verify if basic functionality is supported by the browser - if(!window.File && !window.FileReader && !window.Blob && !window.btoa && !window.DataView){ - console.log("TPKLayer library is not supported by this browser"); - this.emit(this.VALIDATION_EVENT,{msg:this.NO_SUPPORT_ERROR, err : null}); - } - else{ - this.emit(this.VALIDATION_EVENT,{msg:this.WINDOW_VALIDATED, err : null}); - } - - //Verify if IndexedDB is supported and initializes properly - if( /*false &&*/ this.store.isSupported() ) - { - this.store.init(function(result){ - if(result === false){ - console.log("There was an error initializing the TPKLayer database"); - this.emit(this.DATABASE_ERROR_EVENT,{msg:this.DB_INIT_ERROR, err: null}); - } - else{ - this.store.usedSpace(function(size,err){ - var mb = this._bytes2MBs(size.sizeBytes); - if(mb > this.MAX_DB_SIZE){ - console.log("Database is full!"); - this.emit(this.DATABASE_ERROR_EVENT,{msg:this.DB_FULL_ERROR,err : err}); - } - this.emit(this.VALIDATION_EVENT,{msg:this.DB_VALIDATED,err : null}); - console.log("DB size: " + mb + " MBs, Tile count: " + size.tileCount + ", Error: " + err); - this._isDBValid = true; - }.bind(this)); - } - }.bind(this)); - } - else - { - console.log("IndexedDB is not supported on your browser."); - this.emit(this.VALIDATION_EVENT,{msg:this.NO_SUPPORT_ERROR, err : null}); - } - }, - - /** - * Function for pulling out individual files from the .tpk/zip and storing - * them in memory. - * @param files - * @param callback - * @private - */ - _parseInMemFiles: function(files,callback){ - - var inMemTilesLength = this._fileEntriesLength; - this._zeroLengthFileCounter = 0; - var promises = []; - - for(var i=0;i < inMemTilesLength;i++){ - - var deferred = new Deferred(); - var name = files[i].filename.toLocaleUpperCase(); - - var index = name.indexOf("_ALLLAYERS",0); - if(index != -1){ - this.TILE_PATH = name.slice(0,index); - } - - if(files[i].compressedSize === 0) { - this._zeroLengthFileCounter++; - } - - var indexCDI = name.indexOf("CONF.CDI",0); - var indexXML = name.indexOf("CONF.XML",0); - var indexBUNDLE = name.indexOf("BUNDLE",0); - var indexBUNDLX = name.indexOf("BUNDLX",0); - - if(indexCDI != -1 || indexXML != -1){ - this._unzipConfFiles(files,i,deferred,function(/* deferred */ d, /* token */ t){ console.log("CONF FILE"); - d.resolve(t); - }); - } - else if(indexBUNDLE != -1 || indexBUNDLX != -1){ - this._unzipTileFiles(files,i,deferred,function(/* deferred */ d, /* token */ t){ - d.resolve(t); - }); - } - else{ - deferred.resolve(i); - } - promises.push(deferred); - } - - all(promises).then( function(results) - { - callback && callback(results); // jshint ignore:line - }); - }, - - /** - * Calculate the size of an Object based on whether or not the item is enumerable. - * Native Objects don't have a built in size property. - * More info: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty - * @param obj - * @returns {number} - * @constructor - */ - ObjectSize: function(obj) { - var size = 0, key; - for (key in obj) { - if (obj.hasOwnProperty(key)) { - size++; - } - } - return size; - }, - - /** - * Retrieve XML config files - * @param files - * @param token - * @param callback - * @private - */ - _unzipConfFiles: function(files,token,deferred,callback){ - files[token].getData(new O.esri.zip.TextWriter(token),function(data){ - this._inMemTilesIndex.push("blank"); - var name = files[data.token].filename.toLocaleUpperCase(); - this._inMemTilesObject[name]= data.string; - var size = this.ObjectSize(this._inMemTilesObject); - if(size > 0){ - callback(deferred,data.token); - } - }.bind(this)); - }, - - /** - * Retrieve binary tile files as ArrayBuffers - * @param files - * @param token - * @param callback - * @private - */ - _unzipTileFiles: function(files,token,deferred,callback){ - var that = this; - files[token].getData(new O.esri.zip.BlobWriter(token),function(data){ - if(data.size !== 0){ - var reader = new FileReader(); - reader.token = data.token; - reader.onerror = function (event) { - console.error("_unzipTileFiles Error: " + event.target.error.message); - that.emit(that.PARSING_ERROR, {msg: "Error parsing file: ", err: event.target.error}); - }; - reader.onloadend = function(evt) { - if(reader.token !== undefined){ - that._inMemTilesIndex.push("blank"); - var name = files[reader.token].filename.toLocaleUpperCase(); - that._inMemTilesObject[name]= reader.result; - var size = that.ObjectSize(that._inMemTilesObject); - if(size > 0){ - callback(deferred,data.token); - } - } - }; - reader.readAsArrayBuffer(data); //open bundleX - } - }); - }, - - /** - * Parse conf.cdi - * @param callback - * @private - */ - _parseConfCdi: function(callback){ - var m_conf_i = this._inMemTilesObject[this.TILE_PATH + "CONF.CDI"]; - - var x2js = new O.esri.TPK.X2JS(); - - var jsonObj = x2js.xml_str2json( m_conf_i ); - var envelopeInfo = jsonObj.EnvelopeN; - var xmin = parseFloat(envelopeInfo.XMin); - var ymin = parseFloat(envelopeInfo.YMin); - var xmax = parseFloat(envelopeInfo.XMax); - var ymax = parseFloat(envelopeInfo.YMax); - var sr = parseInt(envelopeInfo.SpatialReference.WKID); - - var initExtent = new Extent( - xmin,ymin,xmax,ymax, new SpatialReference({wkid:sr}) - ); - - callback(initExtent); - }, - - /** - * Parse conf.xml - * @param callback - * @private - */ - _parseConfXml:function(callback) { - var m_conf = this._inMemTilesObject[this.TILE_PATH + "CONF.XML"]; - - var x2js = new O.esri.TPK.X2JS(); - - var jsonObj = x2js.xml_str2json(m_conf); - var cacheInfo = jsonObj.CacheInfo; - var tileInfo = {}; - tileInfo.rows = parseInt(cacheInfo.TileCacheInfo.TileRows); - tileInfo.cols = parseInt(cacheInfo.TileCacheInfo.TileCols); - tileInfo.dpi = parseInt(cacheInfo.TileCacheInfo.DPI); - tileInfo.format = cacheInfo.TileImageInfo.CacheTileFormat; - tileInfo.compressionQuality = parseInt(cacheInfo.TileImageInfo.CompressionQuality); - tileInfo.origin = { - x: parseInt(cacheInfo.TileCacheInfo.TileOrigin.X), - y: parseInt(cacheInfo.TileCacheInfo.TileOrigin.Y) - }; - tileInfo.spatialReference = { - "wkid": parseInt(cacheInfo.TileCacheInfo.SpatialReference.WKID) - }; - - var lods = cacheInfo.TileCacheInfo.LODInfos.LODInfo; - var finalLods = []; - for (var i = 0; i < lods.length; i++) { - finalLods.push({ - "level": parseFloat(lods[i].LevelID), - "resolution": parseFloat(lods[i].Resolution), - "scale": parseFloat(lods[i].Scale)}); - } - - tileInfo.lods = finalLods; - callback(tileInfo); - }, - - /** - * Parses the in-memory tile cache and returns a base64 tile image - * @param layersDir - * @param level - * @param row - * @param col - * @param tileCount - number of tiles in the Extent - * @param tiledId - id of the associated tile being passed - * @param callback - * @private - */ - _getInMemTiles: function(url,layersDir,level,row,col,tileId,callback){ - - var that = this._self; - var db = this.store; - - //First check in the database if the tile exists. - //If not then we store the tile in the database later. - this.store.retrieve(url, function(success, offlineTile){ - if( success ) - { - console.log("Tile found in storage: " + url); - callback(offlineTile.img,tileId,url); - } - else { - console.log("Tile is not in storage: " + url); - var snappedRow = Math.floor(row / 128) * 128; - var snappedCol = Math.floor(col / 128) * 128; - - var path = this._getCacheFilePath(layersDir, level, snappedRow, snappedCol).toLocaleUpperCase(); - - var offset; - var bundleIndex = path + ".BUNDLE"; - var bufferI = this._inMemTilesObject[bundleIndex]; - var bufferX = this._inMemTilesObject[path + ".BUNDLX"]; - - if(bufferI !== undefined || bufferX !== undefined) { - offset = this._getOffset(level, row, col, snappedRow, snappedCol); - var pointer = that._getPointer(bufferX, offset); - - that._buffer2Base64(bufferI,pointer,function(result){ - if (that._isDBWriteable) { - that._storeTile(url, result, db,function(success,err){ - if(err){ - console.log("TPKLayer - Error writing to database." + err.message); - that.emit(that.DATABASE_ERROR_EVENT,{msg:"Error writing to database. ", err : err}); - } - }); - } - callback(result,tileId, url); - }.bind(that)); - } - else{ - console.log("_getInMemTiles Error: Invalid values"); - callback(null,tileId,url); - } - } - }.bind(that)); - }, - - /** - * Stores a tile in the local database. - * @param url - * @param base64Str - * @param db - * @param callback - * @private - */ - _storeTile: function(url,base64Str,db,callback){ - var tile = { - url: url, - img: base64Str - }; - - db.store(tile,function(success,err){ - callback(success,err); - }); - }, - - /** - * Returns a pointer for reading a BUNDLE binary file as based on the given offset. - * @param buffer - * @param offset - * @returns {Uint8} - * @private - */ - _getPointer: function(/* ArrayBuffer */ buffer,offset){ - var snip = buffer.slice(offset); - var dv = new DataView(snip,0,5); - - var nume1 = dv.getUint8(0,true); - var nume2 = dv.getUint8(1,true); - var nume3 = dv.getUint8(2,true); - var nume4 = dv.getUint8(3,true); - var nume5 = dv.getUint8(4,true); - - var value = nume5; - value = value * 256 + nume4; - value = value * 256 + nume3; - value = value * 256 + nume2; - value = value * 256 + nume1; - - return value; - }, - - /** - * Convert an ArrayBuffer to base64. My testing shows this to be - * much faster than combining Blobs and btoa(). - * ALL CREDITS: https://gist.github.com/jonleighton/958841 - * NO licensing listed at the gist repo. - * @param arrayBuffer - * @returns {string} - * @private - */ - _base64ArrayBuffer: function(arrayBuffer) { - var base64 = ""; - var encodings = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - var bytes = new Uint8Array(arrayBuffer); - var byteLength = bytes.byteLength; - var byteRemainder = byteLength % 3; - var mainLength = byteLength - byteRemainder; - - var a, b, c, d; - var chunk; - - /*jslint bitwise: true */ - - // Main loop deals with bytes in chunks of 3 - for (var i = 0; i < mainLength; i = i + 3) { - // Combine the three bytes into a single integer - chunk = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2]; - - // Use bitmasks to extract 6-bit segments from the triplet - a = (chunk & 16515072) >> 18; // 16515072 = (2^6 - 1) << 18 - b = (chunk & 258048) >> 12; // 258048 = (2^6 - 1) << 12 - c = (chunk & 4032) >> 6; // 4032 = (2^6 - 1) << 6 - d = chunk & 63; // 63 = 2^6 - 1 - - // Convert the raw binary segments to the appropriate ASCII encoding - base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d]; - } - - // Deal with the remaining bytes and padding - if (byteRemainder == 1) { - chunk = bytes[mainLength]; - - a = (chunk & 252) >> 2; // 252 = (2^6 - 1) << 2 - - // Set the 4 least significant bits to zero - b = (chunk & 3) << 4; // 3 = 2^2 - 1 - - base64 += encodings[a] + encodings[b] + "=="; - } else if (byteRemainder == 2) { - chunk = (bytes[mainLength] << 8) | bytes[mainLength + 1]; - - a = (chunk & 64512) >> 10; // 64512 = (2^6 - 1) << 10 - b = (chunk & 1008) >> 4; // 1008 = (2^6 - 1) << 4 - - // Set the 2 least significant bits to zero - c = (chunk & 15) << 2; // 15 = 2^4 - 1 - - base64 += encodings[a] + encodings[b] + encodings[c] + "="; - } - - /*jslint bitwise: false */ - - return base64; - }, - - /** - * Given a ArrayBuffer and a position it will return a Base64 tile image - * @param arrayBuffer - * @param position - * @returns {string} - * @private - */ - _buffer2Base64: function(/* ArrayBuffer */arrayBuffer,/* int */ position,callback){ - var view = new DataView(arrayBuffer,position); - var chunk = view.getInt32(0,true); - var buffer = view.buffer.slice(position + 4,position + 4 + chunk); - var string = this._base64ArrayBuffer(buffer); - callback(string); - }, - - /** - * Converts an integer to hex - * @param value - * @returns {string} - * @private - */ - _int2HexString: function(/* int */ value){ - var text = value.toString(16).toUpperCase(); - if (text.length === 1) - { - return "000" + text; - } - if (text.length === 2) - { - return "00" + text; - } - if (text.length === 3) - { - return "0" + text; - } - return text.substr(0, text.length); - }, - - /** - * Determines where to start reading a BUNDLEX binary file - * @param level - * @param row - * @param col - * @param startRow - * @param startCol - * @returns {number} - * @private - */ - _getOffset: function(/* int */level, /* number */row,/* number */col, /* number */startRow, /* number */ startCol){ - var recordNumber = 128 * (col - startCol) + (row - startRow); - return 16 + recordNumber * 5; - }, - - /** - * Returns a hexadecimal representation of a cache file path - * @param layerDir - * @param level - * @param row - * @param col - * @returns {string} - * @private - */ - _getCacheFilePath: function(/* String */ layerDir, /* int */level, /* int */row, /* int */ col){ - var arr = []; - - arr.push(layerDir); - arr.push("/"); - arr.push("L"); - arr.push(level < 10 ? "0" + level : level); - arr.push("/"); - arr.push("R"); - arr.push(this._int2HexString(row)); - arr.push("C"); - arr.push(this._int2HexString(col)); - - return arr.join(""); - }, - - /** - * Returns database size in MBs. - * @returns {string} - * @private - */ - _bytes2MBs: function(bytes){ - return (bytes >>> 20 ) + '.' + ( bytes & (2*0x3FF ) ); // jshint ignore:line - } - }); - } -); -/** - * Creates a namespace for the non-AMD libraries in this directory - */ - - -if(typeof O != "undefined"){ - O.esri.TPK = {}; -} -else{ - O = {}; // jshint ignore:line - O.esri = { - TPK: {}, - Tiles: {} - }; -} - -//"use strict"; - - -/*global indexedDB */ -/** - * Library for handling the storing of map tiles in IndexedDB. - * - * Author: Andy Gup (@agup) - * Contributor: Javier Abadia (@javierabadia) - */ - -O.esri.Tiles.TilesStore = function(){ - /** - * Internal reference to the local database - * @type {null} - * @private - */ - this._db = null; - - this.dbName = "offline_tile_store"; - this.objectStoreName = "tilepath"; - - /** - * Determines if indexedDB is supported - * @returns {boolean} - */ - this.isSupported = function(){ - - if(!window.indexedDB && !window.openDatabase){ - return false; - } - - return true; - }; - - /** - * Adds an object to the database - * @param urlDataPair - * @param callback callback(boolean, err) - */ - this.store = function(urlDataPair,callback) - { - try - { - var transaction = this._db.transaction([this.objectStoreName],"readwrite"); - - transaction.oncomplete = function() - { - callback(true); - }; - - transaction.onerror = function(event) - { - callback(false,event.target.error.message); - }; - - var objectStore = transaction.objectStore(this.objectStoreName); - var request = objectStore.put(urlDataPair); - request.onsuccess = function() - { - //console.log("item added to db " + event.target.result); - }; - } - catch(err) - { - console.log("TilesStore: " + err.stack); - callback(false, err.stack); - } - }; - - /** - * Retrieve a record. - * @param url - * @param callback - */ - this.retrieve = function(/* String */ url,callback) - { - if(this._db !== null) - { - var objectStore = this._db.transaction([this.objectStoreName]).objectStore(this.objectStoreName); - var request = objectStore.get(url); - request.onsuccess = function(event) - { - var result = event.target.result; - if(result === undefined) - { - callback(false,"not found"); - } - else - { - callback(true,result); - } - }; - request.onerror = function(err) - { - console.log(err); - callback(false, err); - }; - } - }; - - /** - * Deletes entire database - * @param callback callback(boolean, err) - */ - this.deleteAll = function(callback) - { - if(this._db !== null) - { - var request = this._db.transaction([this.objectStoreName],"readwrite") - .objectStore(this.objectStoreName) - .clear(); - request.onsuccess = function() - { - callback(true); - }; - request.onerror = function(err) - { - callback(false, err); - }; - } - else - { - callback(false,null); - } - }; - - /** - * Delete an individual entry - * @param url - * @param callback callback(boolean, err) - */ - this.delete = function(/* String */ url,callback) - { - if(this._db !== null) - { - var request = this._db.transaction([this.objectStoreName],"readwrite") - .objectStore(this.objectStoreName) - .delete(url); - request.onsuccess = function() - { - callback(true); - }; - request.onerror = function(err) - { - callback(false, err); - }; - } - else - { - callback(false,null); - } - }; - - /** - * Retrieve all tiles from indexeddb - * @param callback callback(url, img, err) - */ - this.getAllTiles = function(callback) - { - if(this._db !== null){ - var transaction = this._db.transaction([this.objectStoreName]) - .objectStore(this.objectStoreName) - .openCursor(); - - transaction.onsuccess = function(event) - { - var cursor = event.target.result; - if(cursor){ - var url = cursor.value.url; - var img = cursor.value.img; - callback(url,img,null); - cursor.continue(); - } - else - { - callback(null, null, "end"); - } - }.bind(this); - transaction.onerror = function(err) - { - callback(null, null, err); - }; - } - else - { - callback(null, null, "no db"); - } - }; - - /** - * Provides the size of database in bytes - * @param callback callback(size, null) or callback(null, error) - */ - this.usedSpace = function(callback){ - if(this._db !== null){ - var usage = { sizeBytes: 0, tileCount: 0 }; - - var transaction = this._db.transaction([this.objectStoreName]) - .objectStore(this.objectStoreName) - .openCursor(); - - transaction.onsuccess = function(event){ - var cursor = event.target.result; - if(cursor){ - var storedObject = cursor.value; - var json = JSON.stringify(storedObject); - usage.sizeBytes += this._stringBytes(json); - usage.tileCount += 1; - cursor.continue(); - } - else - { - callback(usage,null); - } - }.bind(this); - transaction.onerror = function(err) - { - callback(null, err); - }; - } - else - { - callback(null,null); - } - }; - - this._stringBytes = function(str) { - return str.length /**2*/ ; - }; - - this.init = function(callback) - { - var request = indexedDB.open(this.dbName, 4); - callback = callback || function(success) { console.log("TilesStore::init() success:", success); }.bind(this); - - request.onerror = function(event) - { - console.log("indexedDB error: " + event.target.errorCode); - callback(false,event.target.errorCode); - }.bind(this); - - request.onupgradeneeded = function(event) - { - var db = event.target.result; - - if( db.objectStoreNames.contains(this.objectStoreName)) - { - db.deleteObjectStore(this.objectStoreName); - } - - db.createObjectStore(this.objectStoreName, { keyPath: "url" }); - }.bind(this); - - request.onsuccess = function(event) - { - this._db = event.target.result; - console.log("database opened successfully"); - callback(true); - }.bind(this); - }; -}; - - -//https://github.com/gildas-lormeau/zip.js/blob/master/WebContent/zip.js -/* - Copyright (c) 2013 Gildas Lormeau. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the distribution. - - 3. The names of the authors may not be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, - INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, - INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -(function(obj) { - - var ERR_BAD_FORMAT = "File format is not recognized."; - var ERR_ENCRYPTED = "File contains encrypted entry."; - var ERR_ZIP64 = "File is using Zip64 (4gb+ file size)."; - var ERR_READ = "Error while reading zip file."; - var ERR_WRITE = "Error while writing zip file."; - var ERR_WRITE_DATA = "Error while writing file data."; - var ERR_READ_DATA = "Error while reading file data."; - var ERR_DUPLICATED_NAME = "File already exists."; - var CHUNK_SIZE = 512 * 1024; - - var INFLATE_JS = ""; //left blank intentionally! Modified by @agup - var DEFLATE_JS = "deflate.js"; - - var TEXT_PLAIN = "text/plain"; - - var MESSAGE_EVENT = "message"; - - var appendABViewSupported; - try { - appendABViewSupported = new Blob([ new DataView(new ArrayBuffer(0)) ]).size === 0; - } catch (e) { - } - - function Crc32() { - var crc = -1, that = this; - that.append = function(data) { - var offset, table = that.table; - for (offset = 0; offset < data.length; offset++) - crc = (crc >>> 8) ^ table[(crc ^ data[offset]) & 0xFF]; - }; - that.get = function() { - return ~crc; - }; - } - Crc32.prototype.table = (function() { - var i, j, t, table = []; - for (i = 0; i < 256; i++) { - t = i; - for (j = 0; j < 8; j++) - if (t & 1) - t = (t >>> 1) ^ 0xEDB88320; - else - t = t >>> 1; - table[i] = t; - } - return table; - })(); - - function blobSlice(blob, index, length) { - if (blob.slice) - return blob.slice(index, index + length); - else if (blob.webkitSlice) - return blob.webkitSlice(index, index + length); - else if (blob.mozSlice) - return blob.mozSlice(index, index + length); - else if (blob.msSlice) - return blob.msSlice(index, index + length); - } - - function getDataHelper(byteLength, bytes) { - var dataBuffer, dataArray; - dataBuffer = new ArrayBuffer(byteLength); - dataArray = new Uint8Array(dataBuffer); - if (bytes) - dataArray.set(bytes, 0); - return { - buffer : dataBuffer, - array : dataArray, - view : new DataView(dataBuffer) - }; - } - - // Readers - function Reader() { - } - - function TextReader(text) { - var that = this, blobReader; - - function init(callback, onerror) { - var blob = new Blob([ text ], { - type : TEXT_PLAIN - }); - blobReader = new BlobReader(blob); - blobReader.init(function() { - that.size = blobReader.size; - callback(); - }, onerror); - } - - function readUint8Array(index, length, callback, onerror) { - blobReader.readUint8Array(index, length, callback, onerror); - } - - that.size = 0; - that.init = init; - that.readUint8Array = readUint8Array; - } - TextReader.prototype = new Reader(); - TextReader.prototype.constructor = TextReader; - - function Data64URIReader(dataURI) { - var that = this, dataStart; - - function init(callback) { - var dataEnd = dataURI.length; - while (dataURI.charAt(dataEnd - 1) == "=") - dataEnd--; - dataStart = dataURI.indexOf(",") + 1; - that.size = Math.floor((dataEnd - dataStart) * 0.75); - callback(); - } - - function readUint8Array(index, length, callback) { - var i, data = getDataHelper(length); - var start = Math.floor(index / 3) * 4; - var end = Math.ceil((index + length) / 3) * 4; - var bytes = obj.atob(dataURI.substring(start + dataStart, end + dataStart)); - var delta = index - Math.floor(start / 4) * 3; - for (i = delta; i < delta + length; i++) - data.array[i - delta] = bytes.charCodeAt(i); - callback(data.array); - } - - that.size = 0; - that.init = init; - that.readUint8Array = readUint8Array; - } - Data64URIReader.prototype = new Reader(); - Data64URIReader.prototype.constructor = Data64URIReader; - - function BlobReader(blob) { - var that = this; - - function init(callback) { - this.size = blob.size; - callback(); - } - - function readUint8Array(index, length, callback, onerror) { - var reader = new FileReader(); - reader.onload = function(e) { - callback(new Uint8Array(e.target.result)); - }; - reader.onerror = onerror; - reader.readAsArrayBuffer(blobSlice(blob, index, length)); - } - - that.size = 0; - that.init = init; - that.readUint8Array = readUint8Array; - } - BlobReader.prototype = new Reader(); - BlobReader.prototype.constructor = BlobReader; - - // Writers - - function Writer() { - } - Writer.prototype.getData = function(callback) { - callback(this.data); - }; - - //Added by Andy G. Tracking token - function TextWriter(token,encoding) { - var that = this, blob; - - function init(callback) { - blob = new Blob([], { - type: TEXT_PLAIN - }); - callback(); - } - - function writeUint8Array(array, callback) { - blob = new Blob([ blob, appendABViewSupported ? array : array.buffer ], { - type: TEXT_PLAIN - }); - callback(); - } - - function getData(callback, onerror) { - var reader = new FileReader(); - reader.onload = function (e) { - var obj = {string: e.target.result,token:token}; - callback(obj); - }; - reader.onerror = onerror; - reader.readAsText(blob, encoding); - } - - that.init = init; - that.writeUint8Array = writeUint8Array; - that.getData = getData; - } - TextWriter.prototype = new Writer(); - TextWriter.prototype.constructor = TextWriter; - - function Data64URIWriter(contentType) { - var that = this, data = "", pending = ""; - - function init(callback) { - data += "data:" + (contentType || "") + ";base64,"; - callback(); - } - - function writeUint8Array(array, callback) { - var i, delta = pending.length, dataString = pending; - pending = ""; - for (i = 0; i < (Math.floor((delta + array.length) / 3) * 3) - delta; i++) - dataString += String.fromCharCode(array[i]); - for (; i < array.length; i++) - pending += String.fromCharCode(array[i]); - if (dataString.length > 2) - data += obj.btoa(dataString); - else - pending = dataString; - callback(); - } - - function getData(callback) { - callback(data + obj.btoa(pending)); - } - - that.init = init; - that.writeUint8Array = writeUint8Array; - that.getData = getData; - } - Data64URIWriter.prototype = new Writer(); - Data64URIWriter.prototype.constructor = Data64URIWriter; - - //Added by Andy G. Tracking token - function BlobWriter(token,contentType) { - var blob, that = this ; - - function init(callback) { - blob = new Blob([], { - type: contentType - }); - callback(); - } - - function writeUint8Array(array, callback) { - blob = new Blob([ blob, appendABViewSupported ? array : array.buffer ], { - type: contentType - }); - blob.token = token; - callback(); - } - - function getData(callback) { - callback(blob); - } - - that.init = init; - that.writeUint8Array = writeUint8Array; - that.getData = getData; - } - BlobWriter.prototype = new Writer(); - BlobWriter.prototype.constructor = BlobWriter; - - // inflate/deflate core functions - - function launchWorkerProcess(worker, reader, writer, offset, size, onappend, onprogress, onend, onreaderror, onwriteerror) { - var chunkIndex = 0, index, outputSize; - - function onflush() { - worker.removeEventListener(MESSAGE_EVENT, onmessage, false); - onend(outputSize); - } - - function onmessage(event) { - var message = event.data, data = message.data; - - if (message.onappend) { - outputSize += data.length; - writer.writeUint8Array(data, function() { - onappend(false, data); - step(); - }, onwriteerror); - } - if (message.onflush) - if (data) { - outputSize += data.length; - writer.writeUint8Array(data, function() { - onappend(false, data); - onflush(); - }, onwriteerror); - } else - onflush(); - if (message.progress && onprogress) - onprogress(index + message.current, size); - } - - function step() { - index = chunkIndex * CHUNK_SIZE; - if (index < size) - reader.readUint8Array(offset + index, Math.min(CHUNK_SIZE, size - index), function(array) { - worker.postMessage({ - append : true, - data : array - }); - chunkIndex++; - if (onprogress) - onprogress(index, size); - onappend(true, array); - }, onreaderror); - else - worker.postMessage({ - flush : true - }); - } - - outputSize = 0; - worker.addEventListener(MESSAGE_EVENT, onmessage, false); - step(); - } - - function launchProcess(process, reader, writer, offset, size, onappend, onprogress, onend, onreaderror, onwriteerror) { - var chunkIndex = 0, index, outputSize = 0; - - function step() { - var outputData; - index = chunkIndex * CHUNK_SIZE; - if (index < size) - reader.readUint8Array(offset + index, Math.min(CHUNK_SIZE, size - index), function(inputData) { - var outputData = process.append(inputData, function() { - if (onprogress) - onprogress(offset + index, size); - }); - outputSize += outputData.length; - onappend(true, inputData); - writer.writeUint8Array(outputData, function() { - onappend(false, outputData); - chunkIndex++; - setTimeout(step, 1); - }, onwriteerror); - if (onprogress) - onprogress(index, size); - }, onreaderror); - else { - outputData = process.flush(); - if (outputData) { - outputSize += outputData.length; - writer.writeUint8Array(outputData, function() { - onappend(false, outputData); - onend(outputSize); - }, onwriteerror); - } else - onend(outputSize); - } - } - - step(); - } - - function inflate(reader, writer, offset, size, computeCrc32, onend, onprogress, onreaderror, onwriteerror) { - var worker, crc32 = new Crc32(); - - function oninflateappend(sending, array) { - if (computeCrc32 && !sending) - crc32.append(array); - } - - function oninflateend(outputSize) { - onend(outputSize, crc32.get()); - } - - if (obj.zip.useWebWorkers) { - - worker = new Worker(obj.zip.workerScriptsPath + INFLATE_JS); - launchWorkerProcess(worker, reader, writer, offset, size, oninflateappend, onprogress, oninflateend, onreaderror, onwriteerror); - } else - launchProcess(new obj.zip.Inflater(), reader, writer, offset, size, oninflateappend, onprogress, oninflateend, onreaderror, onwriteerror); - return worker; - } - - function deflate(reader, writer, level, onend, onprogress, onreaderror, onwriteerror) { - var worker, crc32 = new Crc32(); - - function ondeflateappend(sending, array) { - if (sending) - crc32.append(array); - } - - function ondeflateend(outputSize) { - onend(outputSize, crc32.get()); - } - - function onmessage() { - worker.removeEventListener(MESSAGE_EVENT, onmessage, false); - launchWorkerProcess(worker, reader, writer, 0, reader.size, ondeflateappend, onprogress, ondeflateend, onreaderror, onwriteerror); - } - - if (obj.zip.useWebWorkers) { - worker = new Worker(obj.zip.workerScriptsPath + DEFLATE_JS); - worker.addEventListener(MESSAGE_EVENT, onmessage, false); - worker.postMessage({ - init : true, - level : level - }); - } else - launchProcess(new obj.zip.Deflater(), reader, writer, 0, reader.size, ondeflateappend, onprogress, ondeflateend, onreaderror, onwriteerror); - return worker; - } - - function copy(reader, writer, offset, size, computeCrc32, onend, onprogress, onreaderror, onwriteerror) { - var chunkIndex = 0, crc32 = new Crc32(); - - function step() { - var index = chunkIndex * CHUNK_SIZE; - if (index < size) - reader.readUint8Array(offset + index, Math.min(CHUNK_SIZE, size - index), function(array) { - if (computeCrc32) - crc32.append(array); - if (onprogress) - onprogress(index, size, array); - writer.writeUint8Array(array, function() { - chunkIndex++; - step(); - }, onwriteerror); - }, onreaderror); - else - onend(size, crc32.get()); - } - - step(); - } - - // ZipReader - - function decodeASCII(str) { - var i, out = "", charCode, extendedASCII = [ '\u00C7', '\u00FC', '\u00E9', '\u00E2', '\u00E4', '\u00E0', '\u00E5', '\u00E7', '\u00EA', '\u00EB', - '\u00E8', '\u00EF', '\u00EE', '\u00EC', '\u00C4', '\u00C5', '\u00C9', '\u00E6', '\u00C6', '\u00F4', '\u00F6', '\u00F2', '\u00FB', '\u00F9', - '\u00FF', '\u00D6', '\u00DC', '\u00F8', '\u00A3', '\u00D8', '\u00D7', '\u0192', '\u00E1', '\u00ED', '\u00F3', '\u00FA', '\u00F1', '\u00D1', - '\u00AA', '\u00BA', '\u00BF', '\u00AE', '\u00AC', '\u00BD', '\u00BC', '\u00A1', '\u00AB', '\u00BB', '_', '_', '_', '\u00A6', '\u00A6', - '\u00C1', '\u00C2', '\u00C0', '\u00A9', '\u00A6', '\u00A6', '+', '+', '\u00A2', '\u00A5', '+', '+', '-', '-', '+', '-', '+', '\u00E3', - '\u00C3', '+', '+', '-', '-', '\u00A6', '-', '+', '\u00A4', '\u00F0', '\u00D0', '\u00CA', '\u00CB', '\u00C8', 'i', '\u00CD', '\u00CE', - '\u00CF', '+', '+', '_', '_', '\u00A6', '\u00CC', '_', '\u00D3', '\u00DF', '\u00D4', '\u00D2', '\u00F5', '\u00D5', '\u00B5', '\u00FE', - '\u00DE', '\u00DA', '\u00DB', '\u00D9', '\u00FD', '\u00DD', '\u00AF', '\u00B4', '\u00AD', '\u00B1', '_', '\u00BE', '\u00B6', '\u00A7', - '\u00F7', '\u00B8', '\u00B0', '\u00A8', '\u00B7', '\u00B9', '\u00B3', '\u00B2', '_', ' ' ]; - for (i = 0; i < str.length; i++) { - charCode = str.charCodeAt(i) & 0xFF; - if (charCode > 127) - out += extendedASCII[charCode - 128]; - else - out += String.fromCharCode(charCode); - } - return out; - } - - function decodeUTF8(string) { - return decodeURIComponent(escape(string)); - } - - function getString(bytes) { - var i, str = ""; - for (i = 0; i < bytes.length; i++) - str += String.fromCharCode(bytes[i]); - return str; - } - - function getDate(timeRaw) { - var date = (timeRaw & 0xffff0000) >> 16, time = timeRaw & 0x0000ffff; - try { - return new Date(1980 + ((date & 0xFE00) >> 9), ((date & 0x01E0) >> 5) - 1, date & 0x001F, (time & 0xF800) >> 11, (time & 0x07E0) >> 5, - (time & 0x001F) * 2, 0); - } catch (e) { - } - } - - function readCommonHeader(entry, data, index, centralDirectory, onerror) { - entry.version = data.view.getUint16(index, true); - entry.bitFlag = data.view.getUint16(index + 2, true); - entry.compressionMethod = data.view.getUint16(index + 4, true); - entry.lastModDateRaw = data.view.getUint32(index + 6, true); - entry.lastModDate = getDate(entry.lastModDateRaw); - if ((entry.bitFlag & 0x01) === 0x01) { - onerror(ERR_ENCRYPTED); - return; - } - if (centralDirectory || (entry.bitFlag & 0x0008) != 0x0008) { - entry.crc32 = data.view.getUint32(index + 10, true); - entry.compressedSize = data.view.getUint32(index + 14, true); - entry.uncompressedSize = data.view.getUint32(index + 18, true); - } - if (entry.compressedSize === 0xFFFFFFFF || entry.uncompressedSize === 0xFFFFFFFF) { - onerror(ERR_ZIP64); - return; - } - entry.filenameLength = data.view.getUint16(index + 22, true); - entry.extraFieldLength = data.view.getUint16(index + 24, true); - } - - function createZipReader(reader, onerror) { - function Entry() { - } - - Entry.prototype.getData = function(writer, onend, onprogress, checkCrc32) { - var that = this, worker; - - function terminate(callback, param) { - if (worker) - worker.terminate(); - worker = null; - if (callback) - callback(param); - } - - function testCrc32(crc32) { - var dataCrc32 = getDataHelper(4); - dataCrc32.view.setUint32(0, crc32); - return that.crc32 == dataCrc32.view.getUint32(0); - } - - function getWriterData(uncompressedSize, crc32) { - if (checkCrc32 && !testCrc32(crc32)) - onreaderror(); - else - writer.getData(function(data) { - terminate(onend, data); - }); - } - - function onreaderror() { - terminate(onerror, ERR_READ_DATA); - } - - function onwriteerror() { - terminate(onerror, ERR_WRITE_DATA); - } - - reader.readUint8Array(that.offset, 30, function(bytes) { - var data = getDataHelper(bytes.length, bytes), dataOffset; - if (data.view.getUint32(0) != 0x504b0304) { - onerror(ERR_BAD_FORMAT); - return; - } - readCommonHeader(that, data, 4, false, onerror); - dataOffset = that.offset + 30 + that.filenameLength + that.extraFieldLength; - writer.init(function() { - if (that.compressionMethod === 0) - copy(reader, writer, dataOffset, that.compressedSize, checkCrc32, getWriterData, onprogress, onreaderror, onwriteerror); - else - worker = inflate(reader, writer, dataOffset, that.compressedSize, checkCrc32, getWriterData, onprogress, onreaderror, onwriteerror); - }, onwriteerror); - }, onreaderror); - }; - - function seekEOCDR(offset, entriesCallback) { - reader.readUint8Array(reader.size - offset, offset, function(bytes) { - var dataView = getDataHelper(bytes.length, bytes).view; - if (dataView.getUint32(0) != 0x504b0506) { - seekEOCDR(offset + 1, entriesCallback); - } else { - entriesCallback(dataView); - } - }, function() { - onerror(ERR_READ); - }); - } - - return { - getEntries : function(callback) { - if (reader.size < 22) { - onerror(ERR_BAD_FORMAT); - return; - } - // look for End of central directory record - seekEOCDR(22, function(dataView) { - var datalength, fileslength; - datalength = dataView.getUint32(16, true); - fileslength = dataView.getUint16(8, true); - reader.readUint8Array(datalength, reader.size - datalength, function(bytes) { - var i, index = 0, entries = [], entry, filename, comment, data = getDataHelper(bytes.length, bytes); - for (i = 0; i < fileslength; i++) { - entry = new Entry(); - if (data.view.getUint32(index) != 0x504b0102) { - onerror(ERR_BAD_FORMAT); - return; - } - readCommonHeader(entry, data, index + 6, true, onerror); - entry.commentLength = data.view.getUint16(index + 32, true); - entry.directory = ((data.view.getUint8(index + 38) & 0x10) == 0x10); - entry.offset = data.view.getUint32(index + 42, true); - filename = getString(data.array.subarray(index + 46, index + 46 + entry.filenameLength)); - entry.filename = ((entry.bitFlag & 0x0800) === 0x0800) ? decodeUTF8(filename) : decodeASCII(filename); - if (!entry.directory && entry.filename.charAt(entry.filename.length - 1) == "/") - entry.directory = true; - comment = getString(data.array.subarray(index + 46 + entry.filenameLength + entry.extraFieldLength, index + 46 - + entry.filenameLength + entry.extraFieldLength + entry.commentLength)); - entry.comment = ((entry.bitFlag & 0x0800) === 0x0800) ? decodeUTF8(comment) : decodeASCII(comment); - entries.push(entry); - index += 46 + entry.filenameLength + entry.extraFieldLength + entry.commentLength; - } - callback(entries); - }, function() { - onerror(ERR_READ); - }); - }); - }, - close : function(callback) { - if (callback) - callback(); - } - }; - } - - // ZipWriter - - function encodeUTF8(string) { - return unescape(encodeURIComponent(string)); - } - - function getBytes(str) { - var i, array = []; - for (i = 0; i < str.length; i++) - array.push(str.charCodeAt(i)); - return array; - } - - function createZipWriter(writer, onerror, dontDeflate) { - var worker, files = {}, filenames = [], datalength = 0; - - function terminate(callback, message) { - if (worker) - worker.terminate(); - worker = null; - if (callback) - callback(message); - } - - function onwriteerror() { - terminate(onerror, ERR_WRITE); - } - - function onreaderror() { - terminate(onerror, ERR_READ_DATA); - } - - return { - add : function(name, reader, onend, onprogress, options) { - var header, filename, date; - - function writeHeader(callback) { - var data; - date = options.lastModDate || new Date(); - header = getDataHelper(26); - files[name] = { - headerArray : header.array, - directory : options.directory, - filename : filename, - offset : datalength, - comment : getBytes(encodeUTF8(options.comment || "")) - }; - header.view.setUint32(0, 0x14000808); - if (options.version) - header.view.setUint8(0, options.version); - if (!dontDeflate && options.level !== 0 && !options.directory) - header.view.setUint16(4, 0x0800); - header.view.setUint16(6, (((date.getHours() << 6) | date.getMinutes()) << 5) | date.getSeconds() / 2, true); - header.view.setUint16(8, ((((date.getFullYear() - 1980) << 4) | (date.getMonth() + 1)) << 5) | date.getDate(), true); - header.view.setUint16(22, filename.length, true); - data = getDataHelper(30 + filename.length); - data.view.setUint32(0, 0x504b0304); - data.array.set(header.array, 4); - data.array.set(filename, 30); - datalength += data.array.length; - writer.writeUint8Array(data.array, callback, onwriteerror); - } - - function writeFooter(compressedLength, crc32) { - var footer = getDataHelper(16); - datalength += compressedLength || 0; - footer.view.setUint32(0, 0x504b0708); - if (typeof crc32 != "undefined") { - header.view.setUint32(10, crc32, true); - footer.view.setUint32(4, crc32, true); - } - if (reader) { - footer.view.setUint32(8, compressedLength, true); - header.view.setUint32(14, compressedLength, true); - footer.view.setUint32(12, reader.size, true); - header.view.setUint32(18, reader.size, true); - } - writer.writeUint8Array(footer.array, function() { - datalength += 16; - terminate(onend); - }, onwriteerror); - } - - function writeFile() { - options = options || {}; - name = name.trim(); - if (options.directory && name.charAt(name.length - 1) != "/") - name += "/"; - if (files.hasOwnProperty(name)) { - onerror(ERR_DUPLICATED_NAME); - return; - } - filename = getBytes(encodeUTF8(name)); - filenames.push(name); - writeHeader(function() { - if (reader) - if (dontDeflate || options.level === 0) - copy(reader, writer, 0, reader.size, true, writeFooter, onprogress, onreaderror, onwriteerror); - else - worker = deflate(reader, writer, options.level, writeFooter, onprogress, onreaderror, onwriteerror); - else - writeFooter(); - }, onwriteerror); - } - - if (reader) - reader.init(writeFile, onreaderror); - else - writeFile(); - }, - close : function(callback) { - var data, length = 0, index = 0, indexFilename, file; - for (indexFilename = 0; indexFilename < filenames.length; indexFilename++) { - file = files[filenames[indexFilename]]; - length += 46 + file.filename.length + file.comment.length; - } - data = getDataHelper(length + 22); - for (indexFilename = 0; indexFilename < filenames.length; indexFilename++) { - file = files[filenames[indexFilename]]; - data.view.setUint32(index, 0x504b0102); - data.view.setUint16(index + 4, 0x1400); - data.array.set(file.headerArray, index + 6); - data.view.setUint16(index + 32, file.comment.length, true); - if (file.directory) - data.view.setUint8(index + 38, 0x10); - data.view.setUint32(index + 42, file.offset, true); - data.array.set(file.filename, index + 46); - data.array.set(file.comment, index + 46 + file.filename.length); - index += 46 + file.filename.length + file.comment.length; - } - data.view.setUint32(index, 0x504b0506); - data.view.setUint16(index + 8, filenames.length, true); - data.view.setUint16(index + 10, filenames.length, true); - data.view.setUint32(index + 12, length, true); - data.view.setUint32(index + 16, datalength, true); - writer.writeUint8Array(data.array, function() { - terminate(function() { - writer.getData(callback); - }); - }, onwriteerror); - } - }; - } - - obj.zip = { - Reader : Reader, - Writer : Writer, - BlobReader : BlobReader, - Data64URIReader : Data64URIReader, - TextReader : TextReader, - BlobWriter : BlobWriter, - Data64URIWriter : Data64URIWriter, - TextWriter : TextWriter, - createReader : function(reader, callback, onerror) { - reader.init(function() { - callback(createZipReader(reader, onerror)); - }, onerror); - }, - createWriter : function(writer, callback, onerror, dontDeflate) { - writer.init(function() { - callback(createZipWriter(writer, onerror, dontDeflate)); - }, onerror); - }, - workerScriptsPath : "", - useWebWorkers : true - }; - -}(O.esri)); -/** - * This library assists with autoCenter the map upon orientation change - * IMPORTANT: There are Esri dependencies in this library including - * esri.Geometry.Point, esri.SpatialReference and Esri.Map. - * The fact that these dependencies exist is implied that they were - * loaded via some other means and made globally available. - * Sometimes this happens by default, as is true in this case. - * @param map - * @param delay - */ -O.esri.TPK.autoCenterMap = function(/* Map */ map,/* int */ delay){ - - /** - * Activates the orientation listener and listens for native events. - */ - function _setOrientationListener(delay){ - var supportsOrientationChange = "onorientationchange" in window, - orientationEvent = supportsOrientationChange ? "orientationchange" : "resize"; - - window.addEventListener(orientationEvent, _debounceMap(function(){ - _centerMap(); - },delay)); - } - - /** - * Center the map based on locations pulled from local storage - * @param context - * @param delay - * @private - */ - function _centerMap(){ - - require(["esri/geometry/Point","esri/SpatialReference"], function (Point,SpatialReference) { - var locationStr = _getCenterPt().split(","); - var wkid = map.spatialReference.wkid; - var mapPt = null; - - if(wkid == 4326){ - mapPt = new Point(locationStr[1],locationStr[0]); - } - else if(wkid == 102100){ - mapPt = new Point(locationStr[0],locationStr[1], new SpatialReference({ wkid: wkid })); - } - map.centerAt(mapPt); - }); - } - - /** - * Minimize the number of times window readjustment fires a function - * http://davidwalsh.name/javascript-debounce-function - * @param func - * @param wait - * @param immediate - * @returns {Function} - */ - function _debounceMap(func, wait, immediate) { - var timeout; - return function() { - var context = this, args = arguments; - clearTimeout(timeout); - timeout = setTimeout(function() { - timeout = null; - if (!immediate) { - func.apply(context, args); - } - }, wait); - if (immediate && !timeout) { - func.apply(context, args); - } - }; - } - - /** - * Automatically sets new center point in local storage. - */ - function _setPanListener(){ - map.on("pan-end",function(){ - var center = map.extent.getCenter(); - _setCenterPt(center.x,center.y,map.spatialReference.wkid); - }); - } - - /** - * Automatically sets new center point and zoom level in - * local storage. - */ - function _setZoomListener(){ - map.on("zoom-end",function(){ - var center = map.extent.getCenter(); - _setCenterPt(center.x,center.y,map.spatialReference.wkid); - map.setZoom(map.getZoom()); - }); - } - - /** - * Uses localStorage to save a location. - * @param lat - * @param lon - * @param spatialReference - */ - function _setCenterPt(lat,lon,spatialReference){ - localStorage.setItem("_centerPtX", lat); - localStorage.setItem("_centerPtY", lon); - localStorage.setItem("_spatialReference", spatialReference); - } - - /** - * Pulls a saved location from localStorage - * Requires that setCenterPt() has been set. - * @returns String x,y,spatialReference - */ - function _getCenterPt(){ - var value = null; - - try{ - value = localStorage.getItem("_centerPtX") + "," + localStorage.getItem("_centerPtY") + "," + - localStorage.getItem("_spatialReference"); - } - catch(err) - { - console.log("getCenterFromLocalStorage: " + err.message); - } - - return value; - } - - this.init = function(){ - _setPanListener(); - _setZoomListener(); - _setOrientationListener(delay); - var centerPt = map.extent.getCenter(); - _setCenterPt(centerPt.x,centerPt.y,map.spatialReference.wkid); - }; -}; -/* - Copyright (c) 2013 Gildas Lormeau. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the distribution. - - 3. The names of the authors may not be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, - INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, - INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This program is based on JZlib 1.0.2 ymnk, JCraft,Inc. - * JZlib is based on zlib-1.1.3, so all credit should go authors - * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) - * and contributors of zlib. - */ - -O.esri.TPK.inflate = function(obj) { - - // Global - var MAX_BITS = 15; - - var Z_OK = 0; - var Z_STREAM_END = 1; - var Z_NEED_DICT = 2; - var Z_STREAM_ERROR = -2; - var Z_DATA_ERROR = -3; - var Z_MEM_ERROR = -4; - var Z_BUF_ERROR = -5; - - var inflate_mask = [ 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff, 0x000003ff, - 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff ]; - - var MANY = 1440; - - // JZlib version : "1.0.2" - var Z_NO_FLUSH = 0; - var Z_FINISH = 4; - - // InfTree - var fixed_bl = 9; - var fixed_bd = 5; - - var fixed_tl = [ 96, 7, 256, 0, 8, 80, 0, 8, 16, 84, 8, 115, 82, 7, 31, 0, 8, 112, 0, 8, 48, 0, 9, 192, 80, 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, 160, 0, 8, 0, - 0, 8, 128, 0, 8, 64, 0, 9, 224, 80, 7, 6, 0, 8, 88, 0, 8, 24, 0, 9, 144, 83, 7, 59, 0, 8, 120, 0, 8, 56, 0, 9, 208, 81, 7, 17, 0, 8, 104, 0, 8, 40, - 0, 9, 176, 0, 8, 8, 0, 8, 136, 0, 8, 72, 0, 9, 240, 80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8, 227, 83, 7, 43, 0, 8, 116, 0, 8, 52, 0, 9, 200, 81, 7, 13, - 0, 8, 100, 0, 8, 36, 0, 9, 168, 0, 8, 4, 0, 8, 132, 0, 8, 68, 0, 9, 232, 80, 7, 8, 0, 8, 92, 0, 8, 28, 0, 9, 152, 84, 7, 83, 0, 8, 124, 0, 8, 60, - 0, 9, 216, 82, 7, 23, 0, 8, 108, 0, 8, 44, 0, 9, 184, 0, 8, 12, 0, 8, 140, 0, 8, 76, 0, 9, 248, 80, 7, 3, 0, 8, 82, 0, 8, 18, 85, 8, 163, 83, 7, - 35, 0, 8, 114, 0, 8, 50, 0, 9, 196, 81, 7, 11, 0, 8, 98, 0, 8, 34, 0, 9, 164, 0, 8, 2, 0, 8, 130, 0, 8, 66, 0, 9, 228, 80, 7, 7, 0, 8, 90, 0, 8, - 26, 0, 9, 148, 84, 7, 67, 0, 8, 122, 0, 8, 58, 0, 9, 212, 82, 7, 19, 0, 8, 106, 0, 8, 42, 0, 9, 180, 0, 8, 10, 0, 8, 138, 0, 8, 74, 0, 9, 244, 80, - 7, 5, 0, 8, 86, 0, 8, 22, 192, 8, 0, 83, 7, 51, 0, 8, 118, 0, 8, 54, 0, 9, 204, 81, 7, 15, 0, 8, 102, 0, 8, 38, 0, 9, 172, 0, 8, 6, 0, 8, 134, 0, - 8, 70, 0, 9, 236, 80, 7, 9, 0, 8, 94, 0, 8, 30, 0, 9, 156, 84, 7, 99, 0, 8, 126, 0, 8, 62, 0, 9, 220, 82, 7, 27, 0, 8, 110, 0, 8, 46, 0, 9, 188, 0, - 8, 14, 0, 8, 142, 0, 8, 78, 0, 9, 252, 96, 7, 256, 0, 8, 81, 0, 8, 17, 85, 8, 131, 82, 7, 31, 0, 8, 113, 0, 8, 49, 0, 9, 194, 80, 7, 10, 0, 8, 97, - 0, 8, 33, 0, 9, 162, 0, 8, 1, 0, 8, 129, 0, 8, 65, 0, 9, 226, 80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9, 146, 83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 210, - 81, 7, 17, 0, 8, 105, 0, 8, 41, 0, 9, 178, 0, 8, 9, 0, 8, 137, 0, 8, 73, 0, 9, 242, 80, 7, 4, 0, 8, 85, 0, 8, 21, 80, 8, 258, 83, 7, 43, 0, 8, 117, - 0, 8, 53, 0, 9, 202, 81, 7, 13, 0, 8, 101, 0, 8, 37, 0, 9, 170, 0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9, 234, 80, 7, 8, 0, 8, 93, 0, 8, 29, 0, 9, 154, - 84, 7, 83, 0, 8, 125, 0, 8, 61, 0, 9, 218, 82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 186, 0, 8, 13, 0, 8, 141, 0, 8, 77, 0, 9, 250, 80, 7, 3, 0, 8, 83, - 0, 8, 19, 85, 8, 195, 83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, 198, 81, 7, 11, 0, 8, 99, 0, 8, 35, 0, 9, 166, 0, 8, 3, 0, 8, 131, 0, 8, 67, 0, 9, 230, - 80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, 150, 84, 7, 67, 0, 8, 123, 0, 8, 59, 0, 9, 214, 82, 7, 19, 0, 8, 107, 0, 8, 43, 0, 9, 182, 0, 8, 11, 0, 8, 139, - 0, 8, 75, 0, 9, 246, 80, 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0, 83, 7, 51, 0, 8, 119, 0, 8, 55, 0, 9, 206, 81, 7, 15, 0, 8, 103, 0, 8, 39, 0, 9, 174, - 0, 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 238, 80, 7, 9, 0, 8, 95, 0, 8, 31, 0, 9, 158, 84, 7, 99, 0, 8, 127, 0, 8, 63, 0, 9, 222, 82, 7, 27, 0, 8, 111, - 0, 8, 47, 0, 9, 190, 0, 8, 15, 0, 8, 143, 0, 8, 79, 0, 9, 254, 96, 7, 256, 0, 8, 80, 0, 8, 16, 84, 8, 115, 82, 7, 31, 0, 8, 112, 0, 8, 48, 0, 9, - 193, 80, 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, 161, 0, 8, 0, 0, 8, 128, 0, 8, 64, 0, 9, 225, 80, 7, 6, 0, 8, 88, 0, 8, 24, 0, 9, 145, 83, 7, 59, 0, 8, - 120, 0, 8, 56, 0, 9, 209, 81, 7, 17, 0, 8, 104, 0, 8, 40, 0, 9, 177, 0, 8, 8, 0, 8, 136, 0, 8, 72, 0, 9, 241, 80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8, - 227, 83, 7, 43, 0, 8, 116, 0, 8, 52, 0, 9, 201, 81, 7, 13, 0, 8, 100, 0, 8, 36, 0, 9, 169, 0, 8, 4, 0, 8, 132, 0, 8, 68, 0, 9, 233, 80, 7, 8, 0, 8, - 92, 0, 8, 28, 0, 9, 153, 84, 7, 83, 0, 8, 124, 0, 8, 60, 0, 9, 217, 82, 7, 23, 0, 8, 108, 0, 8, 44, 0, 9, 185, 0, 8, 12, 0, 8, 140, 0, 8, 76, 0, 9, - 249, 80, 7, 3, 0, 8, 82, 0, 8, 18, 85, 8, 163, 83, 7, 35, 0, 8, 114, 0, 8, 50, 0, 9, 197, 81, 7, 11, 0, 8, 98, 0, 8, 34, 0, 9, 165, 0, 8, 2, 0, 8, - 130, 0, 8, 66, 0, 9, 229, 80, 7, 7, 0, 8, 90, 0, 8, 26, 0, 9, 149, 84, 7, 67, 0, 8, 122, 0, 8, 58, 0, 9, 213, 82, 7, 19, 0, 8, 106, 0, 8, 42, 0, 9, - 181, 0, 8, 10, 0, 8, 138, 0, 8, 74, 0, 9, 245, 80, 7, 5, 0, 8, 86, 0, 8, 22, 192, 8, 0, 83, 7, 51, 0, 8, 118, 0, 8, 54, 0, 9, 205, 81, 7, 15, 0, 8, - 102, 0, 8, 38, 0, 9, 173, 0, 8, 6, 0, 8, 134, 0, 8, 70, 0, 9, 237, 80, 7, 9, 0, 8, 94, 0, 8, 30, 0, 9, 157, 84, 7, 99, 0, 8, 126, 0, 8, 62, 0, 9, - 221, 82, 7, 27, 0, 8, 110, 0, 8, 46, 0, 9, 189, 0, 8, 14, 0, 8, 142, 0, 8, 78, 0, 9, 253, 96, 7, 256, 0, 8, 81, 0, 8, 17, 85, 8, 131, 82, 7, 31, 0, - 8, 113, 0, 8, 49, 0, 9, 195, 80, 7, 10, 0, 8, 97, 0, 8, 33, 0, 9, 163, 0, 8, 1, 0, 8, 129, 0, 8, 65, 0, 9, 227, 80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9, - 147, 83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 211, 81, 7, 17, 0, 8, 105, 0, 8, 41, 0, 9, 179, 0, 8, 9, 0, 8, 137, 0, 8, 73, 0, 9, 243, 80, 7, 4, 0, 8, - 85, 0, 8, 21, 80, 8, 258, 83, 7, 43, 0, 8, 117, 0, 8, 53, 0, 9, 203, 81, 7, 13, 0, 8, 101, 0, 8, 37, 0, 9, 171, 0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9, - 235, 80, 7, 8, 0, 8, 93, 0, 8, 29, 0, 9, 155, 84, 7, 83, 0, 8, 125, 0, 8, 61, 0, 9, 219, 82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 187, 0, 8, 13, 0, 8, - 141, 0, 8, 77, 0, 9, 251, 80, 7, 3, 0, 8, 83, 0, 8, 19, 85, 8, 195, 83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, 199, 81, 7, 11, 0, 8, 99, 0, 8, 35, 0, 9, - 167, 0, 8, 3, 0, 8, 131, 0, 8, 67, 0, 9, 231, 80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, 151, 84, 7, 67, 0, 8, 123, 0, 8, 59, 0, 9, 215, 82, 7, 19, 0, 8, - 107, 0, 8, 43, 0, 9, 183, 0, 8, 11, 0, 8, 139, 0, 8, 75, 0, 9, 247, 80, 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0, 83, 7, 51, 0, 8, 119, 0, 8, 55, 0, 9, - 207, 81, 7, 15, 0, 8, 103, 0, 8, 39, 0, 9, 175, 0, 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 239, 80, 7, 9, 0, 8, 95, 0, 8, 31, 0, 9, 159, 84, 7, 99, 0, 8, - 127, 0, 8, 63, 0, 9, 223, 82, 7, 27, 0, 8, 111, 0, 8, 47, 0, 9, 191, 0, 8, 15, 0, 8, 143, 0, 8, 79, 0, 9, 255 ]; - var fixed_td = [ 80, 5, 1, 87, 5, 257, 83, 5, 17, 91, 5, 4097, 81, 5, 5, 89, 5, 1025, 85, 5, 65, 93, 5, 16385, 80, 5, 3, 88, 5, 513, 84, 5, 33, 92, 5, - 8193, 82, 5, 9, 90, 5, 2049, 86, 5, 129, 192, 5, 24577, 80, 5, 2, 87, 5, 385, 83, 5, 25, 91, 5, 6145, 81, 5, 7, 89, 5, 1537, 85, 5, 97, 93, 5, - 24577, 80, 5, 4, 88, 5, 769, 84, 5, 49, 92, 5, 12289, 82, 5, 13, 90, 5, 3073, 86, 5, 193, 192, 5, 24577 ]; - - // Tables for deflate from PKZIP's appnote.txt. - var cplens = [ // Copy lengths for literal codes 257..285 - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 ]; - - // see note #13 above about 258 - var cplext = [ // Extra bits for literal codes 257..285 - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112 // 112==invalid - ]; - - var cpdist = [ // Copy offsets for distance codes 0..29 - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 ]; - - var cpdext = [ // Extra bits for distance codes - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 ]; - - // If BMAX needs to be larger than 16, then h and x[] should be uLong. - var BMAX = 15; // maximum bit length of any code - - function InfTree() { - var that = this; - - var hn; // hufts used in space - var v; // work area for huft_build - var c; // bit length count table - var r; // table entry for structure assignment - var u; // table stack - var x; // bit offsets, then code stack - - function huft_build(b, // code lengths in bits (all assumed <= - // BMAX) - bindex, n, // number of codes (assumed <= 288) - s, // number of simple-valued codes (0..s-1) - d, // list of base values for non-simple codes - e, // list of extra bits for non-simple codes - t, // result: starting table - m, // maximum lookup bits, returns actual - hp,// space for trees - hn,// hufts used in space - v // working area: values in order of bit length - ) { - // Given a list of code lengths and a maximum table size, make a set of - // tables to decode that set of codes. Return Z_OK on success, - // Z_BUF_ERROR - // if the given code set is incomplete (the tables are still built in - // this - // case), Z_DATA_ERROR if the input is invalid (an over-subscribed set - // of - // lengths), or Z_MEM_ERROR if not enough memory. - - var a; // counter for codes of length k - var f; // i repeats in table every f entries - var g; // maximum code length - var h; // table level - var i; // counter, current code - var j; // counter - var k; // number of bits in current code - var l; // bits per table (returned in m) - var mask; // (1 << w) - 1, to avoid cc -O bug on HP - var p; // pointer into c[], b[], or v[] - var q; // points to current table - var w; // bits before this table == (l * h) - var xp; // pointer into x - var y; // number of dummy codes added - var z; // number of entries in current table - - // Generate counts for each bit length - - p = 0; - i = n; - do { - c[b[bindex + p]]++; - p++; - i--; // assume all entries <= BMAX - } while (i !== 0); - - if (c[0] == n) { // null input--all zero length codes - t[0] = -1; - m[0] = 0; - return Z_OK; - } - - // Find minimum and maximum length, bound *m by those - l = m[0]; - for (j = 1; j <= BMAX; j++) - if (c[j] !== 0) - break; - k = j; // minimum code length - if (l < j) { - l = j; - } - for (i = BMAX; i !== 0; i--) { - if (c[i] !== 0) - break; - } - g = i; // maximum code length - if (l > i) { - l = i; - } - m[0] = l; - - // Adjust last length count to fill out codes, if needed - for (y = 1 << j; j < i; j++, y <<= 1) { - if ((y -= c[j]) < 0) { - return Z_DATA_ERROR; - } - } - if ((y -= c[i]) < 0) { - return Z_DATA_ERROR; - } - c[i] += y; - - // Generate starting offsets into the value table for each length - x[1] = j = 0; - p = 1; - xp = 2; - while (--i !== 0) { // note that i == g from above - x[xp] = (j += c[p]); - xp++; - p++; - } - - // Make a table of values in order of bit lengths - i = 0; - p = 0; - do { - if ((j = b[bindex + p]) !== 0) { - v[x[j]++] = i; - } - p++; - } while (++i < n); - n = x[g]; // set n to length of v - - // Generate the Huffman codes and for each, make the table entries - x[0] = i = 0; // first Huffman code is zero - p = 0; // grab values in bit order - h = -1; // no tables yet--level -1 - w = -l; // bits decoded == (l * h) - u[0] = 0; // just to keep compilers happy - q = 0; // ditto - z = 0; // ditto - - // go through the bit lengths (k already is bits in shortest code) - for (; k <= g; k++) { - a = c[k]; - while (a-- !== 0) { - // here i is the Huffman code of length k bits for value *p - // make tables up to required level - while (k > w + l) { - h++; - w += l; // previous table always l bits - // compute minimum size table less than or equal to l bits - z = g - w; - z = (z > l) ? l : z; // table size upper limit - if ((f = 1 << (j = k - w)) > a + 1) { // try a k-w bit table - // too few codes for - // k-w bit table - f -= a + 1; // deduct codes from patterns left - xp = k; - if (j < z) { - while (++j < z) { // try smaller tables up to z bits - if ((f <<= 1) <= c[++xp]) - break; // enough codes to use up j bits - f -= c[xp]; // else deduct codes from patterns - } - } - } - z = 1 << j; // table entries for j-bit table - - // allocate new table - if (hn[0] + z > MANY) { // (note: doesn't matter for fixed) - return Z_DATA_ERROR; // overflow of MANY - } - u[h] = q = /* hp+ */hn[0]; // DEBUG - hn[0] += z; - - // connect to last table, if there is one - if (h !== 0) { - x[h] = i; // save pattern for backing up - r[0] = /* (byte) */j; // bits in this table - r[1] = /* (byte) */l; // bits to dump before this table - j = i >>> (w - l); - r[2] = /* (int) */(q - u[h - 1] - j); // offset to this table - hp.set(r, (u[h - 1] + j) * 3); - // to - // last - // table - } else { - t[0] = q; // first table is returned result - } - } - - // set up table entry in r - r[1] = /* (byte) */(k - w); - if (p >= n) { - r[0] = 128 + 64; // out of values--invalid code - } else if (v[p] < s) { - r[0] = /* (byte) */(v[p] < 256 ? 0 : 32 + 64); // 256 is - // end-of-block - r[2] = v[p++]; // simple code is just the value - } else { - r[0] = /* (byte) */(e[v[p] - s] + 16 + 64); // non-simple--look - // up in lists - r[2] = d[v[p++] - s]; - } - - // fill code-like entries with r - f = 1 << (k - w); - for (j = i >>> w; j < z; j += f) { - hp.set(r, (q + j) * 3); - } - - // backwards increment the k-bit code i - for (j = 1 << (k - 1); (i & j) !== 0; j >>>= 1) { - i ^= j; - } - i ^= j; - - // backup over finished tables - mask = (1 << w) - 1; // needed on HP, cc -O bug - while ((i & mask) != x[h]) { - h--; // don't need to update q - w -= l; - mask = (1 << w) - 1; - } - } - } - // Return Z_BUF_ERROR if we were given an incomplete table - return y !== 0 && g != 1 ? Z_BUF_ERROR : Z_OK; - } - - function initWorkArea(vsize) { - var i; - if (!hn) { - hn = []; // []; //new Array(1); - v = []; // new Array(vsize); - c = new Int32Array(BMAX + 1); // new Array(BMAX + 1); - r = []; // new Array(3); - u = new Int32Array(BMAX); // new Array(BMAX); - x = new Int32Array(BMAX + 1); // new Array(BMAX + 1); - } - if (v.length < vsize) { - v = []; // new Array(vsize); - } - for (i = 0; i < vsize; i++) { - v[i] = 0; - } - for (i = 0; i < BMAX + 1; i++) { - c[i] = 0; - } - for (i = 0; i < 3; i++) { - r[i] = 0; - } - // for(int i=0; i 257)) { - if (result == Z_DATA_ERROR) { - z.msg = "oversubscribed distance tree"; - } else if (result == Z_BUF_ERROR) { - z.msg = "incomplete distance tree"; - result = Z_DATA_ERROR; - } else if (result != Z_MEM_ERROR) { - z.msg = "empty distance tree with lengths"; - result = Z_DATA_ERROR; - } - return result; - } - - return Z_OK; - }; - - } - - InfTree.inflate_trees_fixed = function(bl, // literal desired/actual bit depth - bd, // distance desired/actual bit depth - tl,// literal/length tree result - td// distance tree result - ) { - bl[0] = fixed_bl; - bd[0] = fixed_bd; - tl[0] = fixed_tl; - td[0] = fixed_td; - return Z_OK; - }; - - // InfCodes - - // waiting for "i:"=input, - // "o:"=output, - // "x:"=nothing - var START = 0; // x: set up for LEN - var LEN = 1; // i: get length/literal/eob next - var LENEXT = 2; // i: getting length extra (have base) - var DIST = 3; // i: get distance next - var DISTEXT = 4;// i: getting distance extra - var COPY = 5; // o: copying bytes in window, waiting - // for space - var LIT = 6; // o: got literal, waiting for output - // space - var WASH = 7; // o: got eob, possibly still output - // waiting - var END = 8; // x: got eob and all data flushed - var BADCODE = 9;// x: got error - - function InfCodes() { - var that = this; - - var mode; // current inflate_codes mode - - // mode dependent information - var len = 0; - - var tree; // pointer into tree - var tree_index = 0; - var need = 0; // bits needed - - var lit = 0; - - // if EXT or COPY, where and how much - var get = 0; // bits to get for extra - var dist = 0; // distance back to copy from - - var lbits = 0; // ltree bits decoded per branch - var dbits = 0; // dtree bits decoder per branch - var ltree; // literal/length/eob tree - var ltree_index = 0; // literal/length/eob tree - var dtree; // distance tree - var dtree_index = 0; // distance tree - - // Called with number of bytes left to write in window at least 258 - // (the maximum string length) and number of input bytes available - // at least ten. The ten bytes are six bytes for the longest length/ - // distance pair plus four bytes for overloading the bit buffer. - - function inflate_fast(bl, bd, tl, tl_index, td, td_index, s, z) { - var t; // temporary pointer - var tp; // temporary pointer - var tp_index; // temporary pointer - var e; // extra bits or operation - var b; // bit buffer - var k; // bits in bit buffer - var p; // input data pointer - var n; // bytes available there - var q; // output window write pointer - var m; // bytes to end of window or read pointer - var ml; // mask for literal/length tree - var md; // mask for distance tree - var c; // bytes to copy - var d; // distance back to copy from - var r; // copy source pointer - - var tp_index_t_3; // (tp_index+t)*3 - - // load input, output, bit values - p = z.next_in_index; - n = z.avail_in; - b = s.bitb; - k = s.bitk; - q = s.write; - m = q < s.read ? s.read - q - 1 : s.end - q; - - // initialize masks - ml = inflate_mask[bl]; - md = inflate_mask[bd]; - - // do until not enough input or output space for fast loop - do { // assume called with m >= 258 && n >= 10 - // get literal/length code - while (k < (20)) { // max bits for literal/length code - n--; - b |= (z.read_byte(p++) & 0xff) << k; - k += 8; - } - - t = b & ml; - tp = tl; - tp_index = tl_index; - tp_index_t_3 = (tp_index + t) * 3; - if ((e = tp[tp_index_t_3]) === 0) { - b >>= (tp[tp_index_t_3 + 1]); - k -= (tp[tp_index_t_3 + 1]); - - s.window[q++] = /* (byte) */tp[tp_index_t_3 + 2]; - m--; - continue; - } - do { - - b >>= (tp[tp_index_t_3 + 1]); - k -= (tp[tp_index_t_3 + 1]); - - if ((e & 16) !== 0) { - e &= 15; - c = tp[tp_index_t_3 + 2] + (/* (int) */b & inflate_mask[e]); - - b >>= e; - k -= e; - - // decode distance base of block to copy - while (k < (15)) { // max bits for distance code - n--; - b |= (z.read_byte(p++) & 0xff) << k; - k += 8; - } - - t = b & md; - tp = td; - tp_index = td_index; - tp_index_t_3 = (tp_index + t) * 3; - e = tp[tp_index_t_3]; - - do { - - b >>= (tp[tp_index_t_3 + 1]); - k -= (tp[tp_index_t_3 + 1]); - - if ((e & 16) !== 0) { - // get extra bits to add to distance base - e &= 15; - while (k < (e)) { // get extra bits (up to 13) - n--; - b |= (z.read_byte(p++) & 0xff) << k; - k += 8; - } - - d = tp[tp_index_t_3 + 2] + (b & inflate_mask[e]); - - b >>= (e); - k -= (e); - - // do the copy - m -= c; - if (q >= d) { // offset before dest - // just copy - r = q - d; - if (q - r > 0 && 2 > (q - r)) { - s.window[q++] = s.window[r++]; // minimum - // count is - // three, - s.window[q++] = s.window[r++]; // so unroll - // loop a - // little - c -= 2; - } else { - s.window.set(s.window.subarray(r, r + 2), q); - q += 2; - r += 2; - c -= 2; - } - } else { // else offset after destination - r = q - d; - do { - r += s.end; // force pointer in window - } while (r < 0); // covers invalid distances - e = s.end - r; - if (c > e) { // if source crosses, - c -= e; // wrapped copy - if (q - r > 0 && e > (q - r)) { - do { - s.window[q++] = s.window[r++]; - } while (--e !== 0); - } else { - s.window.set(s.window.subarray(r, r + e), q); - q += e; - r += e; - e = 0; - } - r = 0; // copy rest from start of window - } - - } - - // copy all or what's left - if (q - r > 0 && c > (q - r)) { - do { - s.window[q++] = s.window[r++]; - } while (--c !== 0); - } else { - s.window.set(s.window.subarray(r, r + c), q); - q += c; - r += c; - c = 0; - } - break; - } else if ((e & 64) === 0) { - t += tp[tp_index_t_3 + 2]; - t += (b & inflate_mask[e]); - tp_index_t_3 = (tp_index + t) * 3; - e = tp[tp_index_t_3]; - } else { - z.msg = "invalid distance code"; - - c = z.avail_in - n; - c = (k >> 3) < c ? k >> 3 : c; - n += c; - p -= c; - k -= c << 3; - - s.bitb = b; - s.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - s.write = q; - - return Z_DATA_ERROR; - } - } while (true); - break; - } - - if ((e & 64) === 0) { - t += tp[tp_index_t_3 + 2]; - t += (b & inflate_mask[e]); - tp_index_t_3 = (tp_index + t) * 3; - if ((e = tp[tp_index_t_3]) === 0) { - - b >>= (tp[tp_index_t_3 + 1]); - k -= (tp[tp_index_t_3 + 1]); - - s.window[q++] = /* (byte) */tp[tp_index_t_3 + 2]; - m--; - break; - } - } else if ((e & 32) !== 0) { - - c = z.avail_in - n; - c = (k >> 3) < c ? k >> 3 : c; - n += c; - p -= c; - k -= c << 3; - - s.bitb = b; - s.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - s.write = q; - - return Z_STREAM_END; - } else { - z.msg = "invalid literal/length code"; - - c = z.avail_in - n; - c = (k >> 3) < c ? k >> 3 : c; - n += c; - p -= c; - k -= c << 3; - - s.bitb = b; - s.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - s.write = q; - - return Z_DATA_ERROR; - } - } while (true); - } while (m >= 258 && n >= 10); - - // not enough input or output--restore pointers and return - c = z.avail_in - n; - c = (k >> 3) < c ? k >> 3 : c; - n += c; - p -= c; - k -= c << 3; - - s.bitb = b; - s.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - s.write = q; - - return Z_OK; - } - - that.init = function(bl, bd, tl, tl_index, td, td_index) { - mode = START; - lbits = /* (byte) */bl; - dbits = /* (byte) */bd; - ltree = tl; - ltree_index = tl_index; - dtree = td; - dtree_index = td_index; - tree = null; - }; - - that.proc = function(s, z, r) { - var j; // temporary storage - var tindex; // temporary pointer - var e; // extra bits or operation - var b = 0; // bit buffer - var k = 0; // bits in bit buffer - var p = 0; // input data pointer - var n; // bytes available there - var q; // output window write pointer - var m; // bytes to end of window or read pointer - var f; // pointer to copy strings from - - // copy input/output information to locals (UPDATE macro restores) - p = z.next_in_index; - n = z.avail_in; - b = s.bitb; - k = s.bitk; - q = s.write; - m = q < s.read ? s.read - q - 1 : s.end - q; - - // process input and output based on current state - while (true) { - switch (mode) { - // waiting for "i:"=input, "o:"=output, "x:"=nothing - case START: // x: set up for LEN - if (m >= 258 && n >= 10) { - - s.bitb = b; - s.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - s.write = q; - r = inflate_fast(lbits, dbits, ltree, ltree_index, dtree, dtree_index, s, z); - - p = z.next_in_index; - n = z.avail_in; - b = s.bitb; - k = s.bitk; - q = s.write; - m = q < s.read ? s.read - q - 1 : s.end - q; - - if (r != Z_OK) { - mode = r == Z_STREAM_END ? WASH : BADCODE; - break; - } - } - need = lbits; - tree = ltree; - tree_index = ltree_index; - - mode = LEN; - case LEN: // i: get length/literal/eob next - j = need; - - while (k < (j)) { - if (n !== 0) - r = Z_OK; - else { - - s.bitb = b; - s.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - s.write = q; - return s.inflate_flush(z, r); - } - n--; - b |= (z.read_byte(p++) & 0xff) << k; - k += 8; - } - - tindex = (tree_index + (b & inflate_mask[j])) * 3; - - b >>>= (tree[tindex + 1]); - k -= (tree[tindex + 1]); - - e = tree[tindex]; - - if (e === 0) { // literal - lit = tree[tindex + 2]; - mode = LIT; - break; - } - if ((e & 16) !== 0) { // length - get = e & 15; - len = tree[tindex + 2]; - mode = LENEXT; - break; - } - if ((e & 64) === 0) { // next table - need = e; - tree_index = tindex / 3 + tree[tindex + 2]; - break; - } - if ((e & 32) !== 0) { // end of block - mode = WASH; - break; - } - mode = BADCODE; // invalid code - z.msg = "invalid literal/length code"; - r = Z_DATA_ERROR; - - s.bitb = b; - s.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - s.write = q; - return s.inflate_flush(z, r); - - case LENEXT: // i: getting length extra (have base) - j = get; - - while (k < (j)) { - if (n !== 0) - r = Z_OK; - else { - - s.bitb = b; - s.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - s.write = q; - return s.inflate_flush(z, r); - } - n--; - b |= (z.read_byte(p++) & 0xff) << k; - k += 8; - } - - len += (b & inflate_mask[j]); - - b >>= j; - k -= j; - - need = dbits; - tree = dtree; - tree_index = dtree_index; - mode = DIST; - case DIST: // i: get distance next - j = need; - - while (k < (j)) { - if (n !== 0) - r = Z_OK; - else { - - s.bitb = b; - s.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - s.write = q; - return s.inflate_flush(z, r); - } - n--; - b |= (z.read_byte(p++) & 0xff) << k; - k += 8; - } - - tindex = (tree_index + (b & inflate_mask[j])) * 3; - - b >>= tree[tindex + 1]; - k -= tree[tindex + 1]; - - e = (tree[tindex]); - if ((e & 16) !== 0) { // distance - get = e & 15; - dist = tree[tindex + 2]; - mode = DISTEXT; - break; - } - if ((e & 64) === 0) { // next table - need = e; - tree_index = tindex / 3 + tree[tindex + 2]; - break; - } - mode = BADCODE; // invalid code - z.msg = "invalid distance code"; - r = Z_DATA_ERROR; - - s.bitb = b; - s.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - s.write = q; - return s.inflate_flush(z, r); - - case DISTEXT: // i: getting distance extra - j = get; - - while (k < (j)) { - if (n !== 0) - r = Z_OK; - else { - - s.bitb = b; - s.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - s.write = q; - return s.inflate_flush(z, r); - } - n--; - b |= (z.read_byte(p++) & 0xff) << k; - k += 8; - } - - dist += (b & inflate_mask[j]); - - b >>= j; - k -= j; - - mode = COPY; - case COPY: // o: copying bytes in window, waiting for space - f = q - dist; - while (f < 0) { // modulo window size-"while" instead - f += s.end; // of "if" handles invalid distances - } - while (len !== 0) { - - if (m === 0) { - if (q == s.end && s.read !== 0) { - q = 0; - m = q < s.read ? s.read - q - 1 : s.end - q; - } - if (m === 0) { - s.write = q; - r = s.inflate_flush(z, r); - q = s.write; - m = q < s.read ? s.read - q - 1 : s.end - q; - - if (q == s.end && s.read !== 0) { - q = 0; - m = q < s.read ? s.read - q - 1 : s.end - q; - } - - if (m === 0) { - s.bitb = b; - s.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - s.write = q; - return s.inflate_flush(z, r); - } - } - } - - s.window[q++] = s.window[f++]; - m--; - - if (f == s.end) - f = 0; - len--; - } - mode = START; - break; - case LIT: // o: got literal, waiting for output space - if (m === 0) { - if (q == s.end && s.read !== 0) { - q = 0; - m = q < s.read ? s.read - q - 1 : s.end - q; - } - if (m === 0) { - s.write = q; - r = s.inflate_flush(z, r); - q = s.write; - m = q < s.read ? s.read - q - 1 : s.end - q; - - if (q == s.end && s.read !== 0) { - q = 0; - m = q < s.read ? s.read - q - 1 : s.end - q; - } - if (m === 0) { - s.bitb = b; - s.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - s.write = q; - return s.inflate_flush(z, r); - } - } - } - r = Z_OK; - - s.window[q++] = /* (byte) */lit; - m--; - - mode = START; - break; - case WASH: // o: got eob, possibly more output - if (k > 7) { // return unused byte, if any - k -= 8; - n++; - p--; // can always return one - } - - s.write = q; - r = s.inflate_flush(z, r); - q = s.write; - m = q < s.read ? s.read - q - 1 : s.end - q; - - if (s.read != s.write) { - s.bitb = b; - s.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - s.write = q; - return s.inflate_flush(z, r); - } - mode = END; - case END: - r = Z_STREAM_END; - s.bitb = b; - s.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - s.write = q; - return s.inflate_flush(z, r); - - case BADCODE: // x: got error - - r = Z_DATA_ERROR; - - s.bitb = b; - s.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - s.write = q; - return s.inflate_flush(z, r); - - default: - r = Z_STREAM_ERROR; - - s.bitb = b; - s.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - s.write = q; - return s.inflate_flush(z, r); - } - } - }; - - that.free = function() { - // ZFREE(z, c); - }; - - } - - // InfBlocks - - // Table for deflate from PKZIP's appnote.txt. - var border = [ // Order of the bit length code lengths - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ]; - - var TYPE = 0; // get type bits (3, including end bit) - var LENS = 1; // get lengths for stored - var STORED = 2;// processing stored block - var TABLE = 3; // get table lengths - var BTREE = 4; // get bit lengths tree for a dynamic - // block - var DTREE = 5; // get length, distance trees for a - // dynamic block - var CODES = 6; // processing fixed or dynamic block - var DRY = 7; // output remaining window bytes - var DONELOCKS = 8; // finished last block, done - var BADBLOCKS = 9; // ot a data error--stuck here - - function InfBlocks(z, w) { - var that = this; - - var mode = TYPE; // current inflate_block mode - - var left = 0; // if STORED, bytes left to copy - - var table = 0; // table lengths (14 bits) - var index = 0; // index into blens (or border) - var blens; // bit lengths of codes - var bb = [ 0 ]; // bit length tree depth - var tb = [ 0 ]; // bit length decoding tree - - var codes = new InfCodes(); // if CODES, current state - - var last = 0; // true if this block is the last block - - var hufts = new Int32Array(MANY * 3); // single malloc for tree space - var check = 0; // check on output - var inftree = new InfTree(); - - that.bitk = 0; // bits in bit buffer - that.bitb = 0; // bit buffer - that.window = new Uint8Array(w); // sliding window - that.end = w; // one byte after sliding window - that.read = 0; // window read pointer - that.write = 0; // window write pointer - - that.reset = function(z, c) { - if (c) - c[0] = check; - // if (mode == BTREE || mode == DTREE) { - // } - if (mode == CODES) { - codes.free(z); - } - mode = TYPE; - that.bitk = 0; - that.bitb = 0; - that.read = that.write = 0; - }; - - that.reset(z, null); - - // copy as much as possible from the sliding window to the output area - that.inflate_flush = function(z, r) { - var n; - var p; - var q; - - // local copies of source and destination pointers - p = z.next_out_index; - q = that.read; - - // compute number of bytes to copy as far as end of window - n = /* (int) */((q <= that.write ? that.write : that.end) - q); - if (n > z.avail_out) - n = z.avail_out; - if (n !== 0 && r == Z_BUF_ERROR) - r = Z_OK; - - // update counters - z.avail_out -= n; - z.total_out += n; - - // copy as far as end of window - z.next_out.set(that.window.subarray(q, q + n), p); - p += n; - q += n; - - // see if more to copy at beginning of window - if (q == that.end) { - // wrap pointers - q = 0; - if (that.write == that.end) - that.write = 0; - - // compute bytes to copy - n = that.write - q; - if (n > z.avail_out) - n = z.avail_out; - if (n !== 0 && r == Z_BUF_ERROR) - r = Z_OK; - - // update counters - z.avail_out -= n; - z.total_out += n; - - // copy - z.next_out.set(that.window.subarray(q, q + n), p); - p += n; - q += n; - } - - // update pointers - z.next_out_index = p; - that.read = q; - - // done - return r; - }; - - that.proc = function(z, r) { - var t; // temporary storage - var b; // bit buffer - var k; // bits in bit buffer - var p; // input data pointer - var n; // bytes available there - var q; // output window write pointer - var m; // bytes to end of window or read pointer - - var i; - - // copy input/output information to locals (UPDATE macro restores) - // { - p = z.next_in_index; - n = z.avail_in; - b = that.bitb; - k = that.bitk; - // } - // { - q = that.write; - m = /* (int) */(q < that.read ? that.read - q - 1 : that.end - q); - // } - - // process input based on current state - // DEBUG dtree - while (true) { - switch (mode) { - case TYPE: - - while (k < (3)) { - if (n !== 0) { - r = Z_OK; - } else { - that.bitb = b; - that.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - that.write = q; - return that.inflate_flush(z, r); - } - n--; - b |= (z.read_byte(p++) & 0xff) << k; - k += 8; - } - t = /* (int) */(b & 7); - last = t & 1; - - switch (t >>> 1) { - case 0: // stored - // { - b >>>= (3); - k -= (3); - // } - t = k & 7; // go to byte boundary - - // { - b >>>= (t); - k -= (t); - // } - mode = LENS; // get length of stored block - break; - case 1: // fixed - // { - var bl = []; // new Array(1); - var bd = []; // new Array(1); - var tl = [ [] ]; // new Array(1); - var td = [ [] ]; // new Array(1); - - InfTree.inflate_trees_fixed(bl, bd, tl, td); - codes.init(bl[0], bd[0], tl[0], 0, td[0], 0); - // } - - // { - b >>>= (3); - k -= (3); - // } - - mode = CODES; - break; - case 2: // dynamic - - // { - b >>>= (3); - k -= (3); - // } - - mode = TABLE; - break; - case 3: // illegal - - // { - b >>>= (3); - k -= (3); - // } - mode = BADBLOCKS; - z.msg = "invalid block type"; - r = Z_DATA_ERROR; - - that.bitb = b; - that.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - that.write = q; - return that.inflate_flush(z, r); - } - break; - case LENS: - - while (k < (32)) { - if (n !== 0) { - r = Z_OK; - } else { - that.bitb = b; - that.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - that.write = q; - return that.inflate_flush(z, r); - } - n--; - b |= (z.read_byte(p++) & 0xff) << k; - k += 8; - } - - if ((((~b) >>> 16) & 0xffff) != (b & 0xffff)) { - mode = BADBLOCKS; - z.msg = "invalid stored block lengths"; - r = Z_DATA_ERROR; - - that.bitb = b; - that.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - that.write = q; - return that.inflate_flush(z, r); - } - left = (b & 0xffff); - b = k = 0; // dump bits - mode = left !== 0 ? STORED : (last !== 0 ? DRY : TYPE); - break; - case STORED: - if (n === 0) { - that.bitb = b; - that.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - that.write = q; - return that.inflate_flush(z, r); - } - - if (m === 0) { - if (q == that.end && that.read !== 0) { - q = 0; - m = /* (int) */(q < that.read ? that.read - q - 1 : that.end - q); - } - if (m === 0) { - that.write = q; - r = that.inflate_flush(z, r); - q = that.write; - m = /* (int) */(q < that.read ? that.read - q - 1 : that.end - q); - if (q == that.end && that.read !== 0) { - q = 0; - m = /* (int) */(q < that.read ? that.read - q - 1 : that.end - q); - } - if (m === 0) { - that.bitb = b; - that.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - that.write = q; - return that.inflate_flush(z, r); - } - } - } - r = Z_OK; - - t = left; - if (t > n) - t = n; - if (t > m) - t = m; - that.window.set(z.read_buf(p, t), q); - p += t; - n -= t; - q += t; - m -= t; - if ((left -= t) !== 0) - break; - mode = last !== 0 ? DRY : TYPE; - break; - case TABLE: - - while (k < (14)) { - if (n !== 0) { - r = Z_OK; - } else { - that.bitb = b; - that.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - that.write = q; - return that.inflate_flush(z, r); - } - - n--; - b |= (z.read_byte(p++) & 0xff) << k; - k += 8; - } - - table = t = (b & 0x3fff); - if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) { - mode = BADBLOCKS; - z.msg = "too many length or distance symbols"; - r = Z_DATA_ERROR; - - that.bitb = b; - that.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - that.write = q; - return that.inflate_flush(z, r); - } - t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); - if (!blens || blens.length < t) { - blens = []; // new Array(t); - } else { - for (i = 0; i < t; i++) { - blens[i] = 0; - } - } - - // { - b >>>= (14); - k -= (14); - // } - - index = 0; - mode = BTREE; - case BTREE: - while (index < 4 + (table >>> 10)) { - while (k < (3)) { - if (n !== 0) { - r = Z_OK; - } else { - that.bitb = b; - that.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - that.write = q; - return that.inflate_flush(z, r); - } - n--; - b |= (z.read_byte(p++) & 0xff) << k; - k += 8; - } - - blens[border[index++]] = b & 7; - - // { - b >>>= (3); - k -= (3); - // } - } - - while (index < 19) { - blens[border[index++]] = 0; - } - - bb[0] = 7; - t = inftree.inflate_trees_bits(blens, bb, tb, hufts, z); - if (t != Z_OK) { - r = t; - if (r == Z_DATA_ERROR) { - blens = null; - mode = BADBLOCKS; - } - - that.bitb = b; - that.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - that.write = q; - return that.inflate_flush(z, r); - } - - index = 0; - mode = DTREE; - case DTREE: - while (true) { - t = table; - if (!(index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))) { - break; - } - - var j, c; - - t = bb[0]; - - while (k < (t)) { - if (n !== 0) { - r = Z_OK; - } else { - that.bitb = b; - that.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - that.write = q; - return that.inflate_flush(z, r); - } - n--; - b |= (z.read_byte(p++) & 0xff) << k; - k += 8; - } - - // if (tb[0] == -1) { - // System.err.println("null..."); - // } - - t = hufts[(tb[0] + (b & inflate_mask[t])) * 3 + 1]; - c = hufts[(tb[0] + (b & inflate_mask[t])) * 3 + 2]; - - if (c < 16) { - b >>>= (t); - k -= (t); - blens[index++] = c; - } else { // c == 16..18 - i = c == 18 ? 7 : c - 14; - j = c == 18 ? 11 : 3; - - while (k < (t + i)) { - if (n !== 0) { - r = Z_OK; - } else { - that.bitb = b; - that.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - that.write = q; - return that.inflate_flush(z, r); - } - n--; - b |= (z.read_byte(p++) & 0xff) << k; - k += 8; - } - - b >>>= (t); - k -= (t); - - j += (b & inflate_mask[i]); - - b >>>= (i); - k -= (i); - - i = index; - t = table; - if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || (c == 16 && i < 1)) { - blens = null; - mode = BADBLOCKS; - z.msg = "invalid bit length repeat"; - r = Z_DATA_ERROR; - - that.bitb = b; - that.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - that.write = q; - return that.inflate_flush(z, r); - } - - c = c == 16 ? blens[i - 1] : 0; - do { - blens[i++] = c; - } while (--j !== 0); - index = i; - } - } - - tb[0] = -1; - // { - var bl_ = []; // new Array(1); - var bd_ = []; // new Array(1); - var tl_ = []; // new Array(1); - var td_ = []; // new Array(1); - bl_[0] = 9; // must be <= 9 for lookahead assumptions - bd_[0] = 6; // must be <= 9 for lookahead assumptions - - t = table; - t = inftree.inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), blens, bl_, bd_, tl_, td_, hufts, z); - - if (t != Z_OK) { - if (t == Z_DATA_ERROR) { - blens = null; - mode = BADBLOCKS; - } - r = t; - - that.bitb = b; - that.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - that.write = q; - return that.inflate_flush(z, r); - } - codes.init(bl_[0], bd_[0], hufts, tl_[0], hufts, td_[0]); - // } - mode = CODES; - case CODES: - that.bitb = b; - that.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - that.write = q; - - if ((r = codes.proc(that, z, r)) != Z_STREAM_END) { - return that.inflate_flush(z, r); - } - r = Z_OK; - codes.free(z); - - p = z.next_in_index; - n = z.avail_in; - b = that.bitb; - k = that.bitk; - q = that.write; - m = /* (int) */(q < that.read ? that.read - q - 1 : that.end - q); - - if (last === 0) { - mode = TYPE; - break; - } - mode = DRY; - case DRY: - that.write = q; - r = that.inflate_flush(z, r); - q = that.write; - m = /* (int) */(q < that.read ? that.read - q - 1 : that.end - q); - if (that.read != that.write) { - that.bitb = b; - that.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - that.write = q; - return that.inflate_flush(z, r); - } - mode = DONELOCKS; - case DONELOCKS: - r = Z_STREAM_END; - - that.bitb = b; - that.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - that.write = q; - return that.inflate_flush(z, r); - case BADBLOCKS: - r = Z_DATA_ERROR; - - that.bitb = b; - that.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - that.write = q; - return that.inflate_flush(z, r); - - default: - r = Z_STREAM_ERROR; - - that.bitb = b; - that.bitk = k; - z.avail_in = n; - z.total_in += p - z.next_in_index; - z.next_in_index = p; - that.write = q; - return that.inflate_flush(z, r); - } - } - }; - - that.free = function(z) { - that.reset(z, null); - that.window = null; - hufts = null; - // ZFREE(z, s); - }; - - that.set_dictionary = function(d, start, n) { - that.window.set(d.subarray(start, start + n), 0); - that.read = that.write = n; - }; - - // Returns true if inflate is currently at the end of a block generated - // by Z_SYNC_FLUSH or Z_FULL_FLUSH. - that.sync_point = function() { - return mode == LENS ? 1 : 0; - }; - - } - - // Inflate - - // preset dictionary flag in zlib header - var PRESET_DICT = 0x20; - - var Z_DEFLATED = 8; - - var METHOD = 0; // waiting for method byte - var FLAG = 1; // waiting for flag byte - var DICT4 = 2; // four dictionary check bytes to go - var DICT3 = 3; // three dictionary check bytes to go - var DICT2 = 4; // two dictionary check bytes to go - var DICT1 = 5; // one dictionary check byte to go - var DICT0 = 6; // waiting for inflateSetDictionary - var BLOCKS = 7; // decompressing blocks - var DONE = 12; // finished check, done - var BAD = 13; // got an error--stay here - - var mark = [ 0, 0, 0xff, 0xff ]; - - function Inflate() { - var that = this; - - that.mode = 0; // current inflate mode - - // mode dependent information - that.method = 0; // if FLAGS, method byte - - // if CHECK, check values to compare - that.was = [ 0 ]; // new Array(1); // computed check value - that.need = 0; // stream check value - - // if BAD, inflateSync's marker bytes count - that.marker = 0; - - // mode independent information - that.wbits = 0; // log2(window size) (8..15, defaults to 15) - - // this.blocks; // current inflate_blocks state - - function inflateReset(z) { - if (!z || !z.istate) - return Z_STREAM_ERROR; - - z.total_in = z.total_out = 0; - z.msg = null; - z.istate.mode = BLOCKS; - z.istate.blocks.reset(z, null); - return Z_OK; - } - - that.inflateEnd = function(z) { - if (that.blocks) - that.blocks.free(z); - that.blocks = null; - // ZFREE(z, z->state); - return Z_OK; - }; - - that.inflateInit = function(z, w) { - z.msg = null; - that.blocks = null; - - // set window size - if (w < 8 || w > 15) { - that.inflateEnd(z); - return Z_STREAM_ERROR; - } - that.wbits = w; - - z.istate.blocks = new InfBlocks(z, 1 << w); - - // reset state - inflateReset(z); - return Z_OK; - }; - - that.inflate = function(z, f) { - var r; - var b; - - if (!z || !z.istate || !z.next_in) - return Z_STREAM_ERROR; - f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK; - r = Z_BUF_ERROR; - while (true) { - // System.out.println("mode: "+z.istate.mode); - switch (z.istate.mode) { - case METHOD: - - if (z.avail_in === 0) - return r; - r = f; - - z.avail_in--; - z.total_in++; - if (((z.istate.method = z.read_byte(z.next_in_index++)) & 0xf) != Z_DEFLATED) { - z.istate.mode = BAD; - z.msg = "unknown compression method"; - z.istate.marker = 5; // can't try inflateSync - break; - } - if ((z.istate.method >> 4) + 8 > z.istate.wbits) { - z.istate.mode = BAD; - z.msg = "invalid window size"; - z.istate.marker = 5; // can't try inflateSync - break; - } - z.istate.mode = FLAG; - case FLAG: - - if (z.avail_in === 0) - return r; - r = f; - - z.avail_in--; - z.total_in++; - b = (z.read_byte(z.next_in_index++)) & 0xff; - - if ((((z.istate.method << 8) + b) % 31) !== 0) { - z.istate.mode = BAD; - z.msg = "incorrect header check"; - z.istate.marker = 5; // can't try inflateSync - break; - } - - if ((b & PRESET_DICT) === 0) { - z.istate.mode = BLOCKS; - break; - } - z.istate.mode = DICT4; - case DICT4: - - if (z.avail_in === 0) - return r; - r = f; - - z.avail_in--; - z.total_in++; - z.istate.need = ((z.read_byte(z.next_in_index++) & 0xff) << 24) & 0xff000000; - z.istate.mode = DICT3; - case DICT3: - - if (z.avail_in === 0) - return r; - r = f; - - z.avail_in--; - z.total_in++; - z.istate.need += ((z.read_byte(z.next_in_index++) & 0xff) << 16) & 0xff0000; - z.istate.mode = DICT2; - case DICT2: - - if (z.avail_in === 0) - return r; - r = f; - - z.avail_in--; - z.total_in++; - z.istate.need += ((z.read_byte(z.next_in_index++) & 0xff) << 8) & 0xff00; - z.istate.mode = DICT1; - case DICT1: - - if (z.avail_in === 0) - return r; - r = f; - - z.avail_in--; - z.total_in++; - z.istate.need += (z.read_byte(z.next_in_index++) & 0xff); - z.istate.mode = DICT0; - return Z_NEED_DICT; - case DICT0: - z.istate.mode = BAD; - z.msg = "need dictionary"; - z.istate.marker = 0; // can try inflateSync - return Z_STREAM_ERROR; - case BLOCKS: - - r = z.istate.blocks.proc(z, r); - if (r == Z_DATA_ERROR) { - z.istate.mode = BAD; - z.istate.marker = 0; // can try inflateSync - break; - } - if (r == Z_OK) { - r = f; - } - if (r != Z_STREAM_END) { - return r; - } - r = f; - z.istate.blocks.reset(z, z.istate.was); - z.istate.mode = DONE; - case DONE: - return Z_STREAM_END; - case BAD: - return Z_DATA_ERROR; - default: - return Z_STREAM_ERROR; - } - } - }; - - that.inflateSetDictionary = function(z, dictionary, dictLength) { - var index = 0; - var length = dictLength; - if (!z || !z.istate || z.istate.mode != DICT0) - return Z_STREAM_ERROR; - - if (length >= (1 << z.istate.wbits)) { - length = (1 << z.istate.wbits) - 1; - index = dictLength - length; - } - z.istate.blocks.set_dictionary(dictionary, index, length); - z.istate.mode = BLOCKS; - return Z_OK; - }; - - that.inflateSync = function(z) { - var n; // number of bytes to look at - var p; // pointer to bytes - var m; // number of marker bytes found in a row - var r, w; // temporaries to save total_in and total_out - - // set up - if (!z || !z.istate) - return Z_STREAM_ERROR; - if (z.istate.mode != BAD) { - z.istate.mode = BAD; - z.istate.marker = 0; - } - if ((n = z.avail_in) === 0) - return Z_BUF_ERROR; - p = z.next_in_index; - m = z.istate.marker; - - // search - while (n !== 0 && m < 4) { - if (z.read_byte(p) == mark[m]) { - m++; - } else if (z.read_byte(p) !== 0) { - m = 0; - } else { - m = 4 - m; - } - p++; - n--; - } - - // restore - z.total_in += p - z.next_in_index; - z.next_in_index = p; - z.avail_in = n; - z.istate.marker = m; - - // return no joy or set up to restart on a new block - if (m != 4) { - return Z_DATA_ERROR; - } - r = z.total_in; - w = z.total_out; - inflateReset(z); - z.total_in = r; - z.total_out = w; - z.istate.mode = BLOCKS; - return Z_OK; - }; - - // Returns true if inflate is currently at the end of a block generated - // by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP - // implementation to provide an additional safety check. PPP uses - // Z_SYNC_FLUSH - // but removes the length bytes of the resulting empty stored block. When - // decompressing, PPP checks that at the end of input packet, inflate is - // waiting for these length bytes. - that.inflateSyncPoint = function(z) { - if (!z || !z.istate || !z.istate.blocks) - return Z_STREAM_ERROR; - return z.istate.blocks.sync_point(); - }; - } - - // ZStream - - function ZStream() { - } - - ZStream.prototype = { - inflateInit : function(bits) { - var that = this; - that.istate = new Inflate(); - if (!bits) - bits = MAX_BITS; - return that.istate.inflateInit(that, bits); - }, - - inflate : function(f) { - var that = this; - if (!that.istate) - return Z_STREAM_ERROR; - return that.istate.inflate(that, f); - }, - - inflateEnd : function() { - var that = this; - if (!that.istate) - return Z_STREAM_ERROR; - var ret = that.istate.inflateEnd(that); - that.istate = null; - return ret; - }, - - inflateSync : function() { - var that = this; - if (!that.istate) - return Z_STREAM_ERROR; - return that.istate.inflateSync(that); - }, - inflateSetDictionary : function(dictionary, dictLength) { - var that = this; - if (!that.istate) - return Z_STREAM_ERROR; - return that.istate.inflateSetDictionary(that, dictionary, dictLength); - }, - read_byte : function(start) { - var that = this; - return that.next_in.subarray(start, start + 1)[0]; - }, - read_buf : function(start, size) { - var that = this; - return that.next_in.subarray(start, start + size); - } - }; - - // Inflater - - function Inflater() { - var that = this; - var z = new ZStream(); - var bufsize = 512; - var flush = Z_NO_FLUSH; - var buf = new Uint8Array(bufsize); - var nomoreinput = false; - - z.inflateInit(); - z.next_out = buf; - - that.append = function(data, onprogress) { - var err, buffers = [], lastIndex = 0, bufferIndex = 0, bufferSize = 0, array; - if (data.length === 0) - return; - z.next_in_index = 0; - z.next_in = data; - z.avail_in = data.length; - do { - z.next_out_index = 0; - z.avail_out = bufsize; - if ((z.avail_in === 0) && (!nomoreinput)) { // if buffer is empty and more input is available, refill it - z.next_in_index = 0; - nomoreinput = true; - } - err = z.inflate(flush); - if (nomoreinput && (err == Z_BUF_ERROR)) - return -1; - if (err != Z_OK && err != Z_STREAM_END) - throw "inflating: " + z.msg; - if ((nomoreinput || err == Z_STREAM_END) && (z.avail_in == data.length)) - return -1; - if (z.next_out_index) - if (z.next_out_index == bufsize) - buffers.push(new Uint8Array(buf)); - else - buffers.push(new Uint8Array(buf.subarray(0, z.next_out_index))); - bufferSize += z.next_out_index; - if (onprogress && z.next_in_index > 0 && z.next_in_index != lastIndex) { - onprogress(z.next_in_index); - lastIndex = z.next_in_index; - } - } while (z.avail_in > 0 || z.avail_out === 0); - array = new Uint8Array(bufferSize); - buffers.forEach(function(chunk) { - array.set(chunk, bufferIndex); - bufferIndex += chunk.length; - }); - return array; - }; - that.flush = function() { - z.inflateEnd(); - }; - } - - var inflater; - - if (obj.zip) - obj.zip.Inflater = Inflater; - else { - inflater = new Inflater(); - obj.addEventListener("message", function(event) { - var message = event.data; - - if (message.append) - obj.postMessage({ - onappend : true, - data : inflater.append(message.data, function(current) { - obj.postMessage({ - progress : true, - current : current - }); - }) - }); - if (message.flush) { - inflater.flush(); - obj.postMessage({ - onflush : true - }); - } - }, false); - } - -}; - -// @agup -// Convert the inflate library to a blobURL -O.esri.TPK.___test = O.esri.TPK.inflate.toString(); - -O.esri.TPK.___blobURL = URL.createObjectURL( - new Blob([ - '(', - O.esri.TPK.___test, - ')(this)'], - {type: 'application/javascript'} - ) -) - -O.esri.zip.workerScriptsPath = O.esri.TPK.___blobURL; - +/*! offline-editor-js - v2.12.0 - 2015-08-07 +* Copyright (c) 2015 Environmental Systems Research Institute, Inc. +* Apache License*/ +/** + * Library for reading an ArcGIS Tile Package (.tpk) file and displaying the tiles + * as a map that can be used both online and offline. + * + * Note: you may have to rename your .tpk file to use .zip in order for it to be recognized. + * + * Author: Andy Gup + * Credits: Mansour Raad for his ArcGIS API for Flex TPKLayer, + * and Jon leighton for his super fast ArrayBuffer to Base64 convert. + */ +define([ + "dojo/_base/declare","esri/geometry/Extent","dojo/query","esri/SpatialReference", + "esri/layers/TileInfo","esri/layers/TiledMapServiceLayer", + "dojo/Deferred","dojo/promise/all","dojo/Evented"], + function(declare,Extent,query,SpatialReference,TileInfo,TiledMapServiceLayer, + Deferred,all,Evented){ + return declare("O.esri.TPK.TPKLayer",[TiledMapServiceLayer,Evented],{ + + // + // Public Properties + // + map: null, + store: null, // Reference to the local database store and hooks to it's functionality + MAX_DB_SIZE: 75, // Recommended maximum size in MBs + TILE_PATH:"", // The absolute path to the root of bundle/bundleX files e.g. V101/YOSEMITE_MAP/ + RECENTER_DELAY: 350, // Millisecond delay before attempting to recent map after an orientation change + PARSING_ERROR: "parsingError", // An error was encountered while parsing a TPK file. + DB_INIT_ERROR: "dbInitError", // An error occurred while initializing the database. + DB_FULL_ERROR: "dbFullError", // No space left in the database. + NO_SUPPORT_ERROR: "libNotSupportedError", // Error indicating this library is not supported in a particular browser. + PROGRESS_START: "start", + PROGRESS_END: "end", + WINDOW_VALIDATED: "windowValidated", // All window functionality checks have passed + DB_VALIDATED: "dbValidated", // All database functionality checks have passed + + // + // Events + // + DATABASE_ERROR_EVENT: "databaseErrorEvent", // An error thrown by the database. + VALIDATION_EVENT: "validationEvent", // Library validation checks. + PROGRESS_EVENT: "progress", // Event dispatched while parsing a bundle file. + + // + // Private properties + // + _maxDBSize: 75, // User configurable maximum size in MBs. + _isDBWriteable: true, // Manually allow or stop writing to the database. + _isDBValid: false, // Does the browser support IndexedDB or IndexedDBShim + _autoCenter: null, // Auto center the map + _fileEntriesLength: 0, // Number of files in zip + _inMemTilesObject: null, // Stores unzipped files from tpk + _inMemTilesObjectLength: 0, + _zeroLengthFileCounter: 0, // For counting the number of zero length files in the tpk (e.g. directories) + + constructor:function(){ + this._self = this; + this._inMemTilesIndex = []; + this._inMemTilesObject = {}; + this.store = new O.esri.Tiles.TilesStore(); + this._validate(); + }, + + extend: function(files){ + this._fileEntriesLength = files.length; + this.emit(this.PROGRESS_EVENT,this.PROGRESS_START); + + this._parseInMemFiles(files,function (){ + //Parse conf.xml and conf.cdi to get the required setup info + this._parseConfCdi(function(initExtent){ + this.initialExtent = (this.fullExtent = initExtent); + this._parseConfXml(function(result){ + this.tileInfo = new TileInfo(result); + this.spatialReference = new SpatialReference({wkid:this.tileInfo.spatialReference.wkid}); + this.loaded = true; + this.onLoad(this); + this.emit(this.PROGRESS_EVENT,this.PROGRESS_END); + }.bind(this._self)); + }.bind(this._self)); + }.bind(this._self)); + }, + + /** + * Overrides getTileUrl method + * @param level + * @param row + * @param col + * @returns {string} + */ + getTileUrl:function(level,row,col){ + this.emit(this.PROGRESS_EVENT,this.PROGRESS_START); + var layersDir = this._self.TILE_PATH + "_alllayers"; + var url = this._getCacheFilePath(layersDir,level,row,col); + + if(this._inMemTilesObject != {}) { + /* temporary URL returned immediately, as we haven't retrieved the image from the indexeddb yet */ + var tileid = "void:/" + level + "/" + row + "/" + col; + + if(this.map == null) { + this.map = this.getMap(); + } + if(this._autoCenter == null) { + this._autoCenter = new O.esri.TPK.autoCenterMap(this.map,this.RECENTER_DELAY); + this._autoCenter.init(); + } + + this._getInMemTiles(url,layersDir, level, row, col,tileid,function (result,tileid,url) { + var img = query("img[src=" + tileid + "]")[0]; + if (typeof img == "undefined") { + img = new Image(); + } //create a blank place holder for undefined images + var imgURL; + + if (result) { + console.log("found tile offline", url); + var png = "data:image/png;base64,"; + switch(this.tileInfo.format) { + case "JPEG": + imgURL = "data:image/jpg;base64," + result; + break; + case "PNG": + imgURL = png + result; + break; + case "PNG8": + imgURL = png + result; + break; + case "PNG24": + imgURL = png + result; + break; + case "PNG32": + imgURL = png + result; + break; + default: + imgURL = "data:image/jpg;base64," + result; + + } + img.style.borderColor = "blue"; + } + else { + img.style.borderColor = "green"; + console.log("tile is not in the offline store", url); + imgURL = "data:image/png;base64,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pmk0TROPj48Hn3l4eIimaSJN06O3A4NJwDMxm82ibdtXo4D5fB6r1Sp+//4dz8/Pw5H+6ekpdrtdJEkS8/n8S/9f713ie3vaceo9x557QAB451Sgfyin34HKshweunk5HzAej2MymXz5+f9nbjJyI9L39Wu5XP55+XQZ39uxR4Z3u90wSXjqEV0wAjhjx47oaZq63Me/ZhIQBAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEAAbAJQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEAvqe/BwCeKjUweoA8pQAAAABJRU5ErkJggg=="; + } + // when we return a nonexistent url to the image, the TiledMapServiceLayer::_tileErrorHandler() method + // sets img visibility to 'hidden', so we need to show the image back once we have put the data:image + img.style.visibility = "visible"; + img.src = imgURL; + console.log("URL length " + imgURL.length + ", image: " + imgURL); + this.emit(this.PROGRESS_EVENT,this.PROGRESS_END); + return ""; + /* this result goes nowhere, seriously */ + }.bind(this._self)); + + return tileid; + } + }, + + /** + * Optional. Set the maximum database size. Recommended maximum for mobile devices is 100MBs. + * Making the database too large can result in browser crashes and slow performance. + * TPKs can contain a lot of data! + * @param size + */ + setMaxDBSize: function(size){ + //Make sure the entry is an integer. + var testRegex = /^\d+$/; + if(testRegex.test(size) && size <= this.MAX_DB_SIZE){ + this._maxDBSize = size; + } + else{ + console.log("setMaxDBSize Error: invalid entry. Integers only and less than " + this.MAX_DB_SIZE + "MBs"); + } + }, + + /** + * Returns the size of the tiles database. + * @param callback {size , error}. Note, size is in bytes. + */ + getDBSize: function(callback){ + this.store.usedSpace(function(size,err){ + callback(size,err); + }.bind(this)); + }, + + /** + * Sets whether or not tiles can be written to the database. This function + * can help you manage the size of the tiles database. + * Use this in conjunction with getDBSize() on a map pan or zoom event listener. + * @param value + */ + setDBWriteable: function(/* Boolean */ value){ + this._isDBWriteable = value; + }, + + /** + * Validates whether or not the browser supports this library + * @returns {boolean} + */ + isDBValid: function(){ + this._validate(); + return this._isDBValid; + }, + + /** + * Reads a tile into tile database. Works with offlineTilesEnabler.js and OfflineTilesEnablerLayer.js + * saveToFile() functionality. + * IMPORTANT! The tile must confirm to an object using the pattern shown in _storeTile(). + * @param file + * @param callback callback( boolean, error) + */ + loadFromURL: function (tile, callback) // callback(success,msg) + { + if (this.isDBValid()) { + this.store.store(tile, function (success,err) { + //Check the result + if (success) { + console.log("loadFromURL() success."); + callback(true, ""); + } + else { + console.log("loadFromURL() Failed."); + callback(false, err); + } + }); + } + else { + callback(false, "not supported"); + } + }, + + /** + * Runs specific validation tasks. Reserved for future use. + * Currently only throws console errors. Does not stop execution of the library! + * @private + */ + _validate: function(){ + //Verify if basic functionality is supported by the browser + if(!window.File && !window.FileReader && !window.Blob && !window.btoa && !window.DataView){ + console.log("TPKLayer library is not supported by this browser"); + this.emit(this.VALIDATION_EVENT,{msg:this.NO_SUPPORT_ERROR, err : null}); + } + else{ + this.emit(this.VALIDATION_EVENT,{msg:this.WINDOW_VALIDATED, err : null}); + } + + //Verify if IndexedDB is supported and initializes properly + if( /*false &&*/ this.store.isSupported() ) + { + this.store.init(function(result){ + if(result === false){ + console.log("There was an error initializing the TPKLayer database"); + this.emit(this.DATABASE_ERROR_EVENT,{msg:this.DB_INIT_ERROR, err: null}); + } + else{ + this.store.usedSpace(function(size,err){ + var mb = this._bytes2MBs(size.sizeBytes); + if(mb > this.MAX_DB_SIZE){ + console.log("Database is full!"); + this.emit(this.DATABASE_ERROR_EVENT,{msg:this.DB_FULL_ERROR,err : err}); + } + this.emit(this.VALIDATION_EVENT,{msg:this.DB_VALIDATED,err : null}); + console.log("DB size: " + mb + " MBs, Tile count: " + size.tileCount + ", Error: " + err); + this._isDBValid = true; + }.bind(this)); + } + }.bind(this)); + } + else + { + console.log("IndexedDB is not supported on your browser."); + this.emit(this.VALIDATION_EVENT,{msg:this.NO_SUPPORT_ERROR, err : null}); + } + }, + + /** + * Function for pulling out individual files from the .tpk/zip and storing + * them in memory. + * @param files + * @param callback + * @private + */ + _parseInMemFiles: function(files,callback){ + + var inMemTilesLength = this._fileEntriesLength; + this._zeroLengthFileCounter = 0; + var promises = []; + + for(var i=0;i < inMemTilesLength;i++){ + + var deferred = new Deferred(); + var name = files[i].filename.toLocaleUpperCase(); + + var index = name.indexOf("_ALLLAYERS",0); + if(index != -1){ + this.TILE_PATH = name.slice(0,index); + } + + if(files[i].compressedSize === 0) { + this._zeroLengthFileCounter++; + } + + var indexCDI = name.indexOf("CONF.CDI",0); + var indexXML = name.indexOf("CONF.XML",0); + var indexBUNDLE = name.indexOf("BUNDLE",0); + var indexBUNDLX = name.indexOf("BUNDLX",0); + + if(indexCDI != -1 || indexXML != -1){ + this._unzipConfFiles(files,i,deferred,function(/* deferred */ d, /* token */ t){ console.log("CONF FILE"); + d.resolve(t); + }); + } + else if(indexBUNDLE != -1 || indexBUNDLX != -1){ + this._unzipTileFiles(files,i,deferred,function(/* deferred */ d, /* token */ t){ + d.resolve(t); + }); + } + else{ + deferred.resolve(i); + } + promises.push(deferred); + } + + all(promises).then( function(results) + { + callback && callback(results); // jshint ignore:line + }); + }, + + /** + * Calculate the size of an Object based on whether or not the item is enumerable. + * Native Objects don't have a built in size property. + * More info: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty + * @param obj + * @returns {number} + * @constructor + */ + ObjectSize: function(obj) { + var size = 0, key; + for (key in obj) { + if (obj.hasOwnProperty(key)) { + size++; + } + } + return size; + }, + + /** + * Retrieve XML config files + * @param files + * @param token + * @param callback + * @private + */ + _unzipConfFiles: function(files,token,deferred,callback){ + files[token].getData(new O.esri.zip.TextWriter(token),function(data){ + this._inMemTilesIndex.push("blank"); + var name = files[data.token].filename.toLocaleUpperCase(); + this._inMemTilesObject[name]= data.string; + var size = this.ObjectSize(this._inMemTilesObject); + if(size > 0){ + callback(deferred,data.token); + } + }.bind(this)); + }, + + /** + * Retrieve binary tile files as ArrayBuffers + * @param files + * @param token + * @param callback + * @private + */ + _unzipTileFiles: function(files,token,deferred,callback){ + var that = this; + files[token].getData(new O.esri.zip.BlobWriter(token),function(data){ + if(data.size !== 0){ + var reader = new FileReader(); + reader.token = data.token; + reader.onerror = function (event) { + console.error("_unzipTileFiles Error: " + event.target.error.message); + that.emit(that.PARSING_ERROR, {msg: "Error parsing file: ", err: event.target.error}); + }; + reader.onloadend = function(evt) { + if(reader.token !== undefined){ + that._inMemTilesIndex.push("blank"); + var name = files[reader.token].filename.toLocaleUpperCase(); + that._inMemTilesObject[name]= reader.result; + var size = that.ObjectSize(that._inMemTilesObject); + if(size > 0){ + callback(deferred,data.token); + } + } + }; + reader.readAsArrayBuffer(data); //open bundleX + } + }); + }, + + /** + * Parse conf.cdi + * @param callback + * @private + */ + _parseConfCdi: function(callback){ + var m_conf_i = this._inMemTilesObject[this.TILE_PATH + "CONF.CDI"]; + + var x2js = new O.esri.TPK.X2JS(); + + var jsonObj = x2js.xml_str2json( m_conf_i ); + var envelopeInfo = jsonObj.EnvelopeN; + var xmin = parseFloat(envelopeInfo.XMin); + var ymin = parseFloat(envelopeInfo.YMin); + var xmax = parseFloat(envelopeInfo.XMax); + var ymax = parseFloat(envelopeInfo.YMax); + var sr = parseInt(envelopeInfo.SpatialReference.WKID); + + var initExtent = new Extent( + xmin,ymin,xmax,ymax, new SpatialReference({wkid:sr}) + ); + + callback(initExtent); + }, + + /** + * Parse conf.xml + * @param callback + * @private + */ + _parseConfXml:function(callback) { + var m_conf = this._inMemTilesObject[this.TILE_PATH + "CONF.XML"]; + + var x2js = new O.esri.TPK.X2JS(); + + var jsonObj = x2js.xml_str2json(m_conf); + var cacheInfo = jsonObj.CacheInfo; + var tileInfo = {}; + tileInfo.rows = parseInt(cacheInfo.TileCacheInfo.TileRows); + tileInfo.cols = parseInt(cacheInfo.TileCacheInfo.TileCols); + tileInfo.dpi = parseInt(cacheInfo.TileCacheInfo.DPI); + tileInfo.format = cacheInfo.TileImageInfo.CacheTileFormat; + tileInfo.compressionQuality = parseInt(cacheInfo.TileImageInfo.CompressionQuality); + tileInfo.origin = { + x: parseInt(cacheInfo.TileCacheInfo.TileOrigin.X), + y: parseInt(cacheInfo.TileCacheInfo.TileOrigin.Y) + }; + tileInfo.spatialReference = { + "wkid": parseInt(cacheInfo.TileCacheInfo.SpatialReference.WKID) + }; + + var lods = cacheInfo.TileCacheInfo.LODInfos.LODInfo; + var finalLods = []; + for (var i = 0; i < lods.length; i++) { + finalLods.push({ + "level": parseFloat(lods[i].LevelID), + "resolution": parseFloat(lods[i].Resolution), + "scale": parseFloat(lods[i].Scale)}); + } + + tileInfo.lods = finalLods; + callback(tileInfo); + }, + + /** + * Parses the in-memory tile cache and returns a base64 tile image + * @param layersDir + * @param level + * @param row + * @param col + * @param tileCount - number of tiles in the Extent + * @param tiledId - id of the associated tile being passed + * @param callback + * @private + */ + _getInMemTiles: function(url,layersDir,level,row,col,tileId,callback){ + + var that = this._self; + var db = this.store; + + //First check in the database if the tile exists. + //If not then we store the tile in the database later. + this.store.retrieve(url, function(success, offlineTile){ + if( success ) + { + console.log("Tile found in storage: " + url); + callback(offlineTile.img,tileId,url); + } + else { + console.log("Tile is not in storage: " + url); + var snappedRow = Math.floor(row / 128) * 128; + var snappedCol = Math.floor(col / 128) * 128; + + var path = this._getCacheFilePath(layersDir, level, snappedRow, snappedCol).toLocaleUpperCase(); + + var offset; + var bundleIndex = path + ".BUNDLE"; + var bufferI = this._inMemTilesObject[bundleIndex]; + var bufferX = this._inMemTilesObject[path + ".BUNDLX"]; + + if(bufferI !== undefined || bufferX !== undefined) { + offset = this._getOffset(level, row, col, snappedRow, snappedCol); + var pointer = that._getPointer(bufferX, offset); + + that._buffer2Base64(bufferI,pointer,function(result){ + if (that._isDBWriteable) { + that._storeTile(url, result, db,function(success,err){ + if(err){ + console.log("TPKLayer - Error writing to database." + err.message); + that.emit(that.DATABASE_ERROR_EVENT,{msg:"Error writing to database. ", err : err}); + } + }); + } + callback(result,tileId, url); + }.bind(that)); + } + else{ + console.log("_getInMemTiles Error: Invalid values"); + callback(null,tileId,url); + } + } + }.bind(that)); + }, + + /** + * Stores a tile in the local database. + * @param url + * @param base64Str + * @param db + * @param callback + * @private + */ + _storeTile: function(url,base64Str,db,callback){ + var tile = { + url: url, + img: base64Str + }; + + db.store(tile,function(success,err){ + callback(success,err); + }); + }, + + /** + * Returns a pointer for reading a BUNDLE binary file as based on the given offset. + * @param buffer + * @param offset + * @returns {Uint8} + * @private + */ + _getPointer: function(/* ArrayBuffer */ buffer,offset){ + var snip = buffer.slice(offset); + var dv = new DataView(snip,0,5); + + var nume1 = dv.getUint8(0,true); + var nume2 = dv.getUint8(1,true); + var nume3 = dv.getUint8(2,true); + var nume4 = dv.getUint8(3,true); + var nume5 = dv.getUint8(4,true); + + var value = nume5; + value = value * 256 + nume4; + value = value * 256 + nume3; + value = value * 256 + nume2; + value = value * 256 + nume1; + + return value; + }, + + /** + * Convert an ArrayBuffer to base64. My testing shows this to be + * much faster than combining Blobs and btoa(). + * ALL CREDITS: https://gist.github.com/jonleighton/958841 + * NO licensing listed at the gist repo. + * @param arrayBuffer + * @returns {string} + * @private + */ + _base64ArrayBuffer: function(arrayBuffer) { + var base64 = ""; + var encodings = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + var bytes = new Uint8Array(arrayBuffer); + var byteLength = bytes.byteLength; + var byteRemainder = byteLength % 3; + var mainLength = byteLength - byteRemainder; + + var a, b, c, d; + var chunk; + + /*jslint bitwise: true */ + + // Main loop deals with bytes in chunks of 3 + for (var i = 0; i < mainLength; i = i + 3) { + // Combine the three bytes into a single integer + chunk = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2]; + + // Use bitmasks to extract 6-bit segments from the triplet + a = (chunk & 16515072) >> 18; // 16515072 = (2^6 - 1) << 18 + b = (chunk & 258048) >> 12; // 258048 = (2^6 - 1) << 12 + c = (chunk & 4032) >> 6; // 4032 = (2^6 - 1) << 6 + d = chunk & 63; // 63 = 2^6 - 1 + + // Convert the raw binary segments to the appropriate ASCII encoding + base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d]; + } + + // Deal with the remaining bytes and padding + if (byteRemainder == 1) { + chunk = bytes[mainLength]; + + a = (chunk & 252) >> 2; // 252 = (2^6 - 1) << 2 + + // Set the 4 least significant bits to zero + b = (chunk & 3) << 4; // 3 = 2^2 - 1 + + base64 += encodings[a] + encodings[b] + "=="; + } else if (byteRemainder == 2) { + chunk = (bytes[mainLength] << 8) | bytes[mainLength + 1]; + + a = (chunk & 64512) >> 10; // 64512 = (2^6 - 1) << 10 + b = (chunk & 1008) >> 4; // 1008 = (2^6 - 1) << 4 + + // Set the 2 least significant bits to zero + c = (chunk & 15) << 2; // 15 = 2^4 - 1 + + base64 += encodings[a] + encodings[b] + encodings[c] + "="; + } + + /*jslint bitwise: false */ + + return base64; + }, + + /** + * Given a ArrayBuffer and a position it will return a Base64 tile image + * @param arrayBuffer + * @param position + * @returns {string} + * @private + */ + _buffer2Base64: function(/* ArrayBuffer */arrayBuffer,/* int */ position,callback){ + var view = new DataView(arrayBuffer,position); + var chunk = view.getInt32(0,true); + var buffer = view.buffer.slice(position + 4,position + 4 + chunk); + var string = this._base64ArrayBuffer(buffer); + callback(string); + }, + + /** + * Converts an integer to hex + * @param value + * @returns {string} + * @private + */ + _int2HexString: function(/* int */ value){ + var text = value.toString(16).toUpperCase(); + if (text.length === 1) + { + return "000" + text; + } + if (text.length === 2) + { + return "00" + text; + } + if (text.length === 3) + { + return "0" + text; + } + return text.substr(0, text.length); + }, + + /** + * Determines where to start reading a BUNDLEX binary file + * @param level + * @param row + * @param col + * @param startRow + * @param startCol + * @returns {number} + * @private + */ + _getOffset: function(/* int */level, /* number */row,/* number */col, /* number */startRow, /* number */ startCol){ + var recordNumber = 128 * (col - startCol) + (row - startRow); + return 16 + recordNumber * 5; + }, + + /** + * Returns a hexadecimal representation of a cache file path + * @param layerDir + * @param level + * @param row + * @param col + * @returns {string} + * @private + */ + _getCacheFilePath: function(/* String */ layerDir, /* int */level, /* int */row, /* int */ col){ + var arr = []; + + arr.push(layerDir); + arr.push("/"); + arr.push("L"); + arr.push(level < 10 ? "0" + level : level); + arr.push("/"); + arr.push("R"); + arr.push(this._int2HexString(row)); + arr.push("C"); + arr.push(this._int2HexString(col)); + + return arr.join(""); + }, + + /** + * Returns database size in MBs. + * @returns {string} + * @private + */ + _bytes2MBs: function(bytes){ + return (bytes >>> 20 ) + '.' + ( bytes & (2*0x3FF ) ); // jshint ignore:line + } + }); + } +); +/** + * Creates a namespace for the non-AMD libraries in this directory + */ + + +if(typeof O != "undefined"){ + O.esri.TPK = {}; +} +else{ + O = {}; // jshint ignore:line + O.esri = { + TPK: {}, + Tiles: {} + }; +} + +//"use strict"; + + +/*global indexedDB */ +/** + * Library for handling the storing of map tiles in IndexedDB. + * + * Author: Andy Gup (@agup) + * Contributor: Javier Abadia (@javierabadia) + */ + +O.esri.Tiles.TilesStore = function(){ + /** + * Internal reference to the local database + * @type {null} + * @private + */ + this._db = null; + + this.dbName = "offline_tile_store"; + this.objectStoreName = "tilepath"; + + /** + * Determines if indexedDB is supported + * @returns {boolean} + */ + this.isSupported = function(){ + + if(!window.indexedDB && !window.openDatabase){ + return false; + } + + return true; + }; + + /** + * Adds an object to the database + * @param urlDataPair + * @param callback callback(boolean, err) + */ + this.store = function(urlDataPair,callback) + { + try + { + var transaction = this._db.transaction([this.objectStoreName],"readwrite"); + + transaction.oncomplete = function() + { + callback(true); + }; + + transaction.onerror = function(event) + { + callback(false,event.target.error.message); + }; + + var objectStore = transaction.objectStore(this.objectStoreName); + var request = objectStore.put(urlDataPair); + request.onsuccess = function() + { + //console.log("item added to db " + event.target.result); + }; + } + catch(err) + { + console.log("TilesStore: " + err.stack); + callback(false, err.stack); + } + }; + + /** + * Retrieve a record. + * @param url + * @param callback + */ + this.retrieve = function(/* String */ url,callback) + { + if(this._db !== null) + { + var objectStore = this._db.transaction([this.objectStoreName]).objectStore(this.objectStoreName); + var request = objectStore.get(url); + request.onsuccess = function(event) + { + var result = event.target.result; + if(result === undefined) + { + callback(false,"not found"); + } + else + { + callback(true,result); + } + }; + request.onerror = function(err) + { + console.log(err); + callback(false, err); + }; + } + }; + + /** + * Deletes entire database + * @param callback callback(boolean, err) + */ + this.deleteAll = function(callback) + { + if(this._db !== null) + { + var request = this._db.transaction([this.objectStoreName],"readwrite") + .objectStore(this.objectStoreName) + .clear(); + request.onsuccess = function() + { + callback(true); + }; + request.onerror = function(err) + { + callback(false, err); + }; + } + else + { + callback(false,null); + } + }; + + /** + * Delete an individual entry + * @param url + * @param callback callback(boolean, err) + */ + this.delete = function(/* String */ url,callback) + { + if(this._db !== null) + { + var request = this._db.transaction([this.objectStoreName],"readwrite") + .objectStore(this.objectStoreName) + .delete(url); + request.onsuccess = function() + { + callback(true); + }; + request.onerror = function(err) + { + callback(false, err); + }; + } + else + { + callback(false,null); + } + }; + + /** + * Retrieve all tiles from indexeddb + * @param callback callback(url, img, err) + */ + this.getAllTiles = function(callback) + { + if(this._db !== null){ + var transaction = this._db.transaction([this.objectStoreName]) + .objectStore(this.objectStoreName) + .openCursor(); + + transaction.onsuccess = function(event) + { + var cursor = event.target.result; + if(cursor){ + var url = cursor.value.url; + var img = cursor.value.img; + callback(url,img,null); + cursor.continue(); + } + else + { + callback(null, null, "end"); + } + }.bind(this); + transaction.onerror = function(err) + { + callback(null, null, err); + }; + } + else + { + callback(null, null, "no db"); + } + }; + + /** + * Provides the size of database in bytes + * @param callback callback(size, null) or callback(null, error) + */ + this.usedSpace = function(callback){ + if(this._db !== null){ + var usage = { sizeBytes: 0, tileCount: 0 }; + + var transaction = this._db.transaction([this.objectStoreName]) + .objectStore(this.objectStoreName) + .openCursor(); + + transaction.onsuccess = function(event){ + var cursor = event.target.result; + if(cursor){ + var storedObject = cursor.value; + var json = JSON.stringify(storedObject); + usage.sizeBytes += this._stringBytes(json); + usage.tileCount += 1; + cursor.continue(); + } + else + { + callback(usage,null); + } + }.bind(this); + transaction.onerror = function(err) + { + callback(null, err); + }; + } + else + { + callback(null,null); + } + }; + + this._stringBytes = function(str) { + return str.length /**2*/ ; + }; + + this.init = function(callback) + { + var request = indexedDB.open(this.dbName, 4); + callback = callback || function(success) { console.log("TilesStore::init() success:", success); }.bind(this); + + request.onerror = function(event) + { + console.log("indexedDB error: " + event.target.errorCode); + callback(false,event.target.errorCode); + }.bind(this); + + request.onupgradeneeded = function(event) + { + var db = event.target.result; + + if( db.objectStoreNames.contains(this.objectStoreName)) + { + db.deleteObjectStore(this.objectStoreName); + } + + db.createObjectStore(this.objectStoreName, { keyPath: "url" }); + }.bind(this); + + request.onsuccess = function(event) + { + this._db = event.target.result; + console.log("database opened successfully"); + callback(true); + }.bind(this); + }; +}; + + +//https://github.com/gildas-lormeau/zip.js/blob/master/WebContent/zip.js +/* + Copyright (c) 2013 Gildas Lormeau. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function(obj) { + + var ERR_BAD_FORMAT = "File format is not recognized."; + var ERR_ENCRYPTED = "File contains encrypted entry."; + var ERR_ZIP64 = "File is using Zip64 (4gb+ file size)."; + var ERR_READ = "Error while reading zip file."; + var ERR_WRITE = "Error while writing zip file."; + var ERR_WRITE_DATA = "Error while writing file data."; + var ERR_READ_DATA = "Error while reading file data."; + var ERR_DUPLICATED_NAME = "File already exists."; + var CHUNK_SIZE = 512 * 1024; + + var INFLATE_JS = ""; //left blank intentionally! Modified by @agup + var DEFLATE_JS = "deflate.js"; + + var TEXT_PLAIN = "text/plain"; + + var MESSAGE_EVENT = "message"; + + var appendABViewSupported; + try { + appendABViewSupported = new Blob([ new DataView(new ArrayBuffer(0)) ]).size === 0; + } catch (e) { + } + + function Crc32() { + var crc = -1, that = this; + that.append = function(data) { + var offset, table = that.table; + for (offset = 0; offset < data.length; offset++) + crc = (crc >>> 8) ^ table[(crc ^ data[offset]) & 0xFF]; + }; + that.get = function() { + return ~crc; + }; + } + Crc32.prototype.table = (function() { + var i, j, t, table = []; + for (i = 0; i < 256; i++) { + t = i; + for (j = 0; j < 8; j++) + if (t & 1) + t = (t >>> 1) ^ 0xEDB88320; + else + t = t >>> 1; + table[i] = t; + } + return table; + })(); + + function blobSlice(blob, index, length) { + if (blob.slice) + return blob.slice(index, index + length); + else if (blob.webkitSlice) + return blob.webkitSlice(index, index + length); + else if (blob.mozSlice) + return blob.mozSlice(index, index + length); + else if (blob.msSlice) + return blob.msSlice(index, index + length); + } + + function getDataHelper(byteLength, bytes) { + var dataBuffer, dataArray; + dataBuffer = new ArrayBuffer(byteLength); + dataArray = new Uint8Array(dataBuffer); + if (bytes) + dataArray.set(bytes, 0); + return { + buffer : dataBuffer, + array : dataArray, + view : new DataView(dataBuffer) + }; + } + + // Readers + function Reader() { + } + + function TextReader(text) { + var that = this, blobReader; + + function init(callback, onerror) { + var blob = new Blob([ text ], { + type : TEXT_PLAIN + }); + blobReader = new BlobReader(blob); + blobReader.init(function() { + that.size = blobReader.size; + callback(); + }, onerror); + } + + function readUint8Array(index, length, callback, onerror) { + blobReader.readUint8Array(index, length, callback, onerror); + } + + that.size = 0; + that.init = init; + that.readUint8Array = readUint8Array; + } + TextReader.prototype = new Reader(); + TextReader.prototype.constructor = TextReader; + + function Data64URIReader(dataURI) { + var that = this, dataStart; + + function init(callback) { + var dataEnd = dataURI.length; + while (dataURI.charAt(dataEnd - 1) == "=") + dataEnd--; + dataStart = dataURI.indexOf(",") + 1; + that.size = Math.floor((dataEnd - dataStart) * 0.75); + callback(); + } + + function readUint8Array(index, length, callback) { + var i, data = getDataHelper(length); + var start = Math.floor(index / 3) * 4; + var end = Math.ceil((index + length) / 3) * 4; + var bytes = obj.atob(dataURI.substring(start + dataStart, end + dataStart)); + var delta = index - Math.floor(start / 4) * 3; + for (i = delta; i < delta + length; i++) + data.array[i - delta] = bytes.charCodeAt(i); + callback(data.array); + } + + that.size = 0; + that.init = init; + that.readUint8Array = readUint8Array; + } + Data64URIReader.prototype = new Reader(); + Data64URIReader.prototype.constructor = Data64URIReader; + + function BlobReader(blob) { + var that = this; + + function init(callback) { + this.size = blob.size; + callback(); + } + + function readUint8Array(index, length, callback, onerror) { + var reader = new FileReader(); + reader.onload = function(e) { + callback(new Uint8Array(e.target.result)); + }; + reader.onerror = onerror; + reader.readAsArrayBuffer(blobSlice(blob, index, length)); + } + + that.size = 0; + that.init = init; + that.readUint8Array = readUint8Array; + } + BlobReader.prototype = new Reader(); + BlobReader.prototype.constructor = BlobReader; + + // Writers + + function Writer() { + } + Writer.prototype.getData = function(callback) { + callback(this.data); + }; + + //Added by Andy G. Tracking token + function TextWriter(token,encoding) { + var that = this, blob; + + function init(callback) { + blob = new Blob([], { + type: TEXT_PLAIN + }); + callback(); + } + + function writeUint8Array(array, callback) { + blob = new Blob([ blob, appendABViewSupported ? array : array.buffer ], { + type: TEXT_PLAIN + }); + callback(); + } + + function getData(callback, onerror) { + var reader = new FileReader(); + reader.onload = function (e) { + var obj = {string: e.target.result,token:token}; + callback(obj); + }; + reader.onerror = onerror; + reader.readAsText(blob, encoding); + } + + that.init = init; + that.writeUint8Array = writeUint8Array; + that.getData = getData; + } + TextWriter.prototype = new Writer(); + TextWriter.prototype.constructor = TextWriter; + + function Data64URIWriter(contentType) { + var that = this, data = "", pending = ""; + + function init(callback) { + data += "data:" + (contentType || "") + ";base64,"; + callback(); + } + + function writeUint8Array(array, callback) { + var i, delta = pending.length, dataString = pending; + pending = ""; + for (i = 0; i < (Math.floor((delta + array.length) / 3) * 3) - delta; i++) + dataString += String.fromCharCode(array[i]); + for (; i < array.length; i++) + pending += String.fromCharCode(array[i]); + if (dataString.length > 2) + data += obj.btoa(dataString); + else + pending = dataString; + callback(); + } + + function getData(callback) { + callback(data + obj.btoa(pending)); + } + + that.init = init; + that.writeUint8Array = writeUint8Array; + that.getData = getData; + } + Data64URIWriter.prototype = new Writer(); + Data64URIWriter.prototype.constructor = Data64URIWriter; + + //Added by Andy G. Tracking token + function BlobWriter(token,contentType) { + var blob, that = this ; + + function init(callback) { + blob = new Blob([], { + type: contentType + }); + callback(); + } + + function writeUint8Array(array, callback) { + blob = new Blob([ blob, appendABViewSupported ? array : array.buffer ], { + type: contentType + }); + blob.token = token; + callback(); + } + + function getData(callback) { + callback(blob); + } + + that.init = init; + that.writeUint8Array = writeUint8Array; + that.getData = getData; + } + BlobWriter.prototype = new Writer(); + BlobWriter.prototype.constructor = BlobWriter; + + // inflate/deflate core functions + + function launchWorkerProcess(worker, reader, writer, offset, size, onappend, onprogress, onend, onreaderror, onwriteerror) { + var chunkIndex = 0, index, outputSize; + + function onflush() { + worker.removeEventListener(MESSAGE_EVENT, onmessage, false); + onend(outputSize); + } + + function onmessage(event) { + var message = event.data, data = message.data; + + if (message.onappend) { + outputSize += data.length; + writer.writeUint8Array(data, function() { + onappend(false, data); + step(); + }, onwriteerror); + } + if (message.onflush) + if (data) { + outputSize += data.length; + writer.writeUint8Array(data, function() { + onappend(false, data); + onflush(); + }, onwriteerror); + } else + onflush(); + if (message.progress && onprogress) + onprogress(index + message.current, size); + } + + function step() { + index = chunkIndex * CHUNK_SIZE; + if (index < size) + reader.readUint8Array(offset + index, Math.min(CHUNK_SIZE, size - index), function(array) { + worker.postMessage({ + append : true, + data : array + }); + chunkIndex++; + if (onprogress) + onprogress(index, size); + onappend(true, array); + }, onreaderror); + else + worker.postMessage({ + flush : true + }); + } + + outputSize = 0; + worker.addEventListener(MESSAGE_EVENT, onmessage, false); + step(); + } + + function launchProcess(process, reader, writer, offset, size, onappend, onprogress, onend, onreaderror, onwriteerror) { + var chunkIndex = 0, index, outputSize = 0; + + function step() { + var outputData; + index = chunkIndex * CHUNK_SIZE; + if (index < size) + reader.readUint8Array(offset + index, Math.min(CHUNK_SIZE, size - index), function(inputData) { + var outputData = process.append(inputData, function() { + if (onprogress) + onprogress(offset + index, size); + }); + outputSize += outputData.length; + onappend(true, inputData); + writer.writeUint8Array(outputData, function() { + onappend(false, outputData); + chunkIndex++; + setTimeout(step, 1); + }, onwriteerror); + if (onprogress) + onprogress(index, size); + }, onreaderror); + else { + outputData = process.flush(); + if (outputData) { + outputSize += outputData.length; + writer.writeUint8Array(outputData, function() { + onappend(false, outputData); + onend(outputSize); + }, onwriteerror); + } else + onend(outputSize); + } + } + + step(); + } + + function inflate(reader, writer, offset, size, computeCrc32, onend, onprogress, onreaderror, onwriteerror) { + var worker, crc32 = new Crc32(); + + function oninflateappend(sending, array) { + if (computeCrc32 && !sending) + crc32.append(array); + } + + function oninflateend(outputSize) { + onend(outputSize, crc32.get()); + } + + if (obj.zip.useWebWorkers) { + + worker = new Worker(obj.zip.workerScriptsPath + INFLATE_JS); + launchWorkerProcess(worker, reader, writer, offset, size, oninflateappend, onprogress, oninflateend, onreaderror, onwriteerror); + } else + launchProcess(new obj.zip.Inflater(), reader, writer, offset, size, oninflateappend, onprogress, oninflateend, onreaderror, onwriteerror); + return worker; + } + + function deflate(reader, writer, level, onend, onprogress, onreaderror, onwriteerror) { + var worker, crc32 = new Crc32(); + + function ondeflateappend(sending, array) { + if (sending) + crc32.append(array); + } + + function ondeflateend(outputSize) { + onend(outputSize, crc32.get()); + } + + function onmessage() { + worker.removeEventListener(MESSAGE_EVENT, onmessage, false); + launchWorkerProcess(worker, reader, writer, 0, reader.size, ondeflateappend, onprogress, ondeflateend, onreaderror, onwriteerror); + } + + if (obj.zip.useWebWorkers) { + worker = new Worker(obj.zip.workerScriptsPath + DEFLATE_JS); + worker.addEventListener(MESSAGE_EVENT, onmessage, false); + worker.postMessage({ + init : true, + level : level + }); + } else + launchProcess(new obj.zip.Deflater(), reader, writer, 0, reader.size, ondeflateappend, onprogress, ondeflateend, onreaderror, onwriteerror); + return worker; + } + + function copy(reader, writer, offset, size, computeCrc32, onend, onprogress, onreaderror, onwriteerror) { + var chunkIndex = 0, crc32 = new Crc32(); + + function step() { + var index = chunkIndex * CHUNK_SIZE; + if (index < size) + reader.readUint8Array(offset + index, Math.min(CHUNK_SIZE, size - index), function(array) { + if (computeCrc32) + crc32.append(array); + if (onprogress) + onprogress(index, size, array); + writer.writeUint8Array(array, function() { + chunkIndex++; + step(); + }, onwriteerror); + }, onreaderror); + else + onend(size, crc32.get()); + } + + step(); + } + + // ZipReader + + function decodeASCII(str) { + var i, out = "", charCode, extendedASCII = [ '\u00C7', '\u00FC', '\u00E9', '\u00E2', '\u00E4', '\u00E0', '\u00E5', '\u00E7', '\u00EA', '\u00EB', + '\u00E8', '\u00EF', '\u00EE', '\u00EC', '\u00C4', '\u00C5', '\u00C9', '\u00E6', '\u00C6', '\u00F4', '\u00F6', '\u00F2', '\u00FB', '\u00F9', + '\u00FF', '\u00D6', '\u00DC', '\u00F8', '\u00A3', '\u00D8', '\u00D7', '\u0192', '\u00E1', '\u00ED', '\u00F3', '\u00FA', '\u00F1', '\u00D1', + '\u00AA', '\u00BA', '\u00BF', '\u00AE', '\u00AC', '\u00BD', '\u00BC', '\u00A1', '\u00AB', '\u00BB', '_', '_', '_', '\u00A6', '\u00A6', + '\u00C1', '\u00C2', '\u00C0', '\u00A9', '\u00A6', '\u00A6', '+', '+', '\u00A2', '\u00A5', '+', '+', '-', '-', '+', '-', '+', '\u00E3', + '\u00C3', '+', '+', '-', '-', '\u00A6', '-', '+', '\u00A4', '\u00F0', '\u00D0', '\u00CA', '\u00CB', '\u00C8', 'i', '\u00CD', '\u00CE', + '\u00CF', '+', '+', '_', '_', '\u00A6', '\u00CC', '_', '\u00D3', '\u00DF', '\u00D4', '\u00D2', '\u00F5', '\u00D5', '\u00B5', '\u00FE', + '\u00DE', '\u00DA', '\u00DB', '\u00D9', '\u00FD', '\u00DD', '\u00AF', '\u00B4', '\u00AD', '\u00B1', '_', '\u00BE', '\u00B6', '\u00A7', + '\u00F7', '\u00B8', '\u00B0', '\u00A8', '\u00B7', '\u00B9', '\u00B3', '\u00B2', '_', ' ' ]; + for (i = 0; i < str.length; i++) { + charCode = str.charCodeAt(i) & 0xFF; + if (charCode > 127) + out += extendedASCII[charCode - 128]; + else + out += String.fromCharCode(charCode); + } + return out; + } + + function decodeUTF8(string) { + return decodeURIComponent(escape(string)); + } + + function getString(bytes) { + var i, str = ""; + for (i = 0; i < bytes.length; i++) + str += String.fromCharCode(bytes[i]); + return str; + } + + function getDate(timeRaw) { + var date = (timeRaw & 0xffff0000) >> 16, time = timeRaw & 0x0000ffff; + try { + return new Date(1980 + ((date & 0xFE00) >> 9), ((date & 0x01E0) >> 5) - 1, date & 0x001F, (time & 0xF800) >> 11, (time & 0x07E0) >> 5, + (time & 0x001F) * 2, 0); + } catch (e) { + } + } + + function readCommonHeader(entry, data, index, centralDirectory, onerror) { + entry.version = data.view.getUint16(index, true); + entry.bitFlag = data.view.getUint16(index + 2, true); + entry.compressionMethod = data.view.getUint16(index + 4, true); + entry.lastModDateRaw = data.view.getUint32(index + 6, true); + entry.lastModDate = getDate(entry.lastModDateRaw); + if ((entry.bitFlag & 0x01) === 0x01) { + onerror(ERR_ENCRYPTED); + return; + } + if (centralDirectory || (entry.bitFlag & 0x0008) != 0x0008) { + entry.crc32 = data.view.getUint32(index + 10, true); + entry.compressedSize = data.view.getUint32(index + 14, true); + entry.uncompressedSize = data.view.getUint32(index + 18, true); + } + if (entry.compressedSize === 0xFFFFFFFF || entry.uncompressedSize === 0xFFFFFFFF) { + onerror(ERR_ZIP64); + return; + } + entry.filenameLength = data.view.getUint16(index + 22, true); + entry.extraFieldLength = data.view.getUint16(index + 24, true); + } + + function createZipReader(reader, onerror) { + function Entry() { + } + + Entry.prototype.getData = function(writer, onend, onprogress, checkCrc32) { + var that = this, worker; + + function terminate(callback, param) { + if (worker) + worker.terminate(); + worker = null; + if (callback) + callback(param); + } + + function testCrc32(crc32) { + var dataCrc32 = getDataHelper(4); + dataCrc32.view.setUint32(0, crc32); + return that.crc32 == dataCrc32.view.getUint32(0); + } + + function getWriterData(uncompressedSize, crc32) { + if (checkCrc32 && !testCrc32(crc32)) + onreaderror(); + else + writer.getData(function(data) { + terminate(onend, data); + }); + } + + function onreaderror() { + terminate(onerror, ERR_READ_DATA); + } + + function onwriteerror() { + terminate(onerror, ERR_WRITE_DATA); + } + + reader.readUint8Array(that.offset, 30, function(bytes) { + var data = getDataHelper(bytes.length, bytes), dataOffset; + if (data.view.getUint32(0) != 0x504b0304) { + onerror(ERR_BAD_FORMAT); + return; + } + readCommonHeader(that, data, 4, false, onerror); + dataOffset = that.offset + 30 + that.filenameLength + that.extraFieldLength; + writer.init(function() { + if (that.compressionMethod === 0) + copy(reader, writer, dataOffset, that.compressedSize, checkCrc32, getWriterData, onprogress, onreaderror, onwriteerror); + else + worker = inflate(reader, writer, dataOffset, that.compressedSize, checkCrc32, getWriterData, onprogress, onreaderror, onwriteerror); + }, onwriteerror); + }, onreaderror); + }; + + function seekEOCDR(offset, entriesCallback) { + reader.readUint8Array(reader.size - offset, offset, function(bytes) { + var dataView = getDataHelper(bytes.length, bytes).view; + if (dataView.getUint32(0) != 0x504b0506) { + seekEOCDR(offset + 1, entriesCallback); + } else { + entriesCallback(dataView); + } + }, function() { + onerror(ERR_READ); + }); + } + + return { + getEntries : function(callback) { + if (reader.size < 22) { + onerror(ERR_BAD_FORMAT); + return; + } + // look for End of central directory record + seekEOCDR(22, function(dataView) { + var datalength, fileslength; + datalength = dataView.getUint32(16, true); + fileslength = dataView.getUint16(8, true); + reader.readUint8Array(datalength, reader.size - datalength, function(bytes) { + var i, index = 0, entries = [], entry, filename, comment, data = getDataHelper(bytes.length, bytes); + for (i = 0; i < fileslength; i++) { + entry = new Entry(); + if (data.view.getUint32(index) != 0x504b0102) { + onerror(ERR_BAD_FORMAT); + return; + } + readCommonHeader(entry, data, index + 6, true, onerror); + entry.commentLength = data.view.getUint16(index + 32, true); + entry.directory = ((data.view.getUint8(index + 38) & 0x10) == 0x10); + entry.offset = data.view.getUint32(index + 42, true); + filename = getString(data.array.subarray(index + 46, index + 46 + entry.filenameLength)); + entry.filename = ((entry.bitFlag & 0x0800) === 0x0800) ? decodeUTF8(filename) : decodeASCII(filename); + if (!entry.directory && entry.filename.charAt(entry.filename.length - 1) == "/") + entry.directory = true; + comment = getString(data.array.subarray(index + 46 + entry.filenameLength + entry.extraFieldLength, index + 46 + + entry.filenameLength + entry.extraFieldLength + entry.commentLength)); + entry.comment = ((entry.bitFlag & 0x0800) === 0x0800) ? decodeUTF8(comment) : decodeASCII(comment); + entries.push(entry); + index += 46 + entry.filenameLength + entry.extraFieldLength + entry.commentLength; + } + callback(entries); + }, function() { + onerror(ERR_READ); + }); + }); + }, + close : function(callback) { + if (callback) + callback(); + } + }; + } + + // ZipWriter + + function encodeUTF8(string) { + return unescape(encodeURIComponent(string)); + } + + function getBytes(str) { + var i, array = []; + for (i = 0; i < str.length; i++) + array.push(str.charCodeAt(i)); + return array; + } + + function createZipWriter(writer, onerror, dontDeflate) { + var worker, files = {}, filenames = [], datalength = 0; + + function terminate(callback, message) { + if (worker) + worker.terminate(); + worker = null; + if (callback) + callback(message); + } + + function onwriteerror() { + terminate(onerror, ERR_WRITE); + } + + function onreaderror() { + terminate(onerror, ERR_READ_DATA); + } + + return { + add : function(name, reader, onend, onprogress, options) { + var header, filename, date; + + function writeHeader(callback) { + var data; + date = options.lastModDate || new Date(); + header = getDataHelper(26); + files[name] = { + headerArray : header.array, + directory : options.directory, + filename : filename, + offset : datalength, + comment : getBytes(encodeUTF8(options.comment || "")) + }; + header.view.setUint32(0, 0x14000808); + if (options.version) + header.view.setUint8(0, options.version); + if (!dontDeflate && options.level !== 0 && !options.directory) + header.view.setUint16(4, 0x0800); + header.view.setUint16(6, (((date.getHours() << 6) | date.getMinutes()) << 5) | date.getSeconds() / 2, true); + header.view.setUint16(8, ((((date.getFullYear() - 1980) << 4) | (date.getMonth() + 1)) << 5) | date.getDate(), true); + header.view.setUint16(22, filename.length, true); + data = getDataHelper(30 + filename.length); + data.view.setUint32(0, 0x504b0304); + data.array.set(header.array, 4); + data.array.set(filename, 30); + datalength += data.array.length; + writer.writeUint8Array(data.array, callback, onwriteerror); + } + + function writeFooter(compressedLength, crc32) { + var footer = getDataHelper(16); + datalength += compressedLength || 0; + footer.view.setUint32(0, 0x504b0708); + if (typeof crc32 != "undefined") { + header.view.setUint32(10, crc32, true); + footer.view.setUint32(4, crc32, true); + } + if (reader) { + footer.view.setUint32(8, compressedLength, true); + header.view.setUint32(14, compressedLength, true); + footer.view.setUint32(12, reader.size, true); + header.view.setUint32(18, reader.size, true); + } + writer.writeUint8Array(footer.array, function() { + datalength += 16; + terminate(onend); + }, onwriteerror); + } + + function writeFile() { + options = options || {}; + name = name.trim(); + if (options.directory && name.charAt(name.length - 1) != "/") + name += "/"; + if (files.hasOwnProperty(name)) { + onerror(ERR_DUPLICATED_NAME); + return; + } + filename = getBytes(encodeUTF8(name)); + filenames.push(name); + writeHeader(function() { + if (reader) + if (dontDeflate || options.level === 0) + copy(reader, writer, 0, reader.size, true, writeFooter, onprogress, onreaderror, onwriteerror); + else + worker = deflate(reader, writer, options.level, writeFooter, onprogress, onreaderror, onwriteerror); + else + writeFooter(); + }, onwriteerror); + } + + if (reader) + reader.init(writeFile, onreaderror); + else + writeFile(); + }, + close : function(callback) { + var data, length = 0, index = 0, indexFilename, file; + for (indexFilename = 0; indexFilename < filenames.length; indexFilename++) { + file = files[filenames[indexFilename]]; + length += 46 + file.filename.length + file.comment.length; + } + data = getDataHelper(length + 22); + for (indexFilename = 0; indexFilename < filenames.length; indexFilename++) { + file = files[filenames[indexFilename]]; + data.view.setUint32(index, 0x504b0102); + data.view.setUint16(index + 4, 0x1400); + data.array.set(file.headerArray, index + 6); + data.view.setUint16(index + 32, file.comment.length, true); + if (file.directory) + data.view.setUint8(index + 38, 0x10); + data.view.setUint32(index + 42, file.offset, true); + data.array.set(file.filename, index + 46); + data.array.set(file.comment, index + 46 + file.filename.length); + index += 46 + file.filename.length + file.comment.length; + } + data.view.setUint32(index, 0x504b0506); + data.view.setUint16(index + 8, filenames.length, true); + data.view.setUint16(index + 10, filenames.length, true); + data.view.setUint32(index + 12, length, true); + data.view.setUint32(index + 16, datalength, true); + writer.writeUint8Array(data.array, function() { + terminate(function() { + writer.getData(callback); + }); + }, onwriteerror); + } + }; + } + + obj.zip = { + Reader : Reader, + Writer : Writer, + BlobReader : BlobReader, + Data64URIReader : Data64URIReader, + TextReader : TextReader, + BlobWriter : BlobWriter, + Data64URIWriter : Data64URIWriter, + TextWriter : TextWriter, + createReader : function(reader, callback, onerror) { + reader.init(function() { + callback(createZipReader(reader, onerror)); + }, onerror); + }, + createWriter : function(writer, callback, onerror, dontDeflate) { + writer.init(function() { + callback(createZipWriter(writer, onerror, dontDeflate)); + }, onerror); + }, + workerScriptsPath : "", + useWebWorkers : true + }; + +}(O.esri)); +/** + * This library assists with autoCenter the map upon orientation change + * IMPORTANT: There are Esri dependencies in this library including + * esri.Geometry.Point, esri.SpatialReference and Esri.Map. + * The fact that these dependencies exist is implied that they were + * loaded via some other means and made globally available. + * Sometimes this happens by default, as is true in this case. + * @param map + * @param delay + */ +O.esri.TPK.autoCenterMap = function(/* Map */ map,/* int */ delay){ + + /** + * Activates the orientation listener and listens for native events. + */ + function _setOrientationListener(delay){ + var supportsOrientationChange = "onorientationchange" in window, + orientationEvent = supportsOrientationChange ? "orientationchange" : "resize"; + + window.addEventListener(orientationEvent, _debounceMap(function(){ + _centerMap(); + },delay)); + } + + /** + * Center the map based on locations pulled from local storage + * @param context + * @param delay + * @private + */ + function _centerMap(){ + + require(["esri/geometry/Point","esri/SpatialReference"], function (Point,SpatialReference) { + var locationStr = _getCenterPt().split(","); + var wkid = map.spatialReference.wkid; + var mapPt = null; + + if(wkid == 4326){ + mapPt = new Point(locationStr[1],locationStr[0]); + } + else if(wkid == 102100){ + mapPt = new Point(locationStr[0],locationStr[1], new SpatialReference({ wkid: wkid })); + } + map.centerAt(mapPt); + }); + } + + /** + * Minimize the number of times window readjustment fires a function + * http://davidwalsh.name/javascript-debounce-function + * @param func + * @param wait + * @param immediate + * @returns {Function} + */ + function _debounceMap(func, wait, immediate) { + var timeout; + return function() { + var context = this, args = arguments; + clearTimeout(timeout); + timeout = setTimeout(function() { + timeout = null; + if (!immediate) { + func.apply(context, args); + } + }, wait); + if (immediate && !timeout) { + func.apply(context, args); + } + }; + } + + /** + * Automatically sets new center point in local storage. + */ + function _setPanListener(){ + map.on("pan-end",function(){ + var center = map.extent.getCenter(); + _setCenterPt(center.x,center.y,map.spatialReference.wkid); + }); + } + + /** + * Automatically sets new center point and zoom level in + * local storage. + */ + function _setZoomListener(){ + map.on("zoom-end",function(){ + var center = map.extent.getCenter(); + _setCenterPt(center.x,center.y,map.spatialReference.wkid); + map.setZoom(map.getZoom()); + }); + } + + /** + * Uses localStorage to save a location. + * @param lat + * @param lon + * @param spatialReference + */ + function _setCenterPt(lat,lon,spatialReference){ + localStorage.setItem("_centerPtX", lat); + localStorage.setItem("_centerPtY", lon); + localStorage.setItem("_spatialReference", spatialReference); + } + + /** + * Pulls a saved location from localStorage + * Requires that setCenterPt() has been set. + * @returns String x,y,spatialReference + */ + function _getCenterPt(){ + var value = null; + + try{ + value = localStorage.getItem("_centerPtX") + "," + localStorage.getItem("_centerPtY") + "," + + localStorage.getItem("_spatialReference"); + } + catch(err) + { + console.log("getCenterFromLocalStorage: " + err.message); + } + + return value; + } + + this.init = function(){ + _setPanListener(); + _setZoomListener(); + _setOrientationListener(delay); + var centerPt = map.extent.getCenter(); + _setCenterPt(centerPt.x,centerPt.y,map.spatialReference.wkid); + }; +}; +/* + Copyright (c) 2013 Gildas Lormeau. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This program is based on JZlib 1.0.2 ymnk, JCraft,Inc. + * JZlib is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +O.esri.TPK.inflate = function(obj) { + + // Global + var MAX_BITS = 15; + + var Z_OK = 0; + var Z_STREAM_END = 1; + var Z_NEED_DICT = 2; + var Z_STREAM_ERROR = -2; + var Z_DATA_ERROR = -3; + var Z_MEM_ERROR = -4; + var Z_BUF_ERROR = -5; + + var inflate_mask = [ 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff, 0x000003ff, + 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff ]; + + var MANY = 1440; + + // JZlib version : "1.0.2" + var Z_NO_FLUSH = 0; + var Z_FINISH = 4; + + // InfTree + var fixed_bl = 9; + var fixed_bd = 5; + + var fixed_tl = [ 96, 7, 256, 0, 8, 80, 0, 8, 16, 84, 8, 115, 82, 7, 31, 0, 8, 112, 0, 8, 48, 0, 9, 192, 80, 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, 160, 0, 8, 0, + 0, 8, 128, 0, 8, 64, 0, 9, 224, 80, 7, 6, 0, 8, 88, 0, 8, 24, 0, 9, 144, 83, 7, 59, 0, 8, 120, 0, 8, 56, 0, 9, 208, 81, 7, 17, 0, 8, 104, 0, 8, 40, + 0, 9, 176, 0, 8, 8, 0, 8, 136, 0, 8, 72, 0, 9, 240, 80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8, 227, 83, 7, 43, 0, 8, 116, 0, 8, 52, 0, 9, 200, 81, 7, 13, + 0, 8, 100, 0, 8, 36, 0, 9, 168, 0, 8, 4, 0, 8, 132, 0, 8, 68, 0, 9, 232, 80, 7, 8, 0, 8, 92, 0, 8, 28, 0, 9, 152, 84, 7, 83, 0, 8, 124, 0, 8, 60, + 0, 9, 216, 82, 7, 23, 0, 8, 108, 0, 8, 44, 0, 9, 184, 0, 8, 12, 0, 8, 140, 0, 8, 76, 0, 9, 248, 80, 7, 3, 0, 8, 82, 0, 8, 18, 85, 8, 163, 83, 7, + 35, 0, 8, 114, 0, 8, 50, 0, 9, 196, 81, 7, 11, 0, 8, 98, 0, 8, 34, 0, 9, 164, 0, 8, 2, 0, 8, 130, 0, 8, 66, 0, 9, 228, 80, 7, 7, 0, 8, 90, 0, 8, + 26, 0, 9, 148, 84, 7, 67, 0, 8, 122, 0, 8, 58, 0, 9, 212, 82, 7, 19, 0, 8, 106, 0, 8, 42, 0, 9, 180, 0, 8, 10, 0, 8, 138, 0, 8, 74, 0, 9, 244, 80, + 7, 5, 0, 8, 86, 0, 8, 22, 192, 8, 0, 83, 7, 51, 0, 8, 118, 0, 8, 54, 0, 9, 204, 81, 7, 15, 0, 8, 102, 0, 8, 38, 0, 9, 172, 0, 8, 6, 0, 8, 134, 0, + 8, 70, 0, 9, 236, 80, 7, 9, 0, 8, 94, 0, 8, 30, 0, 9, 156, 84, 7, 99, 0, 8, 126, 0, 8, 62, 0, 9, 220, 82, 7, 27, 0, 8, 110, 0, 8, 46, 0, 9, 188, 0, + 8, 14, 0, 8, 142, 0, 8, 78, 0, 9, 252, 96, 7, 256, 0, 8, 81, 0, 8, 17, 85, 8, 131, 82, 7, 31, 0, 8, 113, 0, 8, 49, 0, 9, 194, 80, 7, 10, 0, 8, 97, + 0, 8, 33, 0, 9, 162, 0, 8, 1, 0, 8, 129, 0, 8, 65, 0, 9, 226, 80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9, 146, 83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 210, + 81, 7, 17, 0, 8, 105, 0, 8, 41, 0, 9, 178, 0, 8, 9, 0, 8, 137, 0, 8, 73, 0, 9, 242, 80, 7, 4, 0, 8, 85, 0, 8, 21, 80, 8, 258, 83, 7, 43, 0, 8, 117, + 0, 8, 53, 0, 9, 202, 81, 7, 13, 0, 8, 101, 0, 8, 37, 0, 9, 170, 0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9, 234, 80, 7, 8, 0, 8, 93, 0, 8, 29, 0, 9, 154, + 84, 7, 83, 0, 8, 125, 0, 8, 61, 0, 9, 218, 82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 186, 0, 8, 13, 0, 8, 141, 0, 8, 77, 0, 9, 250, 80, 7, 3, 0, 8, 83, + 0, 8, 19, 85, 8, 195, 83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, 198, 81, 7, 11, 0, 8, 99, 0, 8, 35, 0, 9, 166, 0, 8, 3, 0, 8, 131, 0, 8, 67, 0, 9, 230, + 80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, 150, 84, 7, 67, 0, 8, 123, 0, 8, 59, 0, 9, 214, 82, 7, 19, 0, 8, 107, 0, 8, 43, 0, 9, 182, 0, 8, 11, 0, 8, 139, + 0, 8, 75, 0, 9, 246, 80, 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0, 83, 7, 51, 0, 8, 119, 0, 8, 55, 0, 9, 206, 81, 7, 15, 0, 8, 103, 0, 8, 39, 0, 9, 174, + 0, 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 238, 80, 7, 9, 0, 8, 95, 0, 8, 31, 0, 9, 158, 84, 7, 99, 0, 8, 127, 0, 8, 63, 0, 9, 222, 82, 7, 27, 0, 8, 111, + 0, 8, 47, 0, 9, 190, 0, 8, 15, 0, 8, 143, 0, 8, 79, 0, 9, 254, 96, 7, 256, 0, 8, 80, 0, 8, 16, 84, 8, 115, 82, 7, 31, 0, 8, 112, 0, 8, 48, 0, 9, + 193, 80, 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, 161, 0, 8, 0, 0, 8, 128, 0, 8, 64, 0, 9, 225, 80, 7, 6, 0, 8, 88, 0, 8, 24, 0, 9, 145, 83, 7, 59, 0, 8, + 120, 0, 8, 56, 0, 9, 209, 81, 7, 17, 0, 8, 104, 0, 8, 40, 0, 9, 177, 0, 8, 8, 0, 8, 136, 0, 8, 72, 0, 9, 241, 80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8, + 227, 83, 7, 43, 0, 8, 116, 0, 8, 52, 0, 9, 201, 81, 7, 13, 0, 8, 100, 0, 8, 36, 0, 9, 169, 0, 8, 4, 0, 8, 132, 0, 8, 68, 0, 9, 233, 80, 7, 8, 0, 8, + 92, 0, 8, 28, 0, 9, 153, 84, 7, 83, 0, 8, 124, 0, 8, 60, 0, 9, 217, 82, 7, 23, 0, 8, 108, 0, 8, 44, 0, 9, 185, 0, 8, 12, 0, 8, 140, 0, 8, 76, 0, 9, + 249, 80, 7, 3, 0, 8, 82, 0, 8, 18, 85, 8, 163, 83, 7, 35, 0, 8, 114, 0, 8, 50, 0, 9, 197, 81, 7, 11, 0, 8, 98, 0, 8, 34, 0, 9, 165, 0, 8, 2, 0, 8, + 130, 0, 8, 66, 0, 9, 229, 80, 7, 7, 0, 8, 90, 0, 8, 26, 0, 9, 149, 84, 7, 67, 0, 8, 122, 0, 8, 58, 0, 9, 213, 82, 7, 19, 0, 8, 106, 0, 8, 42, 0, 9, + 181, 0, 8, 10, 0, 8, 138, 0, 8, 74, 0, 9, 245, 80, 7, 5, 0, 8, 86, 0, 8, 22, 192, 8, 0, 83, 7, 51, 0, 8, 118, 0, 8, 54, 0, 9, 205, 81, 7, 15, 0, 8, + 102, 0, 8, 38, 0, 9, 173, 0, 8, 6, 0, 8, 134, 0, 8, 70, 0, 9, 237, 80, 7, 9, 0, 8, 94, 0, 8, 30, 0, 9, 157, 84, 7, 99, 0, 8, 126, 0, 8, 62, 0, 9, + 221, 82, 7, 27, 0, 8, 110, 0, 8, 46, 0, 9, 189, 0, 8, 14, 0, 8, 142, 0, 8, 78, 0, 9, 253, 96, 7, 256, 0, 8, 81, 0, 8, 17, 85, 8, 131, 82, 7, 31, 0, + 8, 113, 0, 8, 49, 0, 9, 195, 80, 7, 10, 0, 8, 97, 0, 8, 33, 0, 9, 163, 0, 8, 1, 0, 8, 129, 0, 8, 65, 0, 9, 227, 80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9, + 147, 83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 211, 81, 7, 17, 0, 8, 105, 0, 8, 41, 0, 9, 179, 0, 8, 9, 0, 8, 137, 0, 8, 73, 0, 9, 243, 80, 7, 4, 0, 8, + 85, 0, 8, 21, 80, 8, 258, 83, 7, 43, 0, 8, 117, 0, 8, 53, 0, 9, 203, 81, 7, 13, 0, 8, 101, 0, 8, 37, 0, 9, 171, 0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9, + 235, 80, 7, 8, 0, 8, 93, 0, 8, 29, 0, 9, 155, 84, 7, 83, 0, 8, 125, 0, 8, 61, 0, 9, 219, 82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 187, 0, 8, 13, 0, 8, + 141, 0, 8, 77, 0, 9, 251, 80, 7, 3, 0, 8, 83, 0, 8, 19, 85, 8, 195, 83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, 199, 81, 7, 11, 0, 8, 99, 0, 8, 35, 0, 9, + 167, 0, 8, 3, 0, 8, 131, 0, 8, 67, 0, 9, 231, 80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, 151, 84, 7, 67, 0, 8, 123, 0, 8, 59, 0, 9, 215, 82, 7, 19, 0, 8, + 107, 0, 8, 43, 0, 9, 183, 0, 8, 11, 0, 8, 139, 0, 8, 75, 0, 9, 247, 80, 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0, 83, 7, 51, 0, 8, 119, 0, 8, 55, 0, 9, + 207, 81, 7, 15, 0, 8, 103, 0, 8, 39, 0, 9, 175, 0, 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 239, 80, 7, 9, 0, 8, 95, 0, 8, 31, 0, 9, 159, 84, 7, 99, 0, 8, + 127, 0, 8, 63, 0, 9, 223, 82, 7, 27, 0, 8, 111, 0, 8, 47, 0, 9, 191, 0, 8, 15, 0, 8, 143, 0, 8, 79, 0, 9, 255 ]; + var fixed_td = [ 80, 5, 1, 87, 5, 257, 83, 5, 17, 91, 5, 4097, 81, 5, 5, 89, 5, 1025, 85, 5, 65, 93, 5, 16385, 80, 5, 3, 88, 5, 513, 84, 5, 33, 92, 5, + 8193, 82, 5, 9, 90, 5, 2049, 86, 5, 129, 192, 5, 24577, 80, 5, 2, 87, 5, 385, 83, 5, 25, 91, 5, 6145, 81, 5, 7, 89, 5, 1537, 85, 5, 97, 93, 5, + 24577, 80, 5, 4, 88, 5, 769, 84, 5, 49, 92, 5, 12289, 82, 5, 13, 90, 5, 3073, 86, 5, 193, 192, 5, 24577 ]; + + // Tables for deflate from PKZIP's appnote.txt. + var cplens = [ // Copy lengths for literal codes 257..285 + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 ]; + + // see note #13 above about 258 + var cplext = [ // Extra bits for literal codes 257..285 + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112 // 112==invalid + ]; + + var cpdist = [ // Copy offsets for distance codes 0..29 + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 ]; + + var cpdext = [ // Extra bits for distance codes + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 ]; + + // If BMAX needs to be larger than 16, then h and x[] should be uLong. + var BMAX = 15; // maximum bit length of any code + + function InfTree() { + var that = this; + + var hn; // hufts used in space + var v; // work area for huft_build + var c; // bit length count table + var r; // table entry for structure assignment + var u; // table stack + var x; // bit offsets, then code stack + + function huft_build(b, // code lengths in bits (all assumed <= + // BMAX) + bindex, n, // number of codes (assumed <= 288) + s, // number of simple-valued codes (0..s-1) + d, // list of base values for non-simple codes + e, // list of extra bits for non-simple codes + t, // result: starting table + m, // maximum lookup bits, returns actual + hp,// space for trees + hn,// hufts used in space + v // working area: values in order of bit length + ) { + // Given a list of code lengths and a maximum table size, make a set of + // tables to decode that set of codes. Return Z_OK on success, + // Z_BUF_ERROR + // if the given code set is incomplete (the tables are still built in + // this + // case), Z_DATA_ERROR if the input is invalid (an over-subscribed set + // of + // lengths), or Z_MEM_ERROR if not enough memory. + + var a; // counter for codes of length k + var f; // i repeats in table every f entries + var g; // maximum code length + var h; // table level + var i; // counter, current code + var j; // counter + var k; // number of bits in current code + var l; // bits per table (returned in m) + var mask; // (1 << w) - 1, to avoid cc -O bug on HP + var p; // pointer into c[], b[], or v[] + var q; // points to current table + var w; // bits before this table == (l * h) + var xp; // pointer into x + var y; // number of dummy codes added + var z; // number of entries in current table + + // Generate counts for each bit length + + p = 0; + i = n; + do { + c[b[bindex + p]]++; + p++; + i--; // assume all entries <= BMAX + } while (i !== 0); + + if (c[0] == n) { // null input--all zero length codes + t[0] = -1; + m[0] = 0; + return Z_OK; + } + + // Find minimum and maximum length, bound *m by those + l = m[0]; + for (j = 1; j <= BMAX; j++) + if (c[j] !== 0) + break; + k = j; // minimum code length + if (l < j) { + l = j; + } + for (i = BMAX; i !== 0; i--) { + if (c[i] !== 0) + break; + } + g = i; // maximum code length + if (l > i) { + l = i; + } + m[0] = l; + + // Adjust last length count to fill out codes, if needed + for (y = 1 << j; j < i; j++, y <<= 1) { + if ((y -= c[j]) < 0) { + return Z_DATA_ERROR; + } + } + if ((y -= c[i]) < 0) { + return Z_DATA_ERROR; + } + c[i] += y; + + // Generate starting offsets into the value table for each length + x[1] = j = 0; + p = 1; + xp = 2; + while (--i !== 0) { // note that i == g from above + x[xp] = (j += c[p]); + xp++; + p++; + } + + // Make a table of values in order of bit lengths + i = 0; + p = 0; + do { + if ((j = b[bindex + p]) !== 0) { + v[x[j]++] = i; + } + p++; + } while (++i < n); + n = x[g]; // set n to length of v + + // Generate the Huffman codes and for each, make the table entries + x[0] = i = 0; // first Huffman code is zero + p = 0; // grab values in bit order + h = -1; // no tables yet--level -1 + w = -l; // bits decoded == (l * h) + u[0] = 0; // just to keep compilers happy + q = 0; // ditto + z = 0; // ditto + + // go through the bit lengths (k already is bits in shortest code) + for (; k <= g; k++) { + a = c[k]; + while (a-- !== 0) { + // here i is the Huffman code of length k bits for value *p + // make tables up to required level + while (k > w + l) { + h++; + w += l; // previous table always l bits + // compute minimum size table less than or equal to l bits + z = g - w; + z = (z > l) ? l : z; // table size upper limit + if ((f = 1 << (j = k - w)) > a + 1) { // try a k-w bit table + // too few codes for + // k-w bit table + f -= a + 1; // deduct codes from patterns left + xp = k; + if (j < z) { + while (++j < z) { // try smaller tables up to z bits + if ((f <<= 1) <= c[++xp]) + break; // enough codes to use up j bits + f -= c[xp]; // else deduct codes from patterns + } + } + } + z = 1 << j; // table entries for j-bit table + + // allocate new table + if (hn[0] + z > MANY) { // (note: doesn't matter for fixed) + return Z_DATA_ERROR; // overflow of MANY + } + u[h] = q = /* hp+ */hn[0]; // DEBUG + hn[0] += z; + + // connect to last table, if there is one + if (h !== 0) { + x[h] = i; // save pattern for backing up + r[0] = /* (byte) */j; // bits in this table + r[1] = /* (byte) */l; // bits to dump before this table + j = i >>> (w - l); + r[2] = /* (int) */(q - u[h - 1] - j); // offset to this table + hp.set(r, (u[h - 1] + j) * 3); + // to + // last + // table + } else { + t[0] = q; // first table is returned result + } + } + + // set up table entry in r + r[1] = /* (byte) */(k - w); + if (p >= n) { + r[0] = 128 + 64; // out of values--invalid code + } else if (v[p] < s) { + r[0] = /* (byte) */(v[p] < 256 ? 0 : 32 + 64); // 256 is + // end-of-block + r[2] = v[p++]; // simple code is just the value + } else { + r[0] = /* (byte) */(e[v[p] - s] + 16 + 64); // non-simple--look + // up in lists + r[2] = d[v[p++] - s]; + } + + // fill code-like entries with r + f = 1 << (k - w); + for (j = i >>> w; j < z; j += f) { + hp.set(r, (q + j) * 3); + } + + // backwards increment the k-bit code i + for (j = 1 << (k - 1); (i & j) !== 0; j >>>= 1) { + i ^= j; + } + i ^= j; + + // backup over finished tables + mask = (1 << w) - 1; // needed on HP, cc -O bug + while ((i & mask) != x[h]) { + h--; // don't need to update q + w -= l; + mask = (1 << w) - 1; + } + } + } + // Return Z_BUF_ERROR if we were given an incomplete table + return y !== 0 && g != 1 ? Z_BUF_ERROR : Z_OK; + } + + function initWorkArea(vsize) { + var i; + if (!hn) { + hn = []; // []; //new Array(1); + v = []; // new Array(vsize); + c = new Int32Array(BMAX + 1); // new Array(BMAX + 1); + r = []; // new Array(3); + u = new Int32Array(BMAX); // new Array(BMAX); + x = new Int32Array(BMAX + 1); // new Array(BMAX + 1); + } + if (v.length < vsize) { + v = []; // new Array(vsize); + } + for (i = 0; i < vsize; i++) { + v[i] = 0; + } + for (i = 0; i < BMAX + 1; i++) { + c[i] = 0; + } + for (i = 0; i < 3; i++) { + r[i] = 0; + } + // for(int i=0; i 257)) { + if (result == Z_DATA_ERROR) { + z.msg = "oversubscribed distance tree"; + } else if (result == Z_BUF_ERROR) { + z.msg = "incomplete distance tree"; + result = Z_DATA_ERROR; + } else if (result != Z_MEM_ERROR) { + z.msg = "empty distance tree with lengths"; + result = Z_DATA_ERROR; + } + return result; + } + + return Z_OK; + }; + + } + + InfTree.inflate_trees_fixed = function(bl, // literal desired/actual bit depth + bd, // distance desired/actual bit depth + tl,// literal/length tree result + td// distance tree result + ) { + bl[0] = fixed_bl; + bd[0] = fixed_bd; + tl[0] = fixed_tl; + td[0] = fixed_td; + return Z_OK; + }; + + // InfCodes + + // waiting for "i:"=input, + // "o:"=output, + // "x:"=nothing + var START = 0; // x: set up for LEN + var LEN = 1; // i: get length/literal/eob next + var LENEXT = 2; // i: getting length extra (have base) + var DIST = 3; // i: get distance next + var DISTEXT = 4;// i: getting distance extra + var COPY = 5; // o: copying bytes in window, waiting + // for space + var LIT = 6; // o: got literal, waiting for output + // space + var WASH = 7; // o: got eob, possibly still output + // waiting + var END = 8; // x: got eob and all data flushed + var BADCODE = 9;// x: got error + + function InfCodes() { + var that = this; + + var mode; // current inflate_codes mode + + // mode dependent information + var len = 0; + + var tree; // pointer into tree + var tree_index = 0; + var need = 0; // bits needed + + var lit = 0; + + // if EXT or COPY, where and how much + var get = 0; // bits to get for extra + var dist = 0; // distance back to copy from + + var lbits = 0; // ltree bits decoded per branch + var dbits = 0; // dtree bits decoder per branch + var ltree; // literal/length/eob tree + var ltree_index = 0; // literal/length/eob tree + var dtree; // distance tree + var dtree_index = 0; // distance tree + + // Called with number of bytes left to write in window at least 258 + // (the maximum string length) and number of input bytes available + // at least ten. The ten bytes are six bytes for the longest length/ + // distance pair plus four bytes for overloading the bit buffer. + + function inflate_fast(bl, bd, tl, tl_index, td, td_index, s, z) { + var t; // temporary pointer + var tp; // temporary pointer + var tp_index; // temporary pointer + var e; // extra bits or operation + var b; // bit buffer + var k; // bits in bit buffer + var p; // input data pointer + var n; // bytes available there + var q; // output window write pointer + var m; // bytes to end of window or read pointer + var ml; // mask for literal/length tree + var md; // mask for distance tree + var c; // bytes to copy + var d; // distance back to copy from + var r; // copy source pointer + + var tp_index_t_3; // (tp_index+t)*3 + + // load input, output, bit values + p = z.next_in_index; + n = z.avail_in; + b = s.bitb; + k = s.bitk; + q = s.write; + m = q < s.read ? s.read - q - 1 : s.end - q; + + // initialize masks + ml = inflate_mask[bl]; + md = inflate_mask[bd]; + + // do until not enough input or output space for fast loop + do { // assume called with m >= 258 && n >= 10 + // get literal/length code + while (k < (20)) { // max bits for literal/length code + n--; + b |= (z.read_byte(p++) & 0xff) << k; + k += 8; + } + + t = b & ml; + tp = tl; + tp_index = tl_index; + tp_index_t_3 = (tp_index + t) * 3; + if ((e = tp[tp_index_t_3]) === 0) { + b >>= (tp[tp_index_t_3 + 1]); + k -= (tp[tp_index_t_3 + 1]); + + s.window[q++] = /* (byte) */tp[tp_index_t_3 + 2]; + m--; + continue; + } + do { + + b >>= (tp[tp_index_t_3 + 1]); + k -= (tp[tp_index_t_3 + 1]); + + if ((e & 16) !== 0) { + e &= 15; + c = tp[tp_index_t_3 + 2] + (/* (int) */b & inflate_mask[e]); + + b >>= e; + k -= e; + + // decode distance base of block to copy + while (k < (15)) { // max bits for distance code + n--; + b |= (z.read_byte(p++) & 0xff) << k; + k += 8; + } + + t = b & md; + tp = td; + tp_index = td_index; + tp_index_t_3 = (tp_index + t) * 3; + e = tp[tp_index_t_3]; + + do { + + b >>= (tp[tp_index_t_3 + 1]); + k -= (tp[tp_index_t_3 + 1]); + + if ((e & 16) !== 0) { + // get extra bits to add to distance base + e &= 15; + while (k < (e)) { // get extra bits (up to 13) + n--; + b |= (z.read_byte(p++) & 0xff) << k; + k += 8; + } + + d = tp[tp_index_t_3 + 2] + (b & inflate_mask[e]); + + b >>= (e); + k -= (e); + + // do the copy + m -= c; + if (q >= d) { // offset before dest + // just copy + r = q - d; + if (q - r > 0 && 2 > (q - r)) { + s.window[q++] = s.window[r++]; // minimum + // count is + // three, + s.window[q++] = s.window[r++]; // so unroll + // loop a + // little + c -= 2; + } else { + s.window.set(s.window.subarray(r, r + 2), q); + q += 2; + r += 2; + c -= 2; + } + } else { // else offset after destination + r = q - d; + do { + r += s.end; // force pointer in window + } while (r < 0); // covers invalid distances + e = s.end - r; + if (c > e) { // if source crosses, + c -= e; // wrapped copy + if (q - r > 0 && e > (q - r)) { + do { + s.window[q++] = s.window[r++]; + } while (--e !== 0); + } else { + s.window.set(s.window.subarray(r, r + e), q); + q += e; + r += e; + e = 0; + } + r = 0; // copy rest from start of window + } + + } + + // copy all or what's left + if (q - r > 0 && c > (q - r)) { + do { + s.window[q++] = s.window[r++]; + } while (--c !== 0); + } else { + s.window.set(s.window.subarray(r, r + c), q); + q += c; + r += c; + c = 0; + } + break; + } else if ((e & 64) === 0) { + t += tp[tp_index_t_3 + 2]; + t += (b & inflate_mask[e]); + tp_index_t_3 = (tp_index + t) * 3; + e = tp[tp_index_t_3]; + } else { + z.msg = "invalid distance code"; + + c = z.avail_in - n; + c = (k >> 3) < c ? k >> 3 : c; + n += c; + p -= c; + k -= c << 3; + + s.bitb = b; + s.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + s.write = q; + + return Z_DATA_ERROR; + } + } while (true); + break; + } + + if ((e & 64) === 0) { + t += tp[tp_index_t_3 + 2]; + t += (b & inflate_mask[e]); + tp_index_t_3 = (tp_index + t) * 3; + if ((e = tp[tp_index_t_3]) === 0) { + + b >>= (tp[tp_index_t_3 + 1]); + k -= (tp[tp_index_t_3 + 1]); + + s.window[q++] = /* (byte) */tp[tp_index_t_3 + 2]; + m--; + break; + } + } else if ((e & 32) !== 0) { + + c = z.avail_in - n; + c = (k >> 3) < c ? k >> 3 : c; + n += c; + p -= c; + k -= c << 3; + + s.bitb = b; + s.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + s.write = q; + + return Z_STREAM_END; + } else { + z.msg = "invalid literal/length code"; + + c = z.avail_in - n; + c = (k >> 3) < c ? k >> 3 : c; + n += c; + p -= c; + k -= c << 3; + + s.bitb = b; + s.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + s.write = q; + + return Z_DATA_ERROR; + } + } while (true); + } while (m >= 258 && n >= 10); + + // not enough input or output--restore pointers and return + c = z.avail_in - n; + c = (k >> 3) < c ? k >> 3 : c; + n += c; + p -= c; + k -= c << 3; + + s.bitb = b; + s.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + s.write = q; + + return Z_OK; + } + + that.init = function(bl, bd, tl, tl_index, td, td_index) { + mode = START; + lbits = /* (byte) */bl; + dbits = /* (byte) */bd; + ltree = tl; + ltree_index = tl_index; + dtree = td; + dtree_index = td_index; + tree = null; + }; + + that.proc = function(s, z, r) { + var j; // temporary storage + var tindex; // temporary pointer + var e; // extra bits or operation + var b = 0; // bit buffer + var k = 0; // bits in bit buffer + var p = 0; // input data pointer + var n; // bytes available there + var q; // output window write pointer + var m; // bytes to end of window or read pointer + var f; // pointer to copy strings from + + // copy input/output information to locals (UPDATE macro restores) + p = z.next_in_index; + n = z.avail_in; + b = s.bitb; + k = s.bitk; + q = s.write; + m = q < s.read ? s.read - q - 1 : s.end - q; + + // process input and output based on current state + while (true) { + switch (mode) { + // waiting for "i:"=input, "o:"=output, "x:"=nothing + case START: // x: set up for LEN + if (m >= 258 && n >= 10) { + + s.bitb = b; + s.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + s.write = q; + r = inflate_fast(lbits, dbits, ltree, ltree_index, dtree, dtree_index, s, z); + + p = z.next_in_index; + n = z.avail_in; + b = s.bitb; + k = s.bitk; + q = s.write; + m = q < s.read ? s.read - q - 1 : s.end - q; + + if (r != Z_OK) { + mode = r == Z_STREAM_END ? WASH : BADCODE; + break; + } + } + need = lbits; + tree = ltree; + tree_index = ltree_index; + + mode = LEN; + case LEN: // i: get length/literal/eob next + j = need; + + while (k < (j)) { + if (n !== 0) + r = Z_OK; + else { + + s.bitb = b; + s.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + s.write = q; + return s.inflate_flush(z, r); + } + n--; + b |= (z.read_byte(p++) & 0xff) << k; + k += 8; + } + + tindex = (tree_index + (b & inflate_mask[j])) * 3; + + b >>>= (tree[tindex + 1]); + k -= (tree[tindex + 1]); + + e = tree[tindex]; + + if (e === 0) { // literal + lit = tree[tindex + 2]; + mode = LIT; + break; + } + if ((e & 16) !== 0) { // length + get = e & 15; + len = tree[tindex + 2]; + mode = LENEXT; + break; + } + if ((e & 64) === 0) { // next table + need = e; + tree_index = tindex / 3 + tree[tindex + 2]; + break; + } + if ((e & 32) !== 0) { // end of block + mode = WASH; + break; + } + mode = BADCODE; // invalid code + z.msg = "invalid literal/length code"; + r = Z_DATA_ERROR; + + s.bitb = b; + s.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + s.write = q; + return s.inflate_flush(z, r); + + case LENEXT: // i: getting length extra (have base) + j = get; + + while (k < (j)) { + if (n !== 0) + r = Z_OK; + else { + + s.bitb = b; + s.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + s.write = q; + return s.inflate_flush(z, r); + } + n--; + b |= (z.read_byte(p++) & 0xff) << k; + k += 8; + } + + len += (b & inflate_mask[j]); + + b >>= j; + k -= j; + + need = dbits; + tree = dtree; + tree_index = dtree_index; + mode = DIST; + case DIST: // i: get distance next + j = need; + + while (k < (j)) { + if (n !== 0) + r = Z_OK; + else { + + s.bitb = b; + s.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + s.write = q; + return s.inflate_flush(z, r); + } + n--; + b |= (z.read_byte(p++) & 0xff) << k; + k += 8; + } + + tindex = (tree_index + (b & inflate_mask[j])) * 3; + + b >>= tree[tindex + 1]; + k -= tree[tindex + 1]; + + e = (tree[tindex]); + if ((e & 16) !== 0) { // distance + get = e & 15; + dist = tree[tindex + 2]; + mode = DISTEXT; + break; + } + if ((e & 64) === 0) { // next table + need = e; + tree_index = tindex / 3 + tree[tindex + 2]; + break; + } + mode = BADCODE; // invalid code + z.msg = "invalid distance code"; + r = Z_DATA_ERROR; + + s.bitb = b; + s.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + s.write = q; + return s.inflate_flush(z, r); + + case DISTEXT: // i: getting distance extra + j = get; + + while (k < (j)) { + if (n !== 0) + r = Z_OK; + else { + + s.bitb = b; + s.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + s.write = q; + return s.inflate_flush(z, r); + } + n--; + b |= (z.read_byte(p++) & 0xff) << k; + k += 8; + } + + dist += (b & inflate_mask[j]); + + b >>= j; + k -= j; + + mode = COPY; + case COPY: // o: copying bytes in window, waiting for space + f = q - dist; + while (f < 0) { // modulo window size-"while" instead + f += s.end; // of "if" handles invalid distances + } + while (len !== 0) { + + if (m === 0) { + if (q == s.end && s.read !== 0) { + q = 0; + m = q < s.read ? s.read - q - 1 : s.end - q; + } + if (m === 0) { + s.write = q; + r = s.inflate_flush(z, r); + q = s.write; + m = q < s.read ? s.read - q - 1 : s.end - q; + + if (q == s.end && s.read !== 0) { + q = 0; + m = q < s.read ? s.read - q - 1 : s.end - q; + } + + if (m === 0) { + s.bitb = b; + s.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + s.write = q; + return s.inflate_flush(z, r); + } + } + } + + s.window[q++] = s.window[f++]; + m--; + + if (f == s.end) + f = 0; + len--; + } + mode = START; + break; + case LIT: // o: got literal, waiting for output space + if (m === 0) { + if (q == s.end && s.read !== 0) { + q = 0; + m = q < s.read ? s.read - q - 1 : s.end - q; + } + if (m === 0) { + s.write = q; + r = s.inflate_flush(z, r); + q = s.write; + m = q < s.read ? s.read - q - 1 : s.end - q; + + if (q == s.end && s.read !== 0) { + q = 0; + m = q < s.read ? s.read - q - 1 : s.end - q; + } + if (m === 0) { + s.bitb = b; + s.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + s.write = q; + return s.inflate_flush(z, r); + } + } + } + r = Z_OK; + + s.window[q++] = /* (byte) */lit; + m--; + + mode = START; + break; + case WASH: // o: got eob, possibly more output + if (k > 7) { // return unused byte, if any + k -= 8; + n++; + p--; // can always return one + } + + s.write = q; + r = s.inflate_flush(z, r); + q = s.write; + m = q < s.read ? s.read - q - 1 : s.end - q; + + if (s.read != s.write) { + s.bitb = b; + s.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + s.write = q; + return s.inflate_flush(z, r); + } + mode = END; + case END: + r = Z_STREAM_END; + s.bitb = b; + s.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + s.write = q; + return s.inflate_flush(z, r); + + case BADCODE: // x: got error + + r = Z_DATA_ERROR; + + s.bitb = b; + s.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + s.write = q; + return s.inflate_flush(z, r); + + default: + r = Z_STREAM_ERROR; + + s.bitb = b; + s.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + s.write = q; + return s.inflate_flush(z, r); + } + } + }; + + that.free = function() { + // ZFREE(z, c); + }; + + } + + // InfBlocks + + // Table for deflate from PKZIP's appnote.txt. + var border = [ // Order of the bit length code lengths + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ]; + + var TYPE = 0; // get type bits (3, including end bit) + var LENS = 1; // get lengths for stored + var STORED = 2;// processing stored block + var TABLE = 3; // get table lengths + var BTREE = 4; // get bit lengths tree for a dynamic + // block + var DTREE = 5; // get length, distance trees for a + // dynamic block + var CODES = 6; // processing fixed or dynamic block + var DRY = 7; // output remaining window bytes + var DONELOCKS = 8; // finished last block, done + var BADBLOCKS = 9; // ot a data error--stuck here + + function InfBlocks(z, w) { + var that = this; + + var mode = TYPE; // current inflate_block mode + + var left = 0; // if STORED, bytes left to copy + + var table = 0; // table lengths (14 bits) + var index = 0; // index into blens (or border) + var blens; // bit lengths of codes + var bb = [ 0 ]; // bit length tree depth + var tb = [ 0 ]; // bit length decoding tree + + var codes = new InfCodes(); // if CODES, current state + + var last = 0; // true if this block is the last block + + var hufts = new Int32Array(MANY * 3); // single malloc for tree space + var check = 0; // check on output + var inftree = new InfTree(); + + that.bitk = 0; // bits in bit buffer + that.bitb = 0; // bit buffer + that.window = new Uint8Array(w); // sliding window + that.end = w; // one byte after sliding window + that.read = 0; // window read pointer + that.write = 0; // window write pointer + + that.reset = function(z, c) { + if (c) + c[0] = check; + // if (mode == BTREE || mode == DTREE) { + // } + if (mode == CODES) { + codes.free(z); + } + mode = TYPE; + that.bitk = 0; + that.bitb = 0; + that.read = that.write = 0; + }; + + that.reset(z, null); + + // copy as much as possible from the sliding window to the output area + that.inflate_flush = function(z, r) { + var n; + var p; + var q; + + // local copies of source and destination pointers + p = z.next_out_index; + q = that.read; + + // compute number of bytes to copy as far as end of window + n = /* (int) */((q <= that.write ? that.write : that.end) - q); + if (n > z.avail_out) + n = z.avail_out; + if (n !== 0 && r == Z_BUF_ERROR) + r = Z_OK; + + // update counters + z.avail_out -= n; + z.total_out += n; + + // copy as far as end of window + z.next_out.set(that.window.subarray(q, q + n), p); + p += n; + q += n; + + // see if more to copy at beginning of window + if (q == that.end) { + // wrap pointers + q = 0; + if (that.write == that.end) + that.write = 0; + + // compute bytes to copy + n = that.write - q; + if (n > z.avail_out) + n = z.avail_out; + if (n !== 0 && r == Z_BUF_ERROR) + r = Z_OK; + + // update counters + z.avail_out -= n; + z.total_out += n; + + // copy + z.next_out.set(that.window.subarray(q, q + n), p); + p += n; + q += n; + } + + // update pointers + z.next_out_index = p; + that.read = q; + + // done + return r; + }; + + that.proc = function(z, r) { + var t; // temporary storage + var b; // bit buffer + var k; // bits in bit buffer + var p; // input data pointer + var n; // bytes available there + var q; // output window write pointer + var m; // bytes to end of window or read pointer + + var i; + + // copy input/output information to locals (UPDATE macro restores) + // { + p = z.next_in_index; + n = z.avail_in; + b = that.bitb; + k = that.bitk; + // } + // { + q = that.write; + m = /* (int) */(q < that.read ? that.read - q - 1 : that.end - q); + // } + + // process input based on current state + // DEBUG dtree + while (true) { + switch (mode) { + case TYPE: + + while (k < (3)) { + if (n !== 0) { + r = Z_OK; + } else { + that.bitb = b; + that.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + that.write = q; + return that.inflate_flush(z, r); + } + n--; + b |= (z.read_byte(p++) & 0xff) << k; + k += 8; + } + t = /* (int) */(b & 7); + last = t & 1; + + switch (t >>> 1) { + case 0: // stored + // { + b >>>= (3); + k -= (3); + // } + t = k & 7; // go to byte boundary + + // { + b >>>= (t); + k -= (t); + // } + mode = LENS; // get length of stored block + break; + case 1: // fixed + // { + var bl = []; // new Array(1); + var bd = []; // new Array(1); + var tl = [ [] ]; // new Array(1); + var td = [ [] ]; // new Array(1); + + InfTree.inflate_trees_fixed(bl, bd, tl, td); + codes.init(bl[0], bd[0], tl[0], 0, td[0], 0); + // } + + // { + b >>>= (3); + k -= (3); + // } + + mode = CODES; + break; + case 2: // dynamic + + // { + b >>>= (3); + k -= (3); + // } + + mode = TABLE; + break; + case 3: // illegal + + // { + b >>>= (3); + k -= (3); + // } + mode = BADBLOCKS; + z.msg = "invalid block type"; + r = Z_DATA_ERROR; + + that.bitb = b; + that.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + that.write = q; + return that.inflate_flush(z, r); + } + break; + case LENS: + + while (k < (32)) { + if (n !== 0) { + r = Z_OK; + } else { + that.bitb = b; + that.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + that.write = q; + return that.inflate_flush(z, r); + } + n--; + b |= (z.read_byte(p++) & 0xff) << k; + k += 8; + } + + if ((((~b) >>> 16) & 0xffff) != (b & 0xffff)) { + mode = BADBLOCKS; + z.msg = "invalid stored block lengths"; + r = Z_DATA_ERROR; + + that.bitb = b; + that.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + that.write = q; + return that.inflate_flush(z, r); + } + left = (b & 0xffff); + b = k = 0; // dump bits + mode = left !== 0 ? STORED : (last !== 0 ? DRY : TYPE); + break; + case STORED: + if (n === 0) { + that.bitb = b; + that.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + that.write = q; + return that.inflate_flush(z, r); + } + + if (m === 0) { + if (q == that.end && that.read !== 0) { + q = 0; + m = /* (int) */(q < that.read ? that.read - q - 1 : that.end - q); + } + if (m === 0) { + that.write = q; + r = that.inflate_flush(z, r); + q = that.write; + m = /* (int) */(q < that.read ? that.read - q - 1 : that.end - q); + if (q == that.end && that.read !== 0) { + q = 0; + m = /* (int) */(q < that.read ? that.read - q - 1 : that.end - q); + } + if (m === 0) { + that.bitb = b; + that.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + that.write = q; + return that.inflate_flush(z, r); + } + } + } + r = Z_OK; + + t = left; + if (t > n) + t = n; + if (t > m) + t = m; + that.window.set(z.read_buf(p, t), q); + p += t; + n -= t; + q += t; + m -= t; + if ((left -= t) !== 0) + break; + mode = last !== 0 ? DRY : TYPE; + break; + case TABLE: + + while (k < (14)) { + if (n !== 0) { + r = Z_OK; + } else { + that.bitb = b; + that.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + that.write = q; + return that.inflate_flush(z, r); + } + + n--; + b |= (z.read_byte(p++) & 0xff) << k; + k += 8; + } + + table = t = (b & 0x3fff); + if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) { + mode = BADBLOCKS; + z.msg = "too many length or distance symbols"; + r = Z_DATA_ERROR; + + that.bitb = b; + that.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + that.write = q; + return that.inflate_flush(z, r); + } + t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); + if (!blens || blens.length < t) { + blens = []; // new Array(t); + } else { + for (i = 0; i < t; i++) { + blens[i] = 0; + } + } + + // { + b >>>= (14); + k -= (14); + // } + + index = 0; + mode = BTREE; + case BTREE: + while (index < 4 + (table >>> 10)) { + while (k < (3)) { + if (n !== 0) { + r = Z_OK; + } else { + that.bitb = b; + that.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + that.write = q; + return that.inflate_flush(z, r); + } + n--; + b |= (z.read_byte(p++) & 0xff) << k; + k += 8; + } + + blens[border[index++]] = b & 7; + + // { + b >>>= (3); + k -= (3); + // } + } + + while (index < 19) { + blens[border[index++]] = 0; + } + + bb[0] = 7; + t = inftree.inflate_trees_bits(blens, bb, tb, hufts, z); + if (t != Z_OK) { + r = t; + if (r == Z_DATA_ERROR) { + blens = null; + mode = BADBLOCKS; + } + + that.bitb = b; + that.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + that.write = q; + return that.inflate_flush(z, r); + } + + index = 0; + mode = DTREE; + case DTREE: + while (true) { + t = table; + if (!(index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))) { + break; + } + + var j, c; + + t = bb[0]; + + while (k < (t)) { + if (n !== 0) { + r = Z_OK; + } else { + that.bitb = b; + that.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + that.write = q; + return that.inflate_flush(z, r); + } + n--; + b |= (z.read_byte(p++) & 0xff) << k; + k += 8; + } + + // if (tb[0] == -1) { + // System.err.println("null..."); + // } + + t = hufts[(tb[0] + (b & inflate_mask[t])) * 3 + 1]; + c = hufts[(tb[0] + (b & inflate_mask[t])) * 3 + 2]; + + if (c < 16) { + b >>>= (t); + k -= (t); + blens[index++] = c; + } else { // c == 16..18 + i = c == 18 ? 7 : c - 14; + j = c == 18 ? 11 : 3; + + while (k < (t + i)) { + if (n !== 0) { + r = Z_OK; + } else { + that.bitb = b; + that.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + that.write = q; + return that.inflate_flush(z, r); + } + n--; + b |= (z.read_byte(p++) & 0xff) << k; + k += 8; + } + + b >>>= (t); + k -= (t); + + j += (b & inflate_mask[i]); + + b >>>= (i); + k -= (i); + + i = index; + t = table; + if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || (c == 16 && i < 1)) { + blens = null; + mode = BADBLOCKS; + z.msg = "invalid bit length repeat"; + r = Z_DATA_ERROR; + + that.bitb = b; + that.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + that.write = q; + return that.inflate_flush(z, r); + } + + c = c == 16 ? blens[i - 1] : 0; + do { + blens[i++] = c; + } while (--j !== 0); + index = i; + } + } + + tb[0] = -1; + // { + var bl_ = []; // new Array(1); + var bd_ = []; // new Array(1); + var tl_ = []; // new Array(1); + var td_ = []; // new Array(1); + bl_[0] = 9; // must be <= 9 for lookahead assumptions + bd_[0] = 6; // must be <= 9 for lookahead assumptions + + t = table; + t = inftree.inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), blens, bl_, bd_, tl_, td_, hufts, z); + + if (t != Z_OK) { + if (t == Z_DATA_ERROR) { + blens = null; + mode = BADBLOCKS; + } + r = t; + + that.bitb = b; + that.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + that.write = q; + return that.inflate_flush(z, r); + } + codes.init(bl_[0], bd_[0], hufts, tl_[0], hufts, td_[0]); + // } + mode = CODES; + case CODES: + that.bitb = b; + that.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + that.write = q; + + if ((r = codes.proc(that, z, r)) != Z_STREAM_END) { + return that.inflate_flush(z, r); + } + r = Z_OK; + codes.free(z); + + p = z.next_in_index; + n = z.avail_in; + b = that.bitb; + k = that.bitk; + q = that.write; + m = /* (int) */(q < that.read ? that.read - q - 1 : that.end - q); + + if (last === 0) { + mode = TYPE; + break; + } + mode = DRY; + case DRY: + that.write = q; + r = that.inflate_flush(z, r); + q = that.write; + m = /* (int) */(q < that.read ? that.read - q - 1 : that.end - q); + if (that.read != that.write) { + that.bitb = b; + that.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + that.write = q; + return that.inflate_flush(z, r); + } + mode = DONELOCKS; + case DONELOCKS: + r = Z_STREAM_END; + + that.bitb = b; + that.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + that.write = q; + return that.inflate_flush(z, r); + case BADBLOCKS: + r = Z_DATA_ERROR; + + that.bitb = b; + that.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + that.write = q; + return that.inflate_flush(z, r); + + default: + r = Z_STREAM_ERROR; + + that.bitb = b; + that.bitk = k; + z.avail_in = n; + z.total_in += p - z.next_in_index; + z.next_in_index = p; + that.write = q; + return that.inflate_flush(z, r); + } + } + }; + + that.free = function(z) { + that.reset(z, null); + that.window = null; + hufts = null; + // ZFREE(z, s); + }; + + that.set_dictionary = function(d, start, n) { + that.window.set(d.subarray(start, start + n), 0); + that.read = that.write = n; + }; + + // Returns true if inflate is currently at the end of a block generated + // by Z_SYNC_FLUSH or Z_FULL_FLUSH. + that.sync_point = function() { + return mode == LENS ? 1 : 0; + }; + + } + + // Inflate + + // preset dictionary flag in zlib header + var PRESET_DICT = 0x20; + + var Z_DEFLATED = 8; + + var METHOD = 0; // waiting for method byte + var FLAG = 1; // waiting for flag byte + var DICT4 = 2; // four dictionary check bytes to go + var DICT3 = 3; // three dictionary check bytes to go + var DICT2 = 4; // two dictionary check bytes to go + var DICT1 = 5; // one dictionary check byte to go + var DICT0 = 6; // waiting for inflateSetDictionary + var BLOCKS = 7; // decompressing blocks + var DONE = 12; // finished check, done + var BAD = 13; // got an error--stay here + + var mark = [ 0, 0, 0xff, 0xff ]; + + function Inflate() { + var that = this; + + that.mode = 0; // current inflate mode + + // mode dependent information + that.method = 0; // if FLAGS, method byte + + // if CHECK, check values to compare + that.was = [ 0 ]; // new Array(1); // computed check value + that.need = 0; // stream check value + + // if BAD, inflateSync's marker bytes count + that.marker = 0; + + // mode independent information + that.wbits = 0; // log2(window size) (8..15, defaults to 15) + + // this.blocks; // current inflate_blocks state + + function inflateReset(z) { + if (!z || !z.istate) + return Z_STREAM_ERROR; + + z.total_in = z.total_out = 0; + z.msg = null; + z.istate.mode = BLOCKS; + z.istate.blocks.reset(z, null); + return Z_OK; + } + + that.inflateEnd = function(z) { + if (that.blocks) + that.blocks.free(z); + that.blocks = null; + // ZFREE(z, z->state); + return Z_OK; + }; + + that.inflateInit = function(z, w) { + z.msg = null; + that.blocks = null; + + // set window size + if (w < 8 || w > 15) { + that.inflateEnd(z); + return Z_STREAM_ERROR; + } + that.wbits = w; + + z.istate.blocks = new InfBlocks(z, 1 << w); + + // reset state + inflateReset(z); + return Z_OK; + }; + + that.inflate = function(z, f) { + var r; + var b; + + if (!z || !z.istate || !z.next_in) + return Z_STREAM_ERROR; + f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK; + r = Z_BUF_ERROR; + while (true) { + // System.out.println("mode: "+z.istate.mode); + switch (z.istate.mode) { + case METHOD: + + if (z.avail_in === 0) + return r; + r = f; + + z.avail_in--; + z.total_in++; + if (((z.istate.method = z.read_byte(z.next_in_index++)) & 0xf) != Z_DEFLATED) { + z.istate.mode = BAD; + z.msg = "unknown compression method"; + z.istate.marker = 5; // can't try inflateSync + break; + } + if ((z.istate.method >> 4) + 8 > z.istate.wbits) { + z.istate.mode = BAD; + z.msg = "invalid window size"; + z.istate.marker = 5; // can't try inflateSync + break; + } + z.istate.mode = FLAG; + case FLAG: + + if (z.avail_in === 0) + return r; + r = f; + + z.avail_in--; + z.total_in++; + b = (z.read_byte(z.next_in_index++)) & 0xff; + + if ((((z.istate.method << 8) + b) % 31) !== 0) { + z.istate.mode = BAD; + z.msg = "incorrect header check"; + z.istate.marker = 5; // can't try inflateSync + break; + } + + if ((b & PRESET_DICT) === 0) { + z.istate.mode = BLOCKS; + break; + } + z.istate.mode = DICT4; + case DICT4: + + if (z.avail_in === 0) + return r; + r = f; + + z.avail_in--; + z.total_in++; + z.istate.need = ((z.read_byte(z.next_in_index++) & 0xff) << 24) & 0xff000000; + z.istate.mode = DICT3; + case DICT3: + + if (z.avail_in === 0) + return r; + r = f; + + z.avail_in--; + z.total_in++; + z.istate.need += ((z.read_byte(z.next_in_index++) & 0xff) << 16) & 0xff0000; + z.istate.mode = DICT2; + case DICT2: + + if (z.avail_in === 0) + return r; + r = f; + + z.avail_in--; + z.total_in++; + z.istate.need += ((z.read_byte(z.next_in_index++) & 0xff) << 8) & 0xff00; + z.istate.mode = DICT1; + case DICT1: + + if (z.avail_in === 0) + return r; + r = f; + + z.avail_in--; + z.total_in++; + z.istate.need += (z.read_byte(z.next_in_index++) & 0xff); + z.istate.mode = DICT0; + return Z_NEED_DICT; + case DICT0: + z.istate.mode = BAD; + z.msg = "need dictionary"; + z.istate.marker = 0; // can try inflateSync + return Z_STREAM_ERROR; + case BLOCKS: + + r = z.istate.blocks.proc(z, r); + if (r == Z_DATA_ERROR) { + z.istate.mode = BAD; + z.istate.marker = 0; // can try inflateSync + break; + } + if (r == Z_OK) { + r = f; + } + if (r != Z_STREAM_END) { + return r; + } + r = f; + z.istate.blocks.reset(z, z.istate.was); + z.istate.mode = DONE; + case DONE: + return Z_STREAM_END; + case BAD: + return Z_DATA_ERROR; + default: + return Z_STREAM_ERROR; + } + } + }; + + that.inflateSetDictionary = function(z, dictionary, dictLength) { + var index = 0; + var length = dictLength; + if (!z || !z.istate || z.istate.mode != DICT0) + return Z_STREAM_ERROR; + + if (length >= (1 << z.istate.wbits)) { + length = (1 << z.istate.wbits) - 1; + index = dictLength - length; + } + z.istate.blocks.set_dictionary(dictionary, index, length); + z.istate.mode = BLOCKS; + return Z_OK; + }; + + that.inflateSync = function(z) { + var n; // number of bytes to look at + var p; // pointer to bytes + var m; // number of marker bytes found in a row + var r, w; // temporaries to save total_in and total_out + + // set up + if (!z || !z.istate) + return Z_STREAM_ERROR; + if (z.istate.mode != BAD) { + z.istate.mode = BAD; + z.istate.marker = 0; + } + if ((n = z.avail_in) === 0) + return Z_BUF_ERROR; + p = z.next_in_index; + m = z.istate.marker; + + // search + while (n !== 0 && m < 4) { + if (z.read_byte(p) == mark[m]) { + m++; + } else if (z.read_byte(p) !== 0) { + m = 0; + } else { + m = 4 - m; + } + p++; + n--; + } + + // restore + z.total_in += p - z.next_in_index; + z.next_in_index = p; + z.avail_in = n; + z.istate.marker = m; + + // return no joy or set up to restart on a new block + if (m != 4) { + return Z_DATA_ERROR; + } + r = z.total_in; + w = z.total_out; + inflateReset(z); + z.total_in = r; + z.total_out = w; + z.istate.mode = BLOCKS; + return Z_OK; + }; + + // Returns true if inflate is currently at the end of a block generated + // by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + // implementation to provide an additional safety check. PPP uses + // Z_SYNC_FLUSH + // but removes the length bytes of the resulting empty stored block. When + // decompressing, PPP checks that at the end of input packet, inflate is + // waiting for these length bytes. + that.inflateSyncPoint = function(z) { + if (!z || !z.istate || !z.istate.blocks) + return Z_STREAM_ERROR; + return z.istate.blocks.sync_point(); + }; + } + + // ZStream + + function ZStream() { + } + + ZStream.prototype = { + inflateInit : function(bits) { + var that = this; + that.istate = new Inflate(); + if (!bits) + bits = MAX_BITS; + return that.istate.inflateInit(that, bits); + }, + + inflate : function(f) { + var that = this; + if (!that.istate) + return Z_STREAM_ERROR; + return that.istate.inflate(that, f); + }, + + inflateEnd : function() { + var that = this; + if (!that.istate) + return Z_STREAM_ERROR; + var ret = that.istate.inflateEnd(that); + that.istate = null; + return ret; + }, + + inflateSync : function() { + var that = this; + if (!that.istate) + return Z_STREAM_ERROR; + return that.istate.inflateSync(that); + }, + inflateSetDictionary : function(dictionary, dictLength) { + var that = this; + if (!that.istate) + return Z_STREAM_ERROR; + return that.istate.inflateSetDictionary(that, dictionary, dictLength); + }, + read_byte : function(start) { + var that = this; + return that.next_in.subarray(start, start + 1)[0]; + }, + read_buf : function(start, size) { + var that = this; + return that.next_in.subarray(start, start + size); + } + }; + + // Inflater + + function Inflater() { + var that = this; + var z = new ZStream(); + var bufsize = 512; + var flush = Z_NO_FLUSH; + var buf = new Uint8Array(bufsize); + var nomoreinput = false; + + z.inflateInit(); + z.next_out = buf; + + that.append = function(data, onprogress) { + var err, buffers = [], lastIndex = 0, bufferIndex = 0, bufferSize = 0, array; + if (data.length === 0) + return; + z.next_in_index = 0; + z.next_in = data; + z.avail_in = data.length; + do { + z.next_out_index = 0; + z.avail_out = bufsize; + if ((z.avail_in === 0) && (!nomoreinput)) { // if buffer is empty and more input is available, refill it + z.next_in_index = 0; + nomoreinput = true; + } + err = z.inflate(flush); + if (nomoreinput && (err == Z_BUF_ERROR)) + return -1; + if (err != Z_OK && err != Z_STREAM_END) + throw "inflating: " + z.msg; + if ((nomoreinput || err == Z_STREAM_END) && (z.avail_in == data.length)) + return -1; + if (z.next_out_index) + if (z.next_out_index == bufsize) + buffers.push(new Uint8Array(buf)); + else + buffers.push(new Uint8Array(buf.subarray(0, z.next_out_index))); + bufferSize += z.next_out_index; + if (onprogress && z.next_in_index > 0 && z.next_in_index != lastIndex) { + onprogress(z.next_in_index); + lastIndex = z.next_in_index; + } + } while (z.avail_in > 0 || z.avail_out === 0); + array = new Uint8Array(bufferSize); + buffers.forEach(function(chunk) { + array.set(chunk, bufferIndex); + bufferIndex += chunk.length; + }); + return array; + }; + that.flush = function() { + z.inflateEnd(); + }; + } + + var inflater; + + if (obj.zip) + obj.zip.Inflater = Inflater; + else { + inflater = new Inflater(); + obj.addEventListener("message", function(event) { + var message = event.data; + + if (message.append) + obj.postMessage({ + onappend : true, + data : inflater.append(message.data, function(current) { + obj.postMessage({ + progress : true, + current : current + }); + }) + }); + if (message.flush) { + inflater.flush(); + obj.postMessage({ + onflush : true + }); + } + }, false); + } + +}; + +// @agup +// Convert the inflate library to a blobURL +O.esri.TPK.___test = O.esri.TPK.inflate.toString(); + +O.esri.TPK.___blobURL = URL.createObjectURL( + new Blob([ + '(', + O.esri.TPK.___test, + ')(this)'], + {type: 'application/javascript'} + ) +) + +O.esri.zip.workerScriptsPath = O.esri.TPK.___blobURL; + //https://github.com/abdmob/x2js/blob/master/xml2json.js /* Copyright 2011-2013 Abdulla Abdurakhmanov diff --git a/lib/edit/offlineFeaturesManager.js b/lib/edit/offlineFeaturesManager.js index d945a1a..ffadc4b 100644 --- a/lib/edit/offlineFeaturesManager.js +++ b/lib/edit/offlineFeaturesManager.js @@ -9,6 +9,7 @@ define([ "dojo/dom-style", "dojo/query", "esri/config", + "esri/kernel", "esri/layers/GraphicsLayer", "esri/graphic", "esri/request", @@ -17,7 +18,7 @@ define([ "esri/symbols/SimpleFillSymbol", "esri/urlUtils"], function (Evented, Deferred, all, declare, array, domAttr, domStyle, query, - esriConfig, GraphicsLayer, Graphic, esriRequest, SimpleMarkerSymbol, SimpleLineSymbol, SimpleFillSymbol, urlUtils) { + esriConfig, kernel, GraphicsLayer, Graphic, esriRequest, SimpleMarkerSymbol, SimpleLineSymbol, SimpleFillSymbol, urlUtils) { "use strict"; return declare("O.esri.Edit.OfflineFeaturesManager", [Evented], { @@ -2104,6 +2105,11 @@ define([ a = "&adds=" + JSON.stringify((adds)); } if(updates.length > 0) { + array.forEach(updates, function(update){ + if(update.hasOwnProperty("infoTemplate")){ // if the update has an infoTemplate attached, + delete update.infoTemplate; // delete it to reduce payload size. + } + }, this); u = "&updates=" + JSON.stringify(updates); } if(deletes.length > 0) { @@ -2113,6 +2119,16 @@ define([ var params = f + a + u + d; + if(kernel.hasOwnProperty("id")){ // if there are credentials stored + if(kernel.id.hasOwnProperty("credentials")){ // within the kernel object, + array.forEach(kernel.id.credentials, function(credential){ // go thru all of them, + if(credential.server === url.split("/", 3).join("/")){ // find the credential that lines up with the server our feature is on, + params = params + "&token=" + credential.token; // and then append the token to the params. + } + }, this); + } + } + var req = new XMLHttpRequest(); req.open("POST", url + "/applyEdits", true); req.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); @@ -2125,14 +2141,15 @@ define([ callback(obj.addResults, obj.updateResults, obj.deleteResults); } catch(err) { - errback("Unable to parse xhr response"); + console.error("EDIT REQUEST REPONSE WAS NOT SUCCESSFUL:", req); + errback("Unable to parse xhr response", req); } } }; req.onerror = function(e) { - console.log("_makeEditRequest failed: " + e); + console.error("_makeEditRequest failed: " + e); errback(e); }; req.ontimeout = function() { diff --git a/package.json b/package.json index b9084ca..3e8fbae 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "offline-editor-js", - "version": "2.11.0.1", + "version": "2.12.0", "description": "Lightweight set of libraries for working offline with map tiles and ArcGIS feature services", "author": "Andy Gup (http://blog.andygup.net)", "license": "Apache 2", diff --git a/samples/package.json b/samples/package.json index 2afd314..00c9b9e 100644 --- a/samples/package.json +++ b/samples/package.json @@ -9,7 +9,7 @@ "appHomePage": "appcache-tiles.html", "optimizedApiURL": "../samples/jsolib", "arcGISBaseURL": "http://js.arcgis.com/3.14", - "version": "2.11.0.1", + "version": "2.12.0", "private": true, "description": "manifest generator project", "repository": {