├── .bowerrc ├── .gitignore ├── .ruby-gemset ├── .ruby-version ├── Gemfile ├── Gemfile.lock ├── Gruntfile.coffee ├── README.md ├── app ├── environments │ ├── development.coffee │ └── production.coffee ├── images │ └── apple-touch-icon.png ├── includes │ ├── analytics.html │ ├── head.html │ └── javascripts.html ├── index.html ├── javascripts │ ├── application.coffee │ ├── collections │ │ └── ServicesCollection.coffee │ ├── helpers │ │ └── handlebars_helpers.coffee │ ├── initialize.coffee │ ├── mixins │ │ └── application_mixins.coffee │ ├── models │ │ ├── PhraseModel.coffee │ │ ├── ServiceModel.coffee │ │ └── SettingsModel.coffee │ ├── routers │ │ └── ApplicationRouter.coffee │ ├── utils │ │ ├── DropboxClient.coffee │ │ ├── Generator.coffee │ │ ├── Shortcuts.coffee │ │ ├── Storage.coffee │ │ └── Vault.coffee │ └── views │ │ ├── AppNoticeView.coffee │ │ ├── ApplicationView.coffee │ │ ├── BeerView.coffee │ │ ├── FooterView.coffee │ │ ├── GeneratorView.coffee │ │ ├── HelpView.coffee │ │ ├── PhraseView.coffee │ │ ├── RootView.coffee │ │ ├── ServiceView.coffee │ │ ├── ServicesView.coffee │ │ ├── SettingsView.coffee │ │ ├── ShortcutsView.coffee │ │ ├── SidebarTabsView.coffee │ │ ├── SidebarView.coffee │ │ ├── SuggestionsView.coffee │ │ └── WelcomeView.coffee ├── stylesheets │ ├── _alert.scss │ ├── _footer.scss │ ├── _generator.scss │ ├── _layout.scss │ ├── _mixins.scss │ ├── _services.scss │ ├── _settings.scss │ ├── _shortcuts.scss │ ├── _sidebar.scss │ ├── _stats.scss │ ├── _suggestions.scss │ ├── _twitter_typeahead.scss │ ├── _ui.scss │ ├── _variables.scss │ ├── _welcome.scss │ └── application.scss └── templates │ ├── _primary_nav.hbs │ ├── app_notice.hbs │ ├── application.hbs │ ├── beer.hbs │ ├── footer.hbs │ ├── generator.hbs │ ├── help.hbs │ ├── no_results.hbs │ ├── phrase.hbs │ ├── service.hbs │ ├── settings.hbs │ ├── shortcuts.hbs │ ├── sidebar.hbs │ ├── sidebar_tabs_view.hbs │ ├── suggestions.hbs │ ├── toggle.hbs │ └── welcome.hbs ├── bower.json ├── package.json ├── planning.txt ├── todo.txt └── vendor └── javascripts ├── backbone.shortcuts.js └── dropbox-datastores-1.2.0.js /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## MAC OS 2 | .DS_Store 3 | 4 | ## TEXTMATE 5 | *.tmproj 6 | tmtags 7 | 8 | ## EMACS 9 | *~ 10 | \#* 11 | .\#* 12 | 13 | ## VIM 14 | *.swp 15 | 16 | ## PROJECT::GENERAL 17 | .sass-cache 18 | coverage 19 | rdoc 20 | pkg 21 | 22 | bower_components 23 | node_modules 24 | dist 25 | .tmp 26 | 27 | s3.json 28 | -------------------------------------------------------------------------------- /.ruby-gemset: -------------------------------------------------------------------------------- 1 | cassidy 2 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 2.3.0 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "compass" 4 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | chunky_png (1.3.1) 5 | compass (1.0.1) 6 | chunky_png (~> 1.2) 7 | compass-core (~> 1.0.1) 8 | compass-import-once (~> 1.0.5) 9 | rb-fsevent (>= 0.9.3) 10 | rb-inotify (>= 0.9) 11 | sass (>= 3.3.13, < 3.5) 12 | compass-core (1.0.1) 13 | multi_json (~> 1.0) 14 | sass (>= 3.3.0, < 3.5) 15 | compass-import-once (1.0.5) 16 | sass (>= 3.2, < 3.5) 17 | ffi (1.9.3) 18 | multi_json (1.10.1) 19 | rb-fsevent (0.9.4) 20 | rb-inotify (0.9.5) 21 | ffi (>= 0.5.0) 22 | sass (3.4.2) 23 | 24 | PLATFORMS 25 | ruby 26 | 27 | DEPENDENCIES 28 | compass 29 | -------------------------------------------------------------------------------- /Gruntfile.coffee: -------------------------------------------------------------------------------- 1 | _ = require('lodash') 2 | glob = require('glob') 3 | 4 | module.exports = (grunt) -> 5 | require('load-grunt-tasks')(grunt) 6 | 7 | config = 8 | pkg: grunt.file.readJSON('package.json') 9 | aws: { 10 | key: process.env.S3_KEY 11 | secret: process.env.S3_SECRET 12 | bucket: process.env.S3_BUCKET 13 | distribution: process.env.S3_DISTRIBUTION 14 | } 15 | env: grunt.option('e') or 'development' 16 | 17 | s3: 18 | options: 19 | accessKeyId: '<%= aws.key %>' 20 | secretAccessKey: '<%= aws.secret %>' 21 | bucket: '<%= aws.bucket %>' 22 | access: 'public-read' 23 | headers: 24 | CacheControl: 7200 25 | 26 | production: 27 | cwd: 'dist' 28 | src: '**/*' 29 | options: 30 | gzip: true 31 | 32 | cloudfront: 33 | options: 34 | accessKeyId: '<%= aws.key %>' 35 | secretAccessKey: '<%= aws.secret %>' 36 | distributionId: '<%= aws.distribution %>' 37 | invalidations: _(glob.sync('dist/**/*.{html,png,appcache}')).map((f) -> 38 | "/#{f}").value() 39 | 40 | watch: 41 | options: 42 | livereload: true 43 | files: ['.tmp/**/*', 'Gruntfile*'] 44 | 45 | gruntfile: 46 | files: 'Gruntfile*' 47 | 48 | html: 49 | files: 'app/**/*.html' 50 | tasks: 'includereplace' 51 | 52 | images: 53 | files: 'app/images/*' 54 | tasks: 'copy:images' 55 | 56 | scripts: 57 | files: 'app/javascripts/**/*.coffee' 58 | tasks: ['coffee'] 59 | 60 | styles: 61 | files: 'app/stylesheets/**/*.scss' 62 | tasks: ['compass'] 63 | 64 | templates: 65 | files: 'app/templates/**/*.hbs' 66 | tasks: ['handlebars'] 67 | 68 | handlebars: 69 | compile: 70 | options: 71 | namespace: "JST" 72 | processName: (filePath) -> 73 | filePath 74 | .replace('app/templates/', '') 75 | .replace('.hbs', '') 76 | 77 | files: 78 | ".tmp/javascripts/templates.js": [ 79 | "app/templates/*.hbs" 80 | ] 81 | 82 | coffee: 83 | compileBare: 84 | files: 85 | ".tmp/javascripts/application.js": [ 86 | 'app/javascripts/mixins/*.coffee' 87 | 'app/javascripts/application.coffee' 88 | 'app/environments/<%= env %>.coffee' 89 | 'app/javascripts/*.coffee' 90 | 'app/javascripts/utils/*.coffee' 91 | 'app/javascripts/routers/*.coffee' 92 | 'app/javascripts/models/*.coffee' 93 | 'app/javascripts/collections/*.coffee' 94 | 'app/javascripts/views/*.coffee' 95 | 'app/javascripts/helpers/*.coffee' 96 | 'app/javascripts/initialize.coffee' 97 | ] 98 | 99 | compass: 100 | options: 101 | importPath: [ 102 | 'bower_components' 103 | 'bower_components/bootstrap-sass/vendor/assets/stylesheets' 104 | ] 105 | sassDir: "app/stylesheets" 106 | 107 | main: 108 | options: 109 | cssDir: ".tmp/stylesheets" 110 | environment: 'development' 111 | 112 | dist: 113 | options: 114 | cssDir: "dist/stylesheets" 115 | environment: 'production' 116 | 117 | clean: 118 | dist: ['dist/*'] 119 | server: '.tmp' 120 | 121 | copy: 122 | fontawesome: 123 | expand: true 124 | cwd: 'bower_components/fontawesome/' 125 | dest: '.tmp' 126 | src: [ 127 | 'fonts/*' 128 | ] 129 | 130 | images: 131 | expand: true 132 | cwd: 'app/' 133 | dest: '.tmp' 134 | src: [ 135 | 'images/*' 136 | ] 137 | 138 | dist: 139 | expand: true 140 | cwd: '.tmp' 141 | dest: 'dist' 142 | src: [ 143 | 'fonts/*' 144 | 'images/*' 145 | '*.html' 146 | ] 147 | 148 | useminPrepare: 149 | options: 150 | dest: 'dist' 151 | root: '.tmp' 152 | html: '.tmp/*.html' 153 | 154 | usemin: 155 | html: 'dist/*.html' 156 | 157 | htmlmin: 158 | dist: 159 | options: 160 | removeComments: true, 161 | collapseWhitespace: true 162 | files: [ 163 | expand: true 164 | cwd: 'dist' 165 | src: '*.html' 166 | dest: 'dist' 167 | ] 168 | 169 | includereplace: 170 | html: 171 | options: 172 | includesDir: 'app/includes' 173 | prefix: '{% ' 174 | suffix: ' %}' 175 | 176 | files: [ 177 | expand: true 178 | flatten: true 179 | cwd: 'app' 180 | src: ['*.html'] 181 | dest: '.tmp/' 182 | ] 183 | 184 | rev: 185 | options: 186 | encoding: 'utf8', 187 | algorithm: 'md5', 188 | length: 8 189 | assets: 190 | files: 191 | src: ['dist/**/*.{js,css}'] 192 | 193 | appcache: 194 | options: 195 | basePath: 'dist' 196 | 197 | all: 198 | dest: 'dist/manifest.appcache' 199 | cache: 'dist/**/*' 200 | network: '*' 201 | 202 | connect: 203 | server: 204 | options: 205 | open: true 206 | base: '.tmp' 207 | livereload: true 208 | middleware: (connect) -> 209 | [ 210 | connect.static('.tmp') 211 | connect().use('/bower_components', connect.static('./bower_components')) 212 | connect().use('/node_modules', connect.static('./node_modules')) 213 | connect().use('/vendor', connect.static('./vendor')) 214 | ] 215 | 216 | dist: 217 | options: 218 | open: true 219 | keepalive: true 220 | base: 'dist' 221 | 222 | grunt.initConfig config 223 | 224 | grunt.registerTask 'default', [ 225 | 'compile' 226 | 'connect:server' 227 | 'watch' 228 | ] 229 | 230 | grunt.registerTask 'compile', [ 231 | 'handlebars' 232 | 'compass:main' 233 | 'coffee' 234 | 'includereplace' 235 | ] 236 | 237 | grunt.registerTask 'build', [ 238 | 'clean' 239 | 'copy:fontawesome' 240 | 'copy:images' 241 | 'includereplace' 242 | 'useminPrepare' 243 | 'handlebars' 244 | 'compass:dist' 245 | 'coffee' 246 | 'concat' 247 | 'uglify' 248 | 'copy:dist' 249 | 'rev' 250 | 'usemin' 251 | 'htmlmin' 252 | ] 253 | 254 | grunt.registerTask 'deploy', [ 255 | 'build' 256 | 's3:production' 257 | 'cloudfront' 258 | ] 259 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cassidy 2 | 3 | [http://cassidy.nicinabox.com](https://cassidy.nicinabox.com) 4 | 5 | A password generator backed by [vault](https://github.com/jcoglan/vault) and grown from [Hatchpass](https://github.com/nicinabox/Hatchpass-BackboneJS). 6 | 7 |  8 | 9 | ## About 10 | 11 | Cassidy generates passwords based on a service (eg, google.com). Combine this with a passphrase and a key (think salt) and you have very strong, unique passwords. No two are alike, even if you use the same service and password as someone else. 12 | 13 | ## How it works 14 | 15 | Your history and the data to recreate a service password is stored in localStorage. Passwords themselves are never stored or transmitted. 16 | 17 | Dropbox syncing of services (using the Datastore API) is also available (https only). Your passphrase IS stored in localStorage using Triple DES and your Key as the salt. 18 | 19 | **Cassidy does not protect against physical access to your machine.** 20 | 21 | ## Todo 22 | 23 | * [ ] Add X-Frame-Options to prevent iframing 24 | * [ ] Remove subsequent renders from Generator view to prevent keyboard jump 25 | * [ ] Implement service salt 26 | * [ ] Research KDF more. Perhaps don't store phrase 27 | 28 | ## Development setup 29 | 30 | * bundle install 31 | * npm install 32 | * bower install 33 | 34 | ## License 35 | 36 | MIT (c) 2014 Nic Aitch 37 | -------------------------------------------------------------------------------- /app/environments/development.coffee: -------------------------------------------------------------------------------- 1 | App.env = 'development' 2 | -------------------------------------------------------------------------------- /app/environments/production.coffee: -------------------------------------------------------------------------------- 1 | App.env = 'production' 2 | -------------------------------------------------------------------------------- /app/images/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicinabox/cassidy/d3a12d8cd4dea70d39a93c7fe05d29794f441278/app/images/apple-touch-icon.png -------------------------------------------------------------------------------- /app/includes/analytics.html: -------------------------------------------------------------------------------- 1 | 14 | -------------------------------------------------------------------------------- /app/includes/head.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
6 | Cassidy is a project I've maintained for a long time. It's seen many iterations in design and functionality and been ported to many different languages. 7 |
8 |9 | As smartphones have become more prevalent, the need for easy logins and strong passwords becomes even greater. Cassidy had some support for syncing (through Dropbox), but when they shut down the product that Cassidy used to to store metadata, a significant part of its usability was hampered. 10 |
11 |12 | Cassidy has no backend, no accounts, and no integration with any other apps. These things are by design to support its security model, but it unfortunately compromises on usability. The workflow to sign in to a site using a computer is clunky at best. On mobile it's downright frustrating for all but the most dedicated of users. 13 |
14 |15 | This project has been a great learning experience for me and I hope it has benefited others as well. I've decided to stop supporting Cassidy going forward. It will remain online and functional, but will not receive new features or bugfixes. 16 |
17 |18 | I am personally transitioning to 1Password and to help with this I've added functionality to Cassidy if you'd like to export your passwords to 1Password as well. 19 |
20 |21 | In Cassidy 22 |
23 |32 | In 1Password 33 |
34 |47 | And thank you for supporting this project. 48 |
49 |50 | --Nic 51 |
52 | -------------------------------------------------------------------------------- /app/templates/application.hbs: -------------------------------------------------------------------------------- 1 |21 | Thank you for your support! 22 |
23 | 24 |8 | Cassidy generates unique passwords by combining a service, key, and phrase. 9 | 10 | Add your own phrase under the Settings tab. A key will be generated pseudo-randomly for you. 11 |
12 | 13 |14 | Write it down or remember your key! You must have it to recreate the same passwords. 15 |
16 | 17 |20 | Recent services appear on the left side. When typing in the service field, you may select from recent services using the autocomplete dropdown. 21 |
22 | 23 |25 | When entering a service, use Enter or Tab to save the service in the sidebar. 26 |
27 |28 | A saved service will also save all the current settings with it. Selecting a saved service will repopulate the settings that it was created with. 29 |
30 | 31 |33 | Hover over a service in the sidebar and click the × on the right side. 34 |
35 | 36 |39 | You may influence the creation of a password by turning on or off several options, including lowercase letters, capital letters, numbers, dashes, sumbols, and length. 40 |
41 | 42 |45 | Your key makes your passwords unique. No one else can have the same generated password for a given service + key combination. 46 |
47 | 48 |51 | Unlike the settings and key, your phrase is not saved with a service. It will be encrypted and persisted in localStorage for your convenience. 52 |
53 | 54 |56 | If you connect to Dropbox, your services will be saved to Dropbox instead of localStorage. This means you can connect several devices (computers, phones, tablets) and have the same services available everywhere. 57 |
58 | 59 |60 | Cassidy does not save passwords, only most of the information required to recreate passwords. Each service will have settings data attached, including the key. You must reenter your Phrase on every new device. 61 |
62 | 63 |66 | Application data is stored in localStorage by default. Under Settings, click Clear local data to reset the application and remove all saved settings and services. 67 |
68 | 69 |70 | Additionally, Reset Settings will restore the settings to your original key and default settings. It is not a dangerous action. 71 |
72 |7 | Cassidy is an open source password manager that doesn't store passwords. 8 |
9 | 10 |11 | It works by by combining a service (website), key, and phrase. Cassidy uses vault and can sync safe metadata with Dropbox. 12 |
13 | 14 |Please close this window.
',t.writeHead(200,{"Content-Length":e.length,"Content-Type":"text/html"}),t.write(e),t.end()},t}(),S.AuthError=function(){function t(t){var e;if(!t.error)throw new Error("Not an OAuth 2.0 error: "+JSON.stringify(t));e="object"==typeof t.error&&t.error.error?t.error:t,this.code=e.error,this.description=e.error_description||null,this.uri=e.error_uri||null}return t.prototype.code=null,t.prototype.description=null,t.prototype.uri=null,t.ACCESS_DENIED="access_denied",t.INVALID_REQUEST="invalid_request",t.UNAUTHORIZED_CLIENT="unauthorized_client",t.INVALID_GRANT="invalid_grant",t.INVALID_SCOPE="invalid_scope",t.UNSUPPORTED_GRANT_TYPE="unsupported_grant_type",t.UNSUPPORTED_RESPONSE_TYPE="unsupported_response_type",t.SERVER_ERROR="server_error",t.TEMPORARILY_UNAVAILABLE="temporarily_unavailable",t.prototype.toString=function(){return"Dropbox OAuth error "+this.code+" :: "+this.description},t.prototype.inspect=function(){return this.toString()},t}(),S.Client=function(){function t(t){var e=this;this._serverRoot=t.server||this._defaultServerRoot(),this._maxApiServer="maxApiServer"in t?t.maxApiServer:this._defaultMaxApiServer(),this._authServer=t.authServer||this._defaultAuthServer(),this._fileServer=t.fileServer||this._defaultFileServer(),this._downloadServer=t.downloadServer||this._defaultDownloadServer(),this._notifyServer=t.notifyServer||this._defaultNotifyServer(),this.onXhr=new S.Util.EventSource({cancelable:!0}),this.onError=new S.Util.EventSource,this.onAuthStepChange=new S.Util.EventSource,this._xhrOnErrorHandler=function(t,r){return e._handleXhrError(t,r)},this._oauth=new S.Util.Oauth(t),this._uid=t.uid||null,this.authStep=this._oauth.step(),this._driver=null,this.authError=null,this._credentials=null,this._datastoreManager=null,this.setupUrls()}return t.prototype.onXhr=null,t.prototype.onError=null,t.prototype.onAuthStepChange=null,t.prototype.authDriver=function(t){return this._driver=t,this},t.prototype.dropboxUid=function(){return this._uid},t.prototype.credentials=function(){return this._credentials||this._computeCredentials(),this._credentials},t.prototype.authenticate=function(t,e){var r,n,i,o,s,a=this;if(e||"function"!=typeof t||(e=t,t=null),r=t&&"interactive"in t?t.interactive:!0,!this._driver&&this.authStep!==h.DONE&&(S.AuthDriver.autoConfigure(this),!this._driver))throw new Error("OAuth driver auto-configuration failed. Call authDriver.");if(this.authStep===h.ERROR)throw new Error("Client got in an error state. Call reset() to reuse it!");return o=function(){return a.authStep=a._oauth.step(),a.authStep===h.ERROR&&(a.authError=a._oauth.error()),a._credentials=null,a.onAuthStepChange.dispatch(a),s()},i=function(){return a.authStep=h.ERROR,a._credentials=null,a.onAuthStepChange.dispatch(a),s()},n=null,s=function(){var t;if(n!==a.authStep&&(n=a.authStep,a._driver&&a._driver.onAuthStepChange))return a._driver.onAuthStepChange(a,s),void 0;switch(a.authStep){case h.RESET:return r?(a._driver.getStateParam&&a._driver.getStateParam(function(t){return a.client.authStep===h.RESET&&a._oauth.setAuthStateParam(t),o()}),a._oauth.setAuthStateParam(S.Util.Oauth.randomAuthStateParam()),o()):(e&&e(null,a),void 0);case h.PARAM_SET:return r?(t=a.authorizeUrl(),a._driver.doAuthorize(t,a._oauth.authStateParam(),a,function(t){return a._oauth.processRedirectParams(t),t.uid&&(a._uid=t.uid),o()})):(e&&e(null,a),void 0);case h.PARAM_LOADED:return a._driver.resumeAuthorize?a._driver.resumeAuthorize(a._oauth.authStateParam(),a,function(t){return a._oauth.processRedirectParams(t),t.uid&&(a._uid=t.uid),o()}):(a._oauth.setAuthStateParam(a._oauth.authStateParam()),o(),void 0);case h.AUTHORIZED:return a.getAccessToken(function(t,e){return t?(a.authError=t,i()):(a._oauth.processRedirectParams(e),a._uid=e.uid,o())});case h.DONE:e&&e(null,a);break;case h.SIGNED_OUT:return a.authStep=h.RESET,a.reset(),s();case h.ERROR:e&&e(a.authError,a)}},s(),this},t.prototype.isAuthenticated=function(){return this.authStep===h.DONE},t.prototype.signOut=function(t,e){var r,n,i=this;if(e||"function"!=typeof t||(e=t,t=null),r=t&&t.mustInvalidate,this.authStep!==h.DONE)throw new Error("This client doesn't have a user's token");return n=new S.Util.Xhr("POST",this._urls.signOut),n.signWithOauth(this._oauth),this._dispatchXhr(n,function(t){if(t)if(t.status===S.ApiError.INVALID_TOKEN)t=null;else if(r)return e&&e(t),void 0;return i.authStep=h.RESET,i.reset(),i.authStep=h.SIGNED_OUT,i.onAuthStepChange.dispatch(i),i._driver&&i._driver.onAuthStepChange?i._driver.onAuthStepChange(i,function(){return e?e(null):void 0}):e?e(null):void 0})},t.prototype.signOff=function(t,e){return this.signOut(t,e)},t.prototype.getAccountInfo=function(t,e){var r,n;return e||"function"!=typeof t||(e=t,t=null),r=!1,t&&t.httpCache&&(r=!0),n=new S.Util.Xhr("GET",this._urls.accountInfo),n.signWithOauth(this._oauth,r),this._dispatchXhr(n,function(t,r){return e(t,S.AccountInfo.parse(r),r)})},t.prototype.getUserInfo=function(t,e){return this.getAccountInfo(t,e)},t.prototype.readFile=function(t,e,r){var n,i,o,s,a,u,l;return r||"function"!=typeof e||(r=e,e=null),i={},u="text",s=null,n=!1,e&&(e.versionTag?i.rev=e.versionTag:e.rev&&(i.rev=e.rev),e.arrayBuffer?u="arraybuffer":e.blob?u="blob":e.buffer?u="buffer":e.binary&&(u="b"),e.length?(null!=e.start?(a=e.start,o=e.start+e.length-1):(a="",o=e.length),s="bytes="+a+"-"+o):null!=e.start&&(s="bytes="+e.start+"-"),e.httpCache&&(n=!0)),l=new S.Util.Xhr("GET",""+this._urls.getFile+"/"+this._urlEncodePath(t)),l.setParams(i).signWithOauth(this._oauth,n),l.setResponseType(u),s&&(s&&l.setHeader("Range",s),l.reportResponseHeaders()),this._dispatchXhr(l,function(t,e,n,i){var o;return o=i?S.Http.RangeInfo.parse(i["content-range"]):null,r(t,e,S.File.Stat.parse(n),o)})},t.prototype.writeFile=function(t,e,r,n){var i;return n||"function"!=typeof r||(n=r,r=null),i=S.Util.Xhr.canSendForms&&"object"==typeof e,i?this._writeFileUsingForm(t,e,r,n):this._writeFileUsingPut(t,e,r,n)},t.prototype._writeFileUsingForm=function(t,e,r,n){var i,o,s,a;return s=t.lastIndexOf("/"),-1===s?(i=t,t=""):(i=t.substring(s),t=t.substring(0,s)),o={file:i},r&&(r.noOverwrite&&(o.overwrite="false"),r.lastVersionTag?o.parent_rev=r.lastVersionTag:(r.parentRev||r.parent_rev)&&(o.parent_rev=r.parentRev||r.parent_rev)),a=new S.Util.Xhr("POST",""+this._urls.postFile+"/"+this._urlEncodePath(t)),a.setParams(o).signWithOauth(this._oauth).setFileField("file",i,e,"application/octet-stream"),delete o.file,this._dispatchXhr(a,function(t,e){return n?n(t,S.File.Stat.parse(e)):void 0})},t.prototype._writeFileUsingPut=function(t,e,r,n){var i,o;return i={},r&&(r.noOverwrite&&(i.overwrite="false"),r.lastVersionTag?i.parent_rev=r.lastVersionTag:(r.parentRev||r.parent_rev)&&(i.parent_rev=r.parentRev||r.parent_rev)),o=new S.Util.Xhr("POST",""+this._urls.putFile+"/"+this._urlEncodePath(t)),o.setBody(e).setParams(i).signWithOauth(this._oauth),this._dispatchXhr(o,function(t,e){return n?n(t,S.File.Stat.parse(e)):void 0})},t.prototype.resumableUploadStep=function(t,e,r){var n,i;return e?(n={offset:e.offset},e.tag&&(n.upload_id=e.tag)):n={offset:0},i=new S.Util.Xhr("POST",this._urls.chunkedUpload),i.setBody(t).setParams(n).signWithOauth(this._oauth),this._dispatchXhr(i,function(t,e){return t&&t.status===S.ApiError.INVALID_PARAM&&t.response&&t.response.upload_id&&t.response.offset?r(null,S.Http.UploadCursor.parse(t.response)):r(t,S.Http.UploadCursor.parse(e))})},t.prototype.resumableUploadFinish=function(t,e,r,n){var i,o;return n||"function"!=typeof r||(n=r,r=null),i={upload_id:e.tag},r&&(r.lastVersionTag?i.parent_rev=r.lastVersionTag:(r.parentRev||r.parent_rev)&&(i.parent_rev=r.parentRev||r.parent_rev),r.noOverwrite&&(i.overwrite="false")),o=new S.Util.Xhr("POST",""+this._urls.commitChunkedUpload+"/"+this._urlEncodePath(t)),o.setParams(i).signWithOauth(this._oauth),this._dispatchXhr(o,function(t,e){return n?n(t,S.File.Stat.parse(e)):void 0})},t.prototype.stat=function(t,e,r){var n,i,o;return r||"function"!=typeof e||(r=e,e=null),i={},n=!1,e&&(e.versionTag?i.rev=e.versionTag:e.rev&&(i.rev=e.rev),e.contentHash?i.hash=e.contentHash:e.hash&&(i.hash=e.hash),(e.removed||e.deleted)&&(i.include_deleted="true"),e.readDir&&(i.list="true",e.readDir!==!0&&(i.file_limit=e.readDir.toString())),e.cacheHash&&(i.hash=e.cacheHash),e.httpCache&&(n=!0)),i.include_deleted||(i.include_deleted="false"),i.list||(i.list="false"),o=new S.Util.Xhr("GET",""+this._urls.metadata+"/"+this._urlEncodePath(t)),o.setParams(i).signWithOauth(this._oauth,n),this._dispatchXhr(o,function(t,e){var n,i,o;return o=S.File.Stat.parse(e),n=(null!=e?e.contents:void 0)?function(){var t,r,n,o;for(n=e.contents,o=[],t=0,r=n.length;r>t;t++)i=n[t],o.push(S.File.Stat.parse(i));return o}():void 0,r(t,o,n)})},t.prototype.readdir=function(t,e,r){var n;return r||"function"!=typeof e||(r=e,e=null),n={readDir:!0},e&&(null!=e.limit&&(n.readDir=e.limit),e.versionTag?n.versionTag=e.versionTag:e.rev&&(n.versionTag=e.rev),e.contentHash?n.contentHash=e.contentHash:e.hash&&(n.contentHash=e.hash),(e.removed||e.deleted)&&(n.removed=e.removed||e.deleted),e.httpCache&&(n.httpCache=e.httpCache)),this.stat(t,n,function(t,e,n){var i,o;return i=n?function(){var t,e,r;for(r=[],t=0,e=n.length;e>t;t++)o=n[t],r.push(o.name);return r}():null,r(t,i,e,n)})},t.prototype.metadata=function(t,e,r){return this.stat(t,e,r)},t.prototype.makeUrl=function(t,e,r){var n,i,o,s,a,u=this;return r||"function"!=typeof e||(r=e,e=null),i=e&&(e["long"]||e.longUrl||e.downloadHack)?{short_url:"false"}:{},t=this._urlEncodePath(t),o=""+this._urls.shares+"/"+t,n=!1,s=!1,e&&(e.downloadHack?(n=!0,s=!0):e.download&&(n=!0,o=""+this._urls.media+"/"+t)),a=new S.Util.Xhr("POST",o).setParams(i).signWithOauth(this._oauth),this._dispatchXhr(a,function(t,e){return s&&(null!=e?e.url:void 0)&&(e.url=e.url.replace(u._authServer,u._downloadServer)),r(t,S.File.ShareUrl.parse(e,n))})},t.prototype.history=function(t,e,r){var n,i,o;return r||"function"!=typeof e||(r=e,e=null),i={},n=!1,e&&(null!=e.limit&&(i.rev_limit=e.limit),e.httpCache&&(n=!0)),o=new S.Util.Xhr("GET",""+this._urls.revisions+"/"+this._urlEncodePath(t)),o.setParams(i).signWithOauth(this._oauth,n),this._dispatchXhr(o,function(t,e){var n,i;return i=e?function(){var t,r,i;for(i=[],t=0,r=e.length;r>t;t++)n=e[t],i.push(S.File.Stat.parse(n));return i}():void 0,r(t,i)})},t.prototype.revisions=function(t,e,r){return this.history(t,e,r)},t.prototype.thumbnailUrl=function(t,e){var r;return r=this.thumbnailXhr(t,e),r.paramsToUrl().url},t.prototype.readThumbnail=function(t,e,r){var n,i;return r||"function"!=typeof e||(r=e,e=null),n="b",e&&(e.blob&&(n="blob"),e.arrayBuffer&&(n="arraybuffer"),e.buffer&&(n="buffer")),i=this.thumbnailXhr(t,e),i.setResponseType(n),this._dispatchXhr(i,function(t,e,n){return r(t,e,S.File.Stat.parse(n))})},t.prototype.thumbnailXhr=function(t,e){var r,n;return r={},e&&(e.format?r.format=e.format:e.png&&(r.format="png"),e.size&&(r.size=e.size)),n=new S.Util.Xhr("GET",""+this._urls.thumbnails+"/"+this._urlEncodePath(t)),n.setParams(r).signWithOauth(this._oauth)},t.prototype.revertFile=function(t,e,r){var n;return n=new S.Util.Xhr("POST",""+this._urls.restore+"/"+this._urlEncodePath(t)),n.setParams({rev:e}).signWithOauth(this._oauth),this._dispatchXhr(n,function(t,e){return r?r(t,S.File.Stat.parse(e)):void 0})},t.prototype.restore=function(t,e,r){return this.revertFile(t,e,r)},t.prototype.findByName=function(t,e,r,n){var i,o,s;return n||"function"!=typeof r||(n=r,r=null),o={query:e},i=!1,r&&(null!=r.limit&&(o.file_limit=r.limit),(r.removed||r.deleted)&&(o.include_deleted=!0),r.httpCache&&(i=!0)),s=new S.Util.Xhr("GET",""+this._urls.search+"/"+this._urlEncodePath(t)),s.setParams(o).signWithOauth(this._oauth,i),this._dispatchXhr(s,function(t,e){var r,i;return i=e?function(){var t,n,i;for(i=[],t=0,n=e.length;n>t;t++)r=e[t],i.push(S.File.Stat.parse(r));return i}():void 0,n(t,i)})},t.prototype.search=function(t,e,r,n){return this.findByName(t,e,r,n)},t.prototype.makeCopyReference=function(t,e){var r;return r=new S.Util.Xhr("GET",""+this._urls.copyRef+"/"+this._urlEncodePath(t)),r.signWithOauth(this._oauth),this._dispatchXhr(r,function(t,r){return e(t,S.File.CopyReference.parse(r))})},t.prototype.copyRef=function(t,e){return this.makeCopyReference(t,e)},t.prototype.pullChanges=function(t,e){var r,n;return e||"function"!=typeof t||(e=t,t=null),r=t?t.cursorTag?{cursor:t.cursorTag}:{cursor:t}:{},n=new S.Util.Xhr("POST",this._urls.delta),n.setParams(r).signWithOauth(this._oauth),this._dispatchXhr(n,function(t,r){return e(t,S.Http.PulledChanges.parse(r))})},t.prototype.delta=function(t,e){return this.pullChanges(t,e)},t.prototype.pollForChanges=function(t,e,r){var n,i;return r||"function"!=typeof e||(r=e,e=null),n=t.cursorTag?{cursor:t.cursorTag}:{cursor:t},e&&"timeout"in e&&(n.timeout=e.timeout),i=new S.Util.Xhr("GET",this._urls.longpollDelta),i.setParams(n),this._dispatchXhr(i,function(t,e){var n;if("string"==typeof e)try{e=JSON.parse(e)}catch(i){n=i,e=null}return r(t,S.Http.PollResult.parse(e))})},t.prototype.mkdir=function(t,e){var r;return r=new S.Util.Xhr("POST",this._urls.fileopsCreateFolder),r.setParams({root:"auto",path:this._normalizePath(t)}).signWithOauth(this._oauth),this._dispatchXhr(r,function(t,r){return e?e(t,S.File.Stat.parse(r)):void 0})},t.prototype.remove=function(t,e){var r;return r=new S.Util.Xhr("POST",this._urls.fileopsDelete),r.setParams({root:"auto",path:this._normalizePath(t)}).signWithOauth(this._oauth),this._dispatchXhr(r,function(t,r){return e?e(t,S.File.Stat.parse(r)):void 0})},t.prototype.unlink=function(t,e){return this.remove(t,e)},t.prototype["delete"]=function(t,e){return this.remove(t,e)},t.prototype.copy=function(t,e,r){var n,i;return n={root:"auto",to_path:this._normalizePath(e)},t instanceof S.File.CopyReference?n.from_copy_ref=t.tag:n.from_path=this._normalizePath(t),i=new S.Util.Xhr("POST",this._urls.fileopsCopy),i.setParams(n).signWithOauth(this._oauth),this._dispatchXhr(i,function(t,e){return r?r(t,S.File.Stat.parse(e)):void 0})},t.prototype.move=function(t,e,r){var n;return n=new S.Util.Xhr("POST",this._urls.fileopsMove),n.setParams({root:"auto",from_path:this._normalizePath(t),to_path:this._normalizePath(e)}).signWithOauth(this._oauth),this._dispatchXhr(n,function(t,e){return r?r(t,S.File.Stat.parse(e)):void 0})},t.prototype.appInfo=function(t,e){var r;return e||"function"!=typeof t||(e=t,t=this._oauth.credentials().key),r=new S.Util.Xhr("GET",this._urls.appsInfo),r.setParams({app_key:t}),this._dispatchXhr(r,function(r,n){return e(r,S.Http.AppInfo.parse(n,t))})},t.prototype.isAppDeveloper=function(t,e,r){var n;return"object"==typeof t&&"uid"in t&&(t=t.uid),r||"function"!=typeof e?"object"==typeof e&&"key"in e&&(e=e.key):(r=e,e=this._oauth.credentials().key),n=new S.Util.Xhr("GET",this._urls.appsCheckDeveloper),n.setParams({app_key:e,uid:t}),this._dispatchXhr(n,function(t,e){return e?r(t,e.is_developer):r(t)})},t.prototype.hasOauthRedirectUri=function(t,e,r){var n;return r||"function"!=typeof e?"object"==typeof e&&"key"in e&&(e=e.key):(r=e,e=this._oauth.credentials().key),n=new S.Util.Xhr("GET",this._urls.appsCheckRedirectUri),n.setParams({app_key:e,redirect_uri:t}),this._dispatchXhr(n,function(t,e){return e?r(t,e.has_redirect_uri):r(t)})},t.prototype.reset=function(){var t;return this._uid=null,this._oauth.reset(),t=this.authStep,this.authStep=this._oauth.step(),t!==this.authStep&&this.onAuthStepChange.dispatch(this),this.authError=null,this._credentials=null,this},t.prototype.setCredentials=function(t){var e;return e=this.authStep,this._oauth.setCredentials(t),this.authStep=this._oauth.step(),this._uid=t.uid||null,this.authError=null,this._credentials=null,e!==this.authStep&&this.onAuthStepChange.dispatch(this),this},t.prototype.appHash=function(){return this._oauth.appHash()},t.prototype.setupUrls=function(){return this._apiServer=this._chooseApiServer(),this._urls={authorize:""+this._authServer+"/1/oauth2/authorize",token:""+this._apiServer+"/1/oauth2/token",signOut:""+this._apiServer+"/1/unlink_access_token",accountInfo:""+this._apiServer+"/1/account/info",getFile:""+this._fileServer+"/1/files/auto",postFile:""+this._fileServer+"/1/files/auto",putFile:""+this._fileServer+"/1/files_put/auto",metadata:""+this._apiServer+"/1/metadata/auto",delta:""+this._apiServer+"/1/delta",longpollDelta:""+this._notifyServer+"/1/longpoll_delta",revisions:""+this._apiServer+"/1/revisions/auto",restore:""+this._apiServer+"/1/restore/auto",search:""+this._apiServer+"/1/search/auto",shares:""+this._apiServer+"/1/shares/auto",media:""+this._apiServer+"/1/media/auto",copyRef:""+this._apiServer+"/1/copy_ref/auto",thumbnails:""+this._fileServer+"/1/thumbnails/auto",chunkedUpload:""+this._fileServer+"/1/chunked_upload",commitChunkedUpload:""+this._fileServer+"/1/commit_chunked_upload/auto",fileopsCopy:""+this._apiServer+"/1/fileops/copy",fileopsCreateFolder:""+this._apiServer+"/1/fileops/create_folder",fileopsDelete:""+this._apiServer+"/1/fileops/delete",fileopsMove:""+this._apiServer+"/1/fileops/move",appsInfo:""+this._apiServer+"/1/apps/info",appsCheckDeveloper:""+this._apiServer+"/1/apps/check_developer",appsCheckRedirectUri:""+this._apiServer+"/1/apps/check_redirect_uri",getDb:""+this._apiServer+"/1/datastores/get_datastore",getOrCreateDb:""+this._apiServer+"/1/datastores/get_or_create_datastore",createDb:""+this._apiServer+"/1/datastores/create_datastore",listDbs:""+this._apiServer+"/1/datastores/list_datastores",deleteDb:""+this._apiServer+"/1/datastores/delete_datastore",getSnapshot:""+this._apiServer+"/1/datastores/get_snapshot",getDeltas:""+this._apiServer+"/1/datastores/get_deltas",putDelta:""+this._apiServer+"/1/datastores/put_delta",datastoreAwait:""+this._apiServer+"/1/datastores/await"},this 3 | },t.prototype._chooseApiServer=function(){var t,e;return e=Math.floor(Math.random()*(this._maxApiServer+1)),t=0===e?"":e.toString(),this._serverRoot.replace("$",t)},t.prototype.authStep=null,t.ERROR=0,t.RESET=1,t.PARAM_SET=2,t.PARAM_LOADED=3,t.AUTHORIZED=4,t.DONE=5,t.SIGNED_OUT=6,t.prototype._urlEncodePath=function(t){return S.Util.Xhr.urlEncodeValue(this._normalizePath(t)).replace(/%2F/gi,"/")},t.prototype._normalizePath=function(t){var e;if("/"===t.substring(0,1)){for(e=1;"/"===t.substring(e,e+1);)e+=1;return t.substring(e)}return t},t.prototype.authorizeUrl=function(){var t;return t=this._oauth.authorizeUrlParams(this._driver.authType(),this._driver.url()),this._urls.authorize+"?"+S.Util.Xhr.urlEncode(t)},t.prototype.getAccessToken=function(t){var e,r;return e=this._oauth.accessTokenParams(this._driver.url()),r=new S.Util.Xhr("POST",this._urls.token).setParams(e).addOauthParams(this._oauth),this._dispatchXhr(r,function(e,r){return e&&e.status===S.ApiError.INVALID_PARAM&&e.response&&e.response.error&&(e=new S.AuthError(e.response)),t(e,r)})},t.prototype._dispatchLongPollXhr=function(t,e,r){return null==r&&(r=6e4),this._dispatchXhr(t,e,r)},t.prototype._dispatchXhr=function(t,e,r){var n,i,o=this;return null==r&&(r=1e4),n=setTimeout(function(){return o._handleLongRequest(t)},2*r),t.setCallback(function(t,r,i,o){return clearTimeout(n),e(t,r,i,o)}),t.onError=this._xhrOnErrorHandler,t.prepare(),i=t.xhr,this.onXhr.dispatch(t)&&t.send(),i},t.prototype._handleXhrError=function(t,e){var r=this;return t.status===S.ApiError.INVALID_TOKEN&&this.authStep===h.DONE&&(this.authError=t,this.authStep=h.ERROR,this.onAuthStepChange.dispatch(this),this._driver&&this._driver.onAuthStepChange)?(this._driver.onAuthStepChange(this,function(){return r.onError.dispatch(t),e(t)}),null):(this.onError.dispatch(t),e(t),void 0)},t.prototype._handleLongRequest=function(){return this.setupUrls()},t.prototype._defaultServerRoot=function(){return"https://api$.dropbox.com"},t.prototype._defaultAuthServer=function(){return this._serverRoot.replace("api$","www")},t.prototype._defaultFileServer=function(){return this._serverRoot.replace("api$","api-content")},t.prototype._defaultDownloadServer=function(){return"https://dl.dropboxusercontent.com"},t.prototype._defaultNotifyServer=function(){return this._serverRoot.replace("api$","api-notify")},t.prototype._defaultMaxApiServer=function(){return 30},t.prototype._computeCredentials=function(){var t;t=this._oauth.credentials(),this._uid&&(t.uid=this._uid),this._serverRoot!==this._defaultServerRoot()&&(t.server=this._serverRoot),this._maxApiServer!==this._defaultMaxApiServer()&&(t.maxApiServer=this._maxApiServer),this._authServer!==this._defaultAuthServer()&&(t.authServer=this._authServer),this._fileServer!==this._defaultFileServer()&&(t.fileServer=this._fileServer),this._downloadServer!==this._defaultDownloadServer()&&(t.downloadServer=this._downloadServer),this._notifyServer!==this._defaultNotifyServer()&&(t.notifyServer=this._notifyServer),this._credentials=t},t}(),h=S.Client,S.Datastore=function(){function t(t,e){var r=this;this._datastore_manager=t,this._managed_datastore=e,this._dsid=this._managed_datastore.get_dsid(),this._handle=this._managed_datastore.get_handle(),this._record_cache=new V(this),this._last_used_timestamp=0,this.recordsChanged=new S.Util.EventSource,this.syncStatusChanged=new S.Util.EventSource,this._timeoutWrapper=function(t){return t},this._evt_mgr=new E,this._evt_mgr.register(this._managed_datastore.syncStateChanged,function(){return r._syncSoon(),r.syncStatusChanged.dispatch(null)}),this._syncPending=!1,this._closed=!1,this._metadata_table=new S.Datastore.Table(this,":info"),this._metadata_table.setResolutionRule("mtime","max")}return t.DATASTORE_SIZE_LIMIT=10485760,t.RECORD_COUNT_LIMIT=1e5,t.BASE_DATASTORE_SIZE=1e3,t.TEAM="team",t.PUBLIC="public",t.OWNER="owner",t.EDITOR="editor",t.VIEWER="viewer",t.NONE="none",t.prototype.recordsChanged=null,t.prototype.syncStatusChanged=null,t.int64=function(t){var e,r;if(Z.is_number(t)&&null!=t[te.INT64_TAG])return te.validateInt64(t);if(Z.is_string(t)){if(!te.is_valid_int64_string(t))throw new Error("Not a valid int64 in string form: "+t);return r=new Number(parseInt(t,10)),r[te.INT64_TAG]=t,te.validateInt64(r)}if(!Z.is_number(t)||!isFinite(t))throw new Error("Not a finite number: "+t);if(Number(t)!==Math.round(t))throw new Error("Number is not an integer: "+t);if(e=t.toFixed(),!te.is_valid_int64_string(e))throw new Error("Number not in int64 range: "+t);return r=new Number(t),r[te.INT64_TAG]=e,te.validateInt64(r)},t.isInt64=function(t){return te.isInt64(t)},t.prototype.getModifiedTime=function(){var t;return t=this._metadata_table.get("info"),null==t?null:t.get("mtime")},t.prototype.getTitle=function(){var t;return t=this._metadata_table.get("info"),null==t?null:t.get("title")},t.prototype.setTitle=function(t){var e;if(null!=t&&!Z.string(t))throw new Error("Title must be a string or null!");return e=this._metadata_table.getOrInsert("info",{}),e.set("title",t)},t.prototype.isShareable=function(){return"."===this._dsid[0]},t.prototype._checkShareable=function(){if(!this.isShareable())throw new Error("Datastore is not shareable")},t.prototype.getEffectiveRole=function(){var t;return this.isShareable()?(t=this._managed_datastore.get_effective_role(),S.Datastore._roleFromInt(t)):S.Datastore.OWNER},t.prototype.isWritable=function(){var t;return t=this.getEffectiveRole(),t===S.Datastore.OWNER||t===S.Datastore.EDITOR},t.prototype._checkWritable=function(){if(!this.isWritable())throw new Error("Datastore is not writable")},t.prototype._checkRole=function(t){if(t!==S.Datastore.EDITOR&&t!==S.Datastore.VIEWER)throw new Error("Invalid role: "+t)},t.prototype._checkPrincipal=function(t){if(t!==S.Datastore.TEAM&&t!==S.Datastore.PUBLIC&&!t.match(/^u[1-9][0-9]*$/))throw new Error("Invalid principal: "+t)},t.prototype._getRole=function(t){var e,r,n;return e=null!=(r=this.getTable(te.ACL_TID))?null!=(n=r.get(t))?n.get("role"):void 0:void 0,null==e?S.Datastore.NONE:S.Datastore._roleFromInt(e)},t.prototype.getRole=function(t){return this._checkShareable(),this._checkPrincipal(t),this._getRole(t)},t.prototype.setRole=function(t,e){var r;return e===S.Datastore.NONE?(this.deleteRole(t),void 0):(this._checkShareable(),this._checkPrincipal(t),this._checkRole(e),this._checkWritable(),r=S.Datastore.int64(S.Datastore._intFromRole(e)),this.getTable(te.ACL_TID).getOrInsert(t).update({role:r}))},t.prototype.deleteRole=function(t){var e;return this._checkShareable(),this._checkPrincipal(t),this._checkWritable(),null!=(e=this.getTable(te.ACL_TID).get(t))?e.deleteRecord():void 0},t.prototype.listRoles=function(){var t,e,r,n,i,o;for(this._checkShareable(),r={},o=this.getTable(te.ACL_TID).query(),n=0,i=o.length;i>n;n++)e=o[n],t=e.getId(),r[t]=this._getRole(t);return r},t._roleFromInt=function(t){switch(!1){case!(t>=te.ROLE_OWNER):return S.Datastore.OWNER;case!(t>=te.ROLE_EDITOR):return S.Datastore.EDITOR;case!(t>=te.ROLE_VIEWER):return S.Datastore.VIEWER;default:return S.Datastore.NONE}},t._intFromRole=function(t){switch(t){case S.Datastore.OWNER:return te.ROLE_OWNER;case S.Datastore.EDITOR:return te.ROLE_EDITOR;case S.Datastore.VIEWER:return te.ROLE_VIEWER;default:return 0}},t.prototype.getTable=function(t){if(this._checkNotClosed(),!S.Datastore.Table.isValidId(t))throw new Error("Invalid table ID: "+t);return new S.Datastore.Table(this,t)},t.prototype.listTableIds=function(){return this._checkNotClosed(),this._managed_datastore.list_tables()},t.prototype.getRecordCount=function(){return this._managed_datastore.get_record_count()},t.prototype.getSize=function(){return this._managed_datastore.get_size()},t.prototype.toString=function(){var t;return t=this._closed?"[closed] ":"","Datastore("+t+this._dsid+" ["+this._handle+"])"},t.prototype.close=function(){return this._closed=!0,this._evt_mgr.unregister_all(),this._listeners=[],this._datastore_manager._obj_manager.close(this._dsid),void 0},t.prototype.getId=function(){return this._dsid},t.prototype.getSyncStatus=function(){return{uploading:this._managed_datastore.get_outgoing_delta_count()>0}},t.isValidId=function(t){var e;return e=new RegExp(Z.DS_ID_REGEX),Z.is_string(t)&&e.test(t)},t.isValidShareableId=function(t){return this.isValidId(t)&&"."===t[0]},t.prototype._generateRid=function(){var t,e,r,n;for(n="_",e="_js_",r=Math.round(1e3*Date.now()),r<=this._last_used_timestamp&&(r=this._last_used_timestamp+1),this._last_used_timestamp=r,t=r.toString(32);t.length<11;)t="0"+t;return n+t+e+te.randomWeb64String(5)},t.prototype._syncSoon=function(){var t=this;if(this._managed_datastore.is_deleted())throw new Error("Cannot sync deleted datastore "+this._dsid);return this._checkNotClosed(),this._syncPending||(this._syncPending=!0,setTimeout(this._timeoutWrapper(function(){return t._syncPending=!1,t._sync()}),0)),void 0},t.prototype._sync=function(){var t,e,r,n,i,o,s,a,u;this._checkNotClosed(),i=this._managed_datastore.sync(),n=this._resolveAffectedRecordMap(i),t=!1;for(s in n)for(r=n[s],a=0,u=r.length;u>a;a++)e=r[a],Y(s===e._tid,"tid mismatch"),t=!0,o=e._rid,this._managed_datastore.query(s,o)||(e._deleted=!0,this._record_cache.remove(s,o));return t&&this.recordsChanged.dispatch(new q(n,!1)),void 0},t.prototype._resolveAffectedRecordMap=function(t){var e,r,n,i,o;r={};for(o in t){i=t[o];for(n in i)e=this._record_cache.getOrCreate(o,n),null==r[o]&&(r[o]=[]),r[o].push(e)}return r},t.prototype._recordsChangedLocally=function(t){return t.length>0&&(this.recordsChanged.dispatch(q._fromRecordList(t,!0)),this._syncSoon()),void 0},t.prototype._checkNotClosed=function(){if(this._closed||!this._managed_datastore._open)throw new Error("Datastore is already closed: "+this);return void 0},t}(),te=S.Datastore.impl={},Z=S.Datastore.impl.T={},Z.identity=function(t){return t},Z.get_coerce_fn=function(t){return null!=t.coerce?t.coerce:null!=t.load_json?function(e){return e instanceof t?e:t.load_json(e)}:Z.identity},Z.get_T_fn=function(t){return null!=t.Type?t.Type:t},Z.str=function(t){return Z.is_string(t)?t:Z.is_function(t)?t():JSON.stringify(t)},Z.assert=function(t,e){if(!t)throw new Error(Z.str(e))},Y=Z.assert,Z.check=function(t,e,r,n,i,o){if(t)return r;throw Z.fail(e,r,n,i,o),new Error("unreachable")},Z.safe_to_string=function(t){var e,r;try{if(r=t.toString(),"[object Object]"!==r)return r}catch(n){e=n}try{return JSON.stringify(t)}catch(n){e=n}try{if(r=t.constructor.name,null!=r?r.match(/^[A-Za-z0-9_]+$/):void 0)return r}catch(n){e=n}return"[T.safe_to_string failed]"},Z.fail=function(t,e,r,n,i){var o,s;throw s=null!=r?null!=n?null!=i?"Wanted "+Z.str(n)+", but "+Z.str(r)+" in "+Z.str(i)+" "+Z.str(t):"Wanted "+Z.str(n)+", but "+Z.str(r)+" "+Z.str(t):""+Z.str(r)+" "+Z.str(t):null!=n?null!=i?"Wanted "+Z.str(n)+", but in "+Z.str(i)+" "+Z.str(t):"Wanted "+Z.str(n)+", but "+Z.str(t):""+Z.str(t),o=new Error(""+s+": "+Z.safe_to_string(e)),console.error(o),o},Z.any=function(t){return t},Z.defined=function(t,e,r,n){return null==r&&(r="defined"),Z.check("undefined"!=typeof t,"is undefined",t,e,r,n),t},Z.nonnull=function(t,e,r,n){return null==r&&(r="nonnull"),Z.defined(t,e,r,n),Z.check(null!=t,"is null",t,e,r,n),t},Z.member=function(t){var e,r;return r="value in "+JSON.stringify(t),e="not in "+JSON.stringify(t),function(n,i,o,s){return null==o&&(o=r),Z.check(ne.call(t,n)>=0,e,n,i,o,s)}},Z.object=function(t,e,r,n){return null==r&&(r="object"),Z.nonnull(t,e,r,n),Z.check("object"==typeof t,"not an object",t,e,r,n),t},Z.bool=function(t,e,r,n){return null==r&&(r="bool"),Z.nonnull(t,e,r,n),Z.check(t===!0||t===!1,"is not bool",t,e,r,n),t},Z.string=function(t,e,r,n){return null==r&&(r="string"),Z.nonnull(t,e,r,n),Z.check(Z.is_string(t),"is not a string",t,e,r,n),t},Z.num=function(t,e,r,n){return null==r&&(r="num"),Z.nonnull(t,e,r,n),Z.check("number"==typeof t,"is not numeric",t,e,r,n),t},Z.int=function(t,e,r,n){return null==r&&(r="int"),Z.num(t,e,r,n),Z.check(0===t%1,"is not an integer",t,e,r,n),t},Z.uint=function(t,e,r,n){return null==r&&(r="uint"),Z.int(t,e,r,n),Z.check(t>=0,"is negative",t,e,r,n),t},Z.nullable=function(t){var e,r;return r="nullable("+t+")",e=function(e,n,i,o){return null==i&&(i=function(){return r}),Z.defined(e,n,i,o),null!=e&&Z.get_T_fn(t)(e,n,i,o),e},e.toString=function(){return r},e.coerce=function(e){return null!=e?Z.get_coerce_fn(t)(e):null},e.fromJSON=function(r){return null!=r?null!=t.fromJSON?t.fromJSON(r):e.coerce(r):null},e},Z.array=function(t,e,r,n){return null==r&&(r="array"),Z.nonnull(t,e,r,n),Z.check(Z.is_array(t),"is not an array",t,e,r,n),t},Z.arrayOf=function(t){var e,r;return r="arrayOf("+t+")",e=function(e,n,i,o){var s,a,u,l,h;for(null==i&&(i=r),Z.array(e,n,i,o),u=l=0,h=e.length;h>l;u=++l)s=e[u],a=function(){return null!=n?"element "+u+" of "+Z.str(n):"element "+u},Z.get_T_fn(t)(s,a,i,o);return e},e.toString=function(){return r},e.coerce=function(e){var n,i,o,s;for(Z.array(e,null,r),s=[],i=0,o=e.length;o>i;i++)n=e[i],s.push(Z.get_coerce_fn(t)(n));return s},e.fromJSON=function(n){var i,o,s,a;if(Z.array(n,"fromJSON input",r),null!=t.fromJSON){for(a=[],o=0,s=n.length;s>o;o++)i=n[o],a.push(t.fromJSON(i));return a}return e.coerce(n)},e},Z.instance=function(t,e,r,n,i){var o;if(!(e instanceof Function))throw new Error("Invalid type given: "+e);return t instanceof e||(null==n&&(n=e.name),Z.check(!1,"got instance of "+(null!=t?null!=(o=t.constructor)?o.name:void 0:void 0),t,r,n,i)),t},Z.unimplemented=function(t){return function(){throw new Error("unimplemented "+t)}},Z.startsWith=function(t,e){return 0===t.lastIndexOf(e,0)},Z.string_matching=function(t){var e;return Z.string(t),Z.check(/^[^].*[$]$/.test(t),"does not start with ^ and end with $",t),e="does not match regex "+t,function(r,n,i,o){return Z.string(r,n,i,o),Z.check(new RegExp(t).test(r),e,r,n,i,o),r}},Z.is_defined=function(t){return"undefined"!=typeof t},Z.is_bool=function(t){return t===!0||t===!1||t&&"object"==typeof t&&t.constructor===Boolean},Z.is_number=function(t){return"number"==typeof t||t&&"object"==typeof t&&t.constructor===Number},Z.is_json_number=function(t){return Z.is_number(t)&&!isNaN(t)&&isFinite(t)},Z.is_string=function(t){return"string"==typeof t||t&&"object"==typeof t&&t.constructor===String},Z.is_function=function(t){return"function"==typeof t},Z.is_object=function(t){return null!=t&&"object"==typeof t},Z.is_array=function(t){return"[object Array]"===Object.prototype.toString.call(t)},Z.is_empty=function(t){return 0===Object.keys(t).length},Z.is_date=function(t){return"[object Date]"===Object.prototype.toString.call(t)},Z.isUint8Array=function(t){return"[object Uint8Array]"===Object.prototype.toString.call(t)},Z.is_simple_map=function(t){var e,r;if(null==t||"object"!=typeof t)return!1;for(e in t)if(r=t[e],!Object.prototype.hasOwnProperty.call(t,e))return!1;return!0},Z.simple_map=function(t,e,r,n){var i,o;null==r&&(r="simple map"),Z.object(t,e,r,n);for(i in t)o=t[i],Z.check(Object.prototype.hasOwnProperty.call(t,i),function(){return"property "+i+" is inherited"},t,e,r,t);return t},Z.simple_typed_map=function(t,e,r){var n,i,o;return n=Z.get_coerce_fn(e),i=Z.get_coerce_fn(r),o=function(n,i,o,s){var a,u;null==o&&(o=t),Z.simple_map(n,i,o,s);for(a in n)u=n[a],Z.get_T_fn(e)(a,"property",null,n),Z.get_T_fn(r)(u,function(){return"value of property "+a},null,n);return n},o.coerce=function(e){var r,o,s;Z.simple_map(e,null,t),o={};for(r in e)s=e[r],o[n(r)]=i(s);return o},o.fromJSON=function(e){var i,o,s;Z.simple_map(e,null,t),o={};for(i in e)s=e[i],o[n(i)]=null!=r.fromJSON?r.fromJSON(s):s;return o},o},Z.DS_ID_REGEX="^[-_a-z0-9]([-_a-z0-9.]{0,62}[-_a-z0-9])?$|^[.][-_a-zA-Z0-9]{1,63}$",Z.dsid=function(t,e,r,n){return null==r&&(r="dsid"),Z.string_matching(Z.DS_ID_REGEX)(t,e,r,n),t},Z.SS_ID_REGEX="^[-._+/=a-zA-Z0-9]{1,64}$|^:[-._+/=a-zA-Z0-9]{1,63}$",Z.tid=function(t,e,r,n){return null==r&&(r="tid"),Z.string_matching(Z.SS_ID_REGEX)(t,e,r,n),t},Z.rowid=function(t,e,r,n){return null==r&&(r="rowid"),Z.string_matching(Z.SS_ID_REGEX)(t,e,r,n),t},Z.field_name=function(t,e,r,n){return null==r&&(r="field name"),Z.string_matching(Z.SS_ID_REGEX)(t,e,r,n),t},function(){var t,e,r;r=[];for(t in Z)e=Z[t],Z.hasOwnProperty(t)?r.push(function(t){return e.toString=function(){return"T."+t}}(t)):r.push(void 0);return r}(),te.struct=ee={},ee.define=function(t,e){var r,n,i,o,s,a,u,l,h,c,d,_,p,f,g,y;for(Z.string(t,"struct name"),Z.array(e,"fields"),f=[],p={},s=g=0,y=e.length;y>g;s=++g){i=e[s],Z.array(i,"field","field descriptor",e),Z.check(2<=i.length&&i.length<=3,"does not have length 2 or 3",i,"field descriptor"),c=Z.string(i[0],"field name","field descriptor",e),_=Z.nonnull(i[1],"field type","field descriptor",e),d=i.length<=2?{}:Z.nonnull(i[2],"map of field options","field descriptor",e);for(l in d)"init"!==l&&"initFn"!==l&&Z.fail("unknown option "+l,d,"field options","field descrptor",e);ne.call(d,"init")>=0&&ne.call(d,"initFn")>=0&&Z.fail("both 'init' and 'initFn' specified",d,"field options","field descriptor",e),u="initFn"in d?d.initFn:"init"in d?(a=d.init,function(t){return function(){return t}}(a)):null,r={name:c,type:_,initFn:u},o="undefined"!=typeof G&&null!==G?new G(r):r,f.push(o),p[c]=o}return h="initializer for "+t+" (fields "+function(){var t,e,r;for(r=[],t=0,e=f.length;e>t;t++)i=f[t],r.push(i.name);return r}().join(", ")+")",n=function(t){var e,r,i;Z.defined(t,"x","initializer");for(c in t)e=t[c],t.hasOwnProperty(c)&&Z.check(null!=p[c],function(){return"has an unexpected field "+c},t,"initializer");for(r=0,i=f.length;i>r;r++)o=f[r],t[o.name]&&!t.hasOwnProperty(o.name)&&Z.fail("Has an indirect property "+o.name,t,"initializer"),t.hasOwnProperty(o.name)?(e=t[o.name],this[o.name]=Z.get_coerce_fn(o.type)(e)):null!=o.initFn?this[o.name]=o.initFn():Z.fail("lacks the field "+o.name,t,"initializer");return n.Type(this,"initializer",h,this),this},n.Type=function(e,r,i,s){var a,u,l;for(Z.defined(e,r,i,s),Z.check(e instanceof n,function(){return"is not an instance of "+t},e,r,i,s),u=0,l=f.length;l>u;u++)o=f[u],Z.check(e.hasOwnProperty(o.name),function(){return"lacks the field "+o.name},e,r,i,s),Z.get_T_fn(o.type)(e[o.name],o.name,i,s);for(c in e)a=e[c],e.hasOwnProperty(c)&&Z.check(null!=p[c],"has an unexpected field",c,r,i,s);return e},n.coerce=function(t){return t instanceof n?(n.Type(t),t):new n(t)},n.prototype.toString=function(){var t,e,r,n,i;for(e=this,t=[],n=0,i=f.length;i>n;n++)o=f[n],r=e[o.name],t.push(""+o.name+": "+(Z.is_object(r)&&Z.is_function(r.toString)?r.toString():JSON.stringify(r)));return"{"+t.join(", ")+"}"},n.prototype.toJSON=function(){var t,e,r,n;for(t=this,e=function(){return""+t},r=0,n=f.length;n>r;r++)o=f[r],Z.get_T_fn(o.type)(this[o.name],o.name,null,e);return this},n.fromJSON=function(t){var e,r;Z.simple_map(t,"input"),e={};for(l in t)r=t[l],o=p[l],null!=o&&(_=o.type,e[l]=null!=_.fromJSON?_.fromJSON(r):r);return new n(e)},n.toString=function(){return"struct "+t},n},G=ee.define("StructField",[["name",Z.string],["type",Z.defined],["initFn",Z.defined]]),ee.toJSO=function(t){var e,r,n,i;if("object"!=typeof t)return t;if(Z.is_array(t))return function(){var r,n,i;for(i=[],r=0,n=t.length;n>r;r++)e=t[r],i.push(ee.toJSO(e));return i}();n={};for(r in t)i=t[r],t.hasOwnProperty(r)&&(n[r]=ee.toJSO(i));return n},ee.union_as_list=function(t,e){var r,n,i,o,s,a,u,l,h,c,d;for(Z.string(t,"union name"),Z.array(e,"variants"),n=function(){throw new Error("Use "+t+".from_array instead")},l={},u=[],h=function(e,r,i){var o;return o=ee.define(""+t+"."+e,i),o.prototype.tag=function(){return e},o.prototype.toString=function(){return""+t+"."+e+"("+JSON.stringify(this)+")"},o.prototype.toJSON=function(){var t,n,i,o,s,a;for(t=[e],s=0,a=r.length;a>s;s++)n=r[s],i=n[0],o=n[1],Z.get_T_fn(o)(this[i],i),t.push(this[i]);return t},o.from_array=function(n){var i,s,a,u,l,h,c;for(l="initializer for "+t,Z.array(n,"initializer",l),Z.check(n.length===r.length+1,"does not have length "+(r.length+1),n,"initializer",l),Z.check(n[0]===e,"does not have tag "+e,n,"initializer",l),i={_tag:e},a=h=0,c=r.length;c>h;a=++h)s=r[a],u=s[0],i[u]=n[a+1];return new o(i)},o.fromJSON=function(t){return t.length>r.length+1&&(t=t.slice(0,r.length+1)),o.from_array(t)},o.coerce=function(t){return t instanceof o?(o.Type(t),t):o.from_array(t)},l[e]=o,n[e]=o},c=0,d=e.length;d>c;c++)i=e[c],Z.array(i,"variant","variant descriptor",e),Z.check(2===i.length,"does not have length 2",i,"variant descriptor",e),a=Z.string(i[0],"tag","tag",e),o=Z.array(i[1],"fields","variant descriptor",e),s=o.slice(0),s.unshift(["_tag",Z.member([a])]),h(a,o,s),u.push(a);return r="initializer for "+t+" (variants "+u.join(", ")+")",n.from_array=function(e){var r,n;return n="initializer for "+t,Z.array(e,"initializer",n),Z.check(e.length>=1,"lacks a tag",e,"initializer",n),r=e[0],Z.string(r,"tag",n,e),Z.member(u)(r),l[r].from_array(e)},n.fromJSON=function(e){var r,n;return n="initializer for "+t,Z.array(e,"initializer",n),Z.check(e.length>=1,"lacks a tag",e,"initializer",n),r=e[0],Z.string(r,"tag",n,e),Z.member(u)(r),l[r].fromJSON(e)},n.Type=function(e,r,n,i){var o;return null==n&&(n=""+t+".Type"),Z.defined(e,r,n,i),Z.defined(e.tag,"tag",n,i),o=e.tag(),Z.string(o,"tag","initializer",e),Z.member(u)(o),l[o].Type(e,null,"object of type "+t),e},n.coerce=function(t){var e,r;for(r in l)if(e=l[r],t instanceof e)return e.Type(t),t;return n.from_array(t)},n.toString=function(){return"union "+t},n},te.nonzero_int64_approximate_regex=new RegExp("^-?[1-9][0-9]{0,18}$"),te.int64_max_str="9223372036854775807",te.int64_min_str="-9223372036854775808",te.ACL_TID=":acl",te.ROLE_OWNER=3e3,te.ROLE_EDITOR=2e3,te.ROLE_VIEWER=1e3,te.int64_string_less_than=function(t,e){var r,n,i;return t===e?!1:(n="0"===t.charAt(0),i="0"===e.charAt(0),n&&!i?!0:i&&!n?!1:(r=t.length===e.length?t>e:t.length>e.length,n&&i?r:!r))},te.is_valid_int64_string=function(t){return Z.is_string(t)?"0"===t?!0:te.nonzero_int64_approximate_regex.test(t)?"-"===t.charAt(0)?t.length