From 9798bac2391be6d245bb9fa610eaeb86b313f2bd Mon Sep 17 00:00:00 2001 From: Dallan Quass Date: Wed, 22 Jan 2014 21:48:57 -0600 Subject: [PATCH] merge files from steroids seed --- .bowerrc | 3 + .cordova/README.md | 13 + .cordova/config.json | 2 +- .gitignore | 6 +- Gruntfile.js | 16 + README.md | 7 +- bower.json | 17 + config/application.coffee | 58 + merges/README.md | 12 + package.json | 19 + platforms/.gitignore | 2 + platforms/README.md | 8 + plugins/.gitignore | 2 + plugins/README.md | 3 + www/config.android.xml | 16 + www/config.ios.xml | 29 + www/config.tizen.xml | 43 + www/config.xml | 18 +- www/index.html | 9 +- www/js/console.log.android.js | 1 + www/js/console.log.js | 37 + www/js/onerror.android.js | 1 + www/js/onerror.js | 13 + www/lib/js/steroids-js/.bower.json | 16 + www/lib/js/steroids-js/component.json | 6 + www/lib/js/steroids-js/steroids.js | 2674 +++++++++++++++++++++++++ www/loading.html | 57 + www/loading.png | Bin 0 -> 8807 bytes 28 files changed, 3064 insertions(+), 24 deletions(-) create mode 100644 .bowerrc create mode 100644 .cordova/README.md create mode 100644 Gruntfile.js create mode 100644 bower.json create mode 100644 config/application.coffee create mode 100644 merges/README.md create mode 100644 package.json create mode 100644 platforms/README.md create mode 100644 plugins/README.md create mode 100644 www/config.android.xml create mode 100644 www/config.ios.xml create mode 100644 www/config.tizen.xml create mode 100644 www/js/console.log.android.js create mode 100644 www/js/console.log.js create mode 100644 www/js/onerror.android.js create mode 100644 www/js/onerror.js create mode 100644 www/lib/js/steroids-js/.bower.json create mode 100644 www/lib/js/steroids-js/component.json create mode 100644 www/lib/js/steroids-js/steroids.js create mode 100644 www/loading.html create mode 100644 www/loading.png diff --git a/.bowerrc b/.bowerrc new file mode 100644 index 0000000..e9824f1 --- /dev/null +++ b/.bowerrc @@ -0,0 +1,3 @@ +{ + "directory": "www/components" +} diff --git a/.cordova/README.md b/.cordova/README.md new file mode 100644 index 0000000..f9a6643 --- /dev/null +++ b/.cordova/README.md @@ -0,0 +1,13 @@ +#Steroids compatibility with Cordova CLI + +The `.cordova` folder is included in new Steroids projects for initial [Cordova CLI](https://github.com/apache/cordova-cli) compatibility. + +Cordova CLI commands can thus be run inside a Steroids project. The support is not complete; the current main use case is to facilitate plugin development in Xcode/Eclipse without having to create a separate Cordova project. You shouldn't use the native iOS/Android projects for actual development, since Steroids.js features are unavailable there. + +Note that you have to load `cordova.js` from the `www/` root in Cordova projects, instead of via `localhost` as it is in Steroids: + +``` + +``` + +The hooks in the `hooks/` folder only affect Cordova CLI commands. For Steroids pre- and post-make hooks, see `config/application.coffee`. \ No newline at end of file diff --git a/.cordova/config.json b/.cordova/config.json index a1104f0..fafc7fe 100644 --- a/.cordova/config.json +++ b/.cordova/config.json @@ -1 +1 @@ -{"id":"com.ionicframework.starter","name":"StarterApp"} \ No newline at end of file +{"id":"com.ionicframework.appgyverstarter","name":"IonicAngularAppGyverSeed"} \ No newline at end of file diff --git a/.gitignore b/.gitignore index f6c8104..b8279af 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ -*.keystore -*.sw* -platforms/^.* +.DS_Store +/dist +node_modules diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 0000000..1752eaf --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,16 @@ +/* + * Default Gruntfile for AppGyver Steroids + * http://www.appgyver.com + * + * Licensed under the MIT license. + */ + +'use strict'; + +module.exports = function(grunt) { + + grunt.loadNpmTasks("grunt-steroids"); + + grunt.registerTask("default", ["steroids-make", "steroids-compile-sass"]); + +}; diff --git a/README.md b/README.md index f9028d5..47e752a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ -ionic-angular-cordova-seed +ionic-angular-appgyver-seed ========================== -The perfect starting point for an Ionic project. +The perfect starting point for an Ionic + AppGyver project. -- [Ionic Tutorials](http://ionicframework.com/tutorials/) \ No newline at end of file +- [Ionic Tutorials](http://ionicframework.com/tutorials/) +- [AppGyver Tutorials](http://academy.appgyver.com/courses/steroids) \ No newline at end of file diff --git a/bower.json b/bower.json new file mode 100644 index 0000000..8a9214d --- /dev/null +++ b/bower.json @@ -0,0 +1,17 @@ +{ + "name": "ionic-angular-appgyver-seed", + "version": "0.0.1", + "authors": [ + ], + "ignore": [ + "**/.*", + "node_modules", + "www/components", + "www/spec", + "test", + "tests" + ], + "dependencies": { + "steroids-js": "3.1.x" + } +} diff --git a/config/application.coffee b/config/application.coffee new file mode 100644 index 0000000..e3097b8 --- /dev/null +++ b/config/application.coffee @@ -0,0 +1,58 @@ +# For an explanation of the steroids.config properties, see the guide at +# http://guides.appgyver.com/steroids/guides/project_configuration/config-application-coffee/ + +steroids.config.name = "ionic-angular-appgyver-seed" + +# -- Initial Location -- +steroids.config.location = "http://localhost/index.html" + +# -- Tab Bar -- +# steroids.config.tabBar.enabled = true +# steroids.config.tabBar.tabs = [ +# { +# title: "Index" +# icon: "icons/pill@2x.png" +# location: "http://localhost/index.html" +# }, +# { +# title: "Internet" +# icon: "icons/telescope@2x.png" +# location: "http://www.google.com" +# } +# ] + +# steroids.config.tabBar.tintColor = "#000000" +# steroids.config.tabBar.tabTitleColor = "#00aeef" +# steroids.config.tabBar.selectedTabTintColor = "#ffffff" +# steroids.config.tabBar.selectedTabBackgroundImage = "icons/pill@2x.png" + +# steroids.config.tabBar.backgroundImage = "" + +# -- Navigation Bar -- +steroids.config.navigationBar.tintColor = "#00aeef" +steroids.config.navigationBar.titleColor = "#ffffff" +steroids.config.navigationBar.buttonTintColor = "#ffffff" +steroids.config.navigationBar.buttonTitleColor = "#ffffff" + +# steroids.config.navigationBar.landscape.backgroundImage = "" +# steroids.config.navigationBar.portrait.backgroundImage = "" + +# -- Android Loading Screen +steroids.config.loadingScreen.tintColor = "#262626" + +# -- iOS Status Bar -- +steroids.config.statusBar.enabled = true +steroids.config.statusBar.style = "default" + +# -- File Watcher -- +# steroids.config.watch.exclude = ["www/my_excluded_file.js", "www/my_excluded_dir"] + +# -- Pre- and Post-Make hooks -- +# steroids.config.hooks.preMake.cmd = "echo" +# steroids.config.hooks.preMake.args = ["running yeoman"] +# steroids.config.hooks.postMake.cmd = "echo" +# steroids.config.hooks.postMake.args = ["cleaning up files"] + +# -- Default Editor -- +# steroids.config.editor.cmd = "subl" +# steroids.config.editor.args = ["."] diff --git a/merges/README.md b/merges/README.md new file mode 100644 index 0000000..b048913 --- /dev/null +++ b/merges/README.md @@ -0,0 +1,12 @@ +Use the `merges` directory just like you would in a vanilla Cordova project. + +Example structure: +`/merges/android/index.html` +`/merges/ios/index.html` + +This will generate `dist/index.android.html` (android) and `dist/index.html` (ios) files during Steroids `make`. +Read more about the `.android.` extension here: http://guides.appgyver.com/steroids/guides/android/android-extension/ + +Merge files will overwrite existing files when building to the `dist` directory. + +For example: `www/index.html` would be overwritten by `merges/ios/index.html` and `www/index.android.html` would be overwritten by `merges/android/index.html`. \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..4e490c1 --- /dev/null +++ b/package.json @@ -0,0 +1,19 @@ +{ + "name": "mySteroidsProject", + "version": "0.0.1", + "description": "My awesome AppGyver Steroids project.", + "repository": "N/A", + "readme":"N/A", + "private": true, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "devDependencies": { + "grunt-steroids": "0.x" + }, + "license": "none", + "engines": { + "steroids": "3.1.9" + } +} diff --git a/platforms/.gitignore b/platforms/.gitignore index 5e7d273..3c8f938 100644 --- a/platforms/.gitignore +++ b/platforms/.gitignore @@ -2,3 +2,5 @@ * # Except this file !.gitignore +# and README.md +!README.md \ No newline at end of file diff --git a/platforms/README.md b/platforms/README.md new file mode 100644 index 0000000..daf2473 --- /dev/null +++ b/platforms/README.md @@ -0,0 +1,8 @@ +The `platforms/` folder houses native Android and iOS Cordova projects, added with the + +``` +$ cordova platform add + +``` + +command. See `.cordova/readme.md` for more information about Cordova CLI compatibility with Steroids. \ No newline at end of file diff --git a/plugins/.gitignore b/plugins/.gitignore index 5e7d273..3c8f938 100644 --- a/plugins/.gitignore +++ b/plugins/.gitignore @@ -2,3 +2,5 @@ * # Except this file !.gitignore +# and README.md +!README.md \ No newline at end of file diff --git a/plugins/README.md b/plugins/README.md new file mode 100644 index 0000000..2202539 --- /dev/null +++ b/plugins/README.md @@ -0,0 +1,3 @@ +Unlike in vanilla Cordova projects, custom plugins are configured in the cloud: http://guides.appgyver.com/steroids/guides/cloud_services/plugin-config/ + +For a list of plugins included with AppGyver Scanner, see the GitHub repo at https://github.com/AppGyver/steroids-plugins \ No newline at end of file diff --git a/www/config.android.xml b/www/config.android.xml new file mode 100644 index 0000000..0d35055 --- /dev/null +++ b/www/config.android.xml @@ -0,0 +1,16 @@ + + + IonicAngularAppGyverSeed + + A sample Ionic Framework app using AppGyver and AngularJS + + + Apache Cordova Team + + + + + + + + \ No newline at end of file diff --git a/www/config.ios.xml b/www/config.ios.xml new file mode 100644 index 0000000..1ab6b1b --- /dev/null +++ b/www/config.ios.xml @@ -0,0 +1,29 @@ + + + IonicAngularAppGyverSeed + + A sample Ionic Framework app using AppGyver and AngularJS + + + Apache Cordova Team + + + + + + + + + + + + + + + + + + + + + diff --git a/www/config.tizen.xml b/www/config.tizen.xml new file mode 100644 index 0000000..d4cccbe --- /dev/null +++ b/www/config.tizen.xml @@ -0,0 +1,43 @@ + + + + + + + + + My Steroids App + + + + + + + + + + + + + + + + + + + + * + default-src *; script-src 'unsafe-inline' *; + + + diff --git a/www/config.xml b/www/config.xml index 894a8c5..a789223 100644 --- a/www/config.xml +++ b/www/config.xml @@ -1,16 +1,6 @@ + + - - StarterApp - - A sample Ionic Framework app using Cordova and AngularJS - - - Apache Cordova Team - - - - - - - + + HelloCordova diff --git a/www/index.html b/www/index.html index 2253b49..ce0cb0b 100644 --- a/www/index.html +++ b/www/index.html @@ -3,13 +3,15 @@ - Ionic Seed App + Ionic Angular AppGyver Seed App + + @@ -19,8 +21,9 @@ - - + + + diff --git a/www/js/console.log.android.js b/www/js/console.log.android.js new file mode 100644 index 0000000..3d93504 --- /dev/null +++ b/www/js/console.log.android.js @@ -0,0 +1 @@ +// no need to override in android diff --git a/www/js/console.log.js b/www/js/console.log.js new file mode 100644 index 0000000..6df73ea --- /dev/null +++ b/www/js/console.log.js @@ -0,0 +1,37 @@ +// When using iOS simulator, the first console.log messages might not appear before Cordova has overridden the console.log +// Here we buffer the messages and output when override is done. + +(function(window) { + + var logMessages = []; + + var defaultConsoleLog = window.console.log; + + window.console.log = function(args) { + logMessages.push(args); + } + + var bufferConsoleLogUntilReadyAndFlush = function() { + var cordovaOverride = "logWithArgs"; + var isNative = "[native code]"; + + if ( (defaultConsoleLog.toString().indexOf(cordovaOverride) > -1) || + (defaultConsoleLog.toString().indexOf(isNative) > -1) ) { + window.console.log = defaultConsoleLog; + for (var i=0; i= 0) { + return true; + } else { + return false; + } + }; + return (_ref = callbacks.onSuccess) != null ? _ref.call() : void 0; + }; + + WebView.prototype.setBackgroundColor = function(options, callbacks) { + var newColor; + if (options == null) { + options = {}; + } + if (callbacks == null) { + callbacks = {}; + } + newColor = options.constructor.name === "String" ? options : options.color; + return steroids.nativeBridge.nativeCall({ + method: "setWebViewBackgroundColor", + parameters: { + color: newColor + }, + successCallbacks: [callbacks.onSuccess], + failureCallbacks: [callbacks.onFailure] + }); + }; + + return WebView; + +})(); +;var PreviewFileView; + +PreviewFileView = (function() { + function PreviewFileView(options) { + var _ref; + if (options == null) { + options = {}; + } + this.filePath = options.constructor.name === "String" ? options : options.filePath; + this.relativeTo = (_ref = options.relativeTo) != null ? _ref : steroids.app.path; + } + + PreviewFileView.prototype.getNativeFilePath = function() { + return "" + this.relativeTo + "/" + this.filePath; + }; + + return PreviewFileView; + +})(); +;var Audio; + +Audio = (function() { + function Audio() {} + + Audio.prototype.play = function(options, callbacks) { + var readyCapableDevice, + _this = this; + if (options == null) { + options = {}; + } + if (callbacks == null) { + callbacks = {}; + } + readyCapableDevice = false; + setTimeout(function() { + if (readyCapableDevice) { + return; + } + return navigator.notification.alert("Audio playback requires a newer version of Scanner, please update from the App Store.", null, "Update Required"); + }, 500); + return steroids.on("ready", function() { + var mediaPath, relativeTo, _ref; + readyCapableDevice = true; + relativeTo = (_ref = options.relativeTo) != null ? _ref : steroids.app.path; + mediaPath = options.constructor.name === "String" ? "" + relativeTo + "/" + options : "" + relativeTo + "/" + options.path; + return steroids.nativeBridge.nativeCall({ + method: "play", + parameters: { + filenameWithPath: mediaPath + }, + successCallbacks: [callbacks.onSuccess], + failureCallbacks: [callbacks.onFailure] + }); + }); + }; + + Audio.prototype.prime = function(options, callbacks) { + if (options == null) { + options = {}; + } + if (callbacks == null) { + callbacks = {}; + } + return steroids.nativeBridge.nativeCall({ + method: "primeAudioPlayer", + parameters: options, + successCallbacks: [callbacks.onSuccess], + failureCallbacks: [callbacks.onFailure] + }); + }; + + return Audio; + +})(); +;var OAuth2Flow; + +OAuth2Flow = (function() { + function OAuth2Flow(options) { + this.options = options != null ? options : {}; + this.options.callbackUrl = "http://localhost:13101/" + this.options.callbackPath; + } + + OAuth2Flow.prototype.authenticate = function() { + throw "ERROR: " + this.name + " has not overridden authenticate method"; + }; + + OAuth2Flow.prototype.concatenateUrlParams = function(params) { + var first, key, result, value; + first = true; + result = ""; + for (key in params) { + value = params[key]; + if (first) { + result = result.concat("?"); + first = false; + } else { + result = result.concat("&"); + } + result = result.concat("" + key + "=" + (encodeURIComponent(value))); + } + return result; + }; + + OAuth2Flow.prototype.urlEncode = function(string) { + var c, hex, i, reserved_chars, str_len, string_arr; + hex = function(code) { + var result; + result = code.toString(16).toUpperCase(); + if (result.length < 2) { + result = 0 + result; + } + return "%" + result; + }; + if (!string) { + return ""; + } + string = string + ""; + reserved_chars = /[ \r\n!*"'();:@&=+$,\/?%#\[\]<>{}|`^\\\u0080-\uffff]/; + str_len = string.length; + i = void 0; + string_arr = string.split(""); + c = void 0; + i = 0; + while (i < str_len) { + if (c = string_arr[i].match(reserved_chars)) { + c = c[0].charCodeAt(0); + if (c < 128) { + string_arr[i] = hex(c); + } else if (c < 2048) { + string_arr[i] = hex(192 + (c >> 6)) + hex(128 + (c & 63)); + } else if (c < 65536) { + string_arr[i] = hex(224 + (c >> 12)) + hex(128 + ((c >> 6) & 63)) + hex(128 + (c & 63)); + } else { + if (c < 2097152) { + string_arr[i] = hex(240 + (c >> 18)) + hex(128 + ((c >> 12) & 63)) + hex(128 + ((c >> 6) & 63)) + hex(128 + (c & 63)); + } + } + } + i++; + } + return string_arr.join(""); + }; + + return OAuth2Flow; + +})(); +;var AuthorizationCodeFlow, _ref, + __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; + +AuthorizationCodeFlow = (function(_super) { + __extends(AuthorizationCodeFlow, _super); + + function AuthorizationCodeFlow() { + this.finish = __bind(this.finish, this); + this.authenticate = __bind(this.authenticate, this); + _ref = AuthorizationCodeFlow.__super__.constructor.apply(this, arguments); + return _ref; + } + + AuthorizationCodeFlow.prototype.authenticate = function() { + var authenticationLayer, authorizationUrl; + this.xhrAuthorizationParams = { + response_type: "code", + client_id: this.options.clientID, + redirect_uri: this.options.callbackUrl, + scope: this.options.scope || "" + }; + authorizationUrl = this.options.authorizationUrl.concat(this.concatenateUrlParams(this.xhrAuthorizationParams)); + authenticationLayer = new steroids.views.WebView({ + location: authorizationUrl + }); + return steroids.modal.show({ + layer: authenticationLayer + }); + }; + + AuthorizationCodeFlow.prototype.finish = function(callback) { + var body, key, request, value, _ref1, + _this = this; + this.xhrAccessTokenParams = { + client_id: this.options.clientID, + client_secret: this.options.clientSecret, + redirect_uri: this.callbackUrl, + grant_type: "authorization_code" + }; + request = new XMLHttpRequest(); + request.open("POST", this.options.accessTokenUrl); + body = []; + _ref1 = this.xhrAccessTokenParams; + for (key in _ref1) { + value = _ref1[key]; + body.push("" + key + "=" + (this.urlEncode(value))); + } + body.push("code=" + steroids.view.params['code']); + body = body.sort().join('&'); + request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); + request.onreadystatechange = function() { + var responseJSON; + if (request.readyState === 4) { + responseJSON = JSON.parse(request.responseText); + callback(responseJSON.access_token); + return steroids.modal.hide(); + } + }; + return request.send(body); + }; + + return AuthorizationCodeFlow; + +})(OAuth2Flow); +;var ClientCredentialsFlow, _ref, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; + +ClientCredentialsFlow = (function(_super) { + __extends(ClientCredentialsFlow, _super); + + function ClientCredentialsFlow() { + _ref = ClientCredentialsFlow.__super__.constructor.apply(this, arguments); + return _ref; + } + + ClientCredentialsFlow.prototype.authenticate = function(callback) { + var body, key, request, value, _ref1, + _this = this; + this.xhrAccessTokenParams = { + client_id: this.options.clientID, + client_secret: this.options.clientSecret, + scope: this.options.scope || "", + grant_type: "client_credentials" + }; + request = new XMLHttpRequest(); + request.open("POST", this.options.accessTokenUrl); + body = []; + _ref1 = this.xhrAccessTokenParams; + for (key in _ref1) { + value = _ref1[key]; + body.push("" + key + "=" + (this.urlEncode(value))); + } + body = body.sort().join('&'); + request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); + request.onreadystatechange = function() { + var responseJSON; + if (request.readyState === 4) { + responseJSON = JSON.parse(request.responseText); + return callback(responseJSON.access_token); + } + }; + return request.send(body); + }; + + return ClientCredentialsFlow; + +})(OAuth2Flow); +;var OAuth2; + +OAuth2 = (function() { + function OAuth2() {} + + OAuth2.AuthorizationCodeFlow = AuthorizationCodeFlow; + + OAuth2.ClientCredentialFlow = ClientCredentialsFlow; + + return OAuth2; + +})(); +;var RSS; + +RSS = (function() { + function RSS(options) { + this.options = options != null ? options : {}; + this.url = options.constructor.name === "String" ? options : options.url; + if (!this.url) { + throw "URL required"; + } + } + + return RSS; + +})(); +;var TouchDB, + __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + +TouchDB = (function() { + TouchDB.baseURL = "http://.touchdb."; + + function TouchDB(options) { + var _this = this; + this.options = options != null ? options : {}; + this.replicateFrom = __bind(this.replicateFrom, this); + this.fireCallbacks = __bind(this.fireCallbacks, this); + if (!this.options.name) { + throw "Database name required"; + } + this.replicas = {}; + this.baseURL = "" + TouchDB.baseURL + "/" + this.options.name; + this.eventCallbacks = {}; + this.createDB({}, { + onSuccess: function() { + return _this.fireCallbacks('ready'); + }, + onFailure: function(error) { + if (error.status === 412) { + return _this.fireCallbacks('ready'); + } else { + return console.log("unable to initialize database: " + error.error); + } + } + }); + this.startMonitoringChanges({}, { + onChange: function() { + return _this.fireCallbacks('change'); + } + }); + } + + TouchDB.prototype.fireCallbacks = function(name) { + var callback, _i, _len, _ref, _results; + if (!this.eventCallbacks[name]) { + return; + } + _ref = this.eventCallbacks[name]; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + callback = _ref[_i]; + _results.push(callback.call()); + } + return _results; + }; + + TouchDB.prototype.on = function(eventName, callback) { + var _base; + (_base = this.eventCallbacks)[eventName] || (_base[eventName] = []); + return this.eventCallbacks[eventName].push(callback); + }; + + TouchDB.prototype.startMonitoringChanges = function(options, callbacks) { + var request, + _this = this; + if (options == null) { + options = {}; + } + if (callbacks == null) { + callbacks = {}; + } + request = new XMLHttpRequest(); + request.open("GET", "" + this.baseURL + "/_changes?feed=continuous"); + request.onreadystatechange = function() { + if (request.readyState !== 3) { + return; + } + return callbacks.onChange(); + }; + return request.send(); + }; + + TouchDB.prototype.createDB = function(options, callbacks) { + var request, + _this = this; + if (options == null) { + options = {}; + } + if (callbacks == null) { + callbacks = {}; + } + request = new XMLHttpRequest(); + request.open("PUT", "" + this.baseURL + "/"); + request.onreadystatechange = function() { + var errorObj, responseObj; + if (request.readyState !== 4) { + return; + } + if (request.status === 412) { + errorObj = JSON.parse(request.responseText); + if (callbacks.onFailure) { + callbacks.onFailure(errorObj); + } + } + if (request.status === 201) { + responseObj = JSON.parse(request.responseText); + if (callbacks.onSuccess) { + return callbacks.onSuccess(responseObj); + } + } + }; + return request.send(); + }; + + TouchDB.prototype.addTwoWayReplica = function(options, callbacks) { + var fromCloudAdded, fromCloudFailed, toCloudAdded, toCloudFailed, + _this = this; + if (options == null) { + options = {}; + } + if (callbacks == null) { + callbacks = {}; + } + toCloudAdded = function() { + return _this.startReplication({ + source: options.url, + target: _this.options.name + }, { + onSuccess: fromCloudAdded, + onFailure: fromCloudFailed + }); + }; + toCloudFailed = function() { + if (callbacks.onFailure) { + return callbacks.onFailure(); + } + }; + fromCloudAdded = function() { + _this.replicas[options.url] = {}; + if (callbacks.onSuccess) { + return callbacks.onSuccess(); + } + }; + fromCloudFailed = function() { + if (callbacks.onFailure) { + return callbacks.onFailure(); + } + }; + return this.startReplication({ + source: this.options.name, + target: options.url + }, { + onSuccess: toCloudAdded, + onFailure: toCloudFailed + }); + }; + + TouchDB.prototype.replicateFrom = function(options, callbacks) { + if (options == null) { + options = {}; + } + if (callbacks == null) { + callbacks = {}; + } + return this.startReplication({ + source: options.url, + target: this.options.name + }, { + onSuccess: callbacks.onSuccess, + onFailure: callbacks.onFailure + }); + }; + + TouchDB.prototype.startReplication = function(options, callbacks) { + var request, + _this = this; + if (options == null) { + options = {}; + } + if (callbacks == null) { + callbacks = {}; + } + request = new XMLHttpRequest(); + request.open("POST", "" + TouchDB.baseURL + "/_replicate"); + request.onreadystatechange = function() { + var errorObj, responseObj; + if (request.readyState !== 4) { + return; + } + if (request.status === 412) { + errorObj = JSON.parse(request.responseText); + callbacks.onFailure(errorObj); + } + if (request.status === 200) { + responseObj = JSON.parse(request.responseText); + return callbacks.onSuccess.call(responseObj); + } + }; + return request.send(JSON.stringify({ + source: options.source, + target: options.target, + continuous: true + })); + }; + + return TouchDB; + +})(); +;var SQLiteDB, + __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + +SQLiteDB = (function() { + function SQLiteDB(options) { + this.options = options != null ? options : {}; + this.execute = __bind(this.execute, this); + this.createTable = __bind(this.createTable, this); + this.dropTable = __bind(this.dropTable, this); + this.databaseName = options.constructor.name === "String" ? options : options.name; + if (!window.sqlitePlugin) { + throw "window.sqlitePlugin is undefined, please load plugin"; + } + if (!this.databaseName) { + throw "database name required"; + } + } + + SQLiteDB.prototype.dropTable = function(opts, callbacks) { + var tableName; + if (opts == null) { + opts = {}; + } + if (callbacks == null) { + callbacks = {}; + } + tableName = opts.constructor.name === "String" ? opts : opts.name; + steroids.debug("dropping table " + tableName); + return this.execute({ + statement: "DROP TABLE " + tableName + }, callbacks); + }; + + SQLiteDB.prototype.createTable = function(opts, callbacks) { + var columnDefinitionString, columnsString, key, statement, tableName, type; + if (opts == null) { + opts = {}; + } + if (callbacks == null) { + callbacks = {}; + } + tableName = opts.constructor.name === "String" ? opts : opts.name; + statement = "CREATE TABLE " + tableName; + if (opts.columns != null) { + columnsString = (function() { + var _ref, _results; + _ref = opts.columns; + _results = []; + for (key in _ref) { + type = _ref[key]; + _results.push("" + key + " " + (type.toUpperCase())); + } + return _results; + })(); + columnDefinitionString = columnsString.join(", "); + } + steroids.debug("creating table " + tableName + " with " + columnDefinitionString); + if (columnDefinitionString != null) { + statement += " (" + columnDefinitionString + ")"; + } + return this.execute({ + statement: statement + }, callbacks); + }; + + SQLiteDB.prototype.execute = function(opts, callbacks) { + var statement, + _this = this; + if (opts == null) { + opts = {}; + } + if (callbacks == null) { + callbacks = {}; + } + statement = opts.constructor.name === "String" ? opts : opts.statement; + steroids.debug("stament to execute: " + statement); + return document.addEventListener('deviceready', function() { + if (!_this.db) { + _this.db = window.sqlitePlugin.openDatabase(_this.databaseName); + } + return _this.db.transaction(function(tx) { + var failure, success; + steroids.debug("execute transaction started"); + success = function(stx, res) { + var i, rows, _i, _ref; + rows = []; + for (i = _i = 0, _ref = res.rows.length - 1; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) { + rows.push(res.rows.item(i)); + } + steroids.debug("execute success, returned " + rows.length + " rows"); + if (callbacks.onSuccess) { + return callbacks.onSuccess(rows, res, stx); + } + }; + failure = function(tx, err) { + steroids.debug("execute failure -- err.message: " + err.message); + if (callbacks.onFailure) { + return callbacks.onFailure(err, tx); + } + }; + return tx.executeSql(statement, [], success, failure); + }); + }); + }; + + return SQLiteDB; + +})(); +;var XHR, + __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + +XHR = (function() { + XHR.prototype.headers = []; + + function XHR() { + this.setRequestHeader = __bind(this.setRequestHeader, this); + this.send = __bind(this.send, this); + this.method = void 0; + this.url = void 0; + this.async = void 0; + this.status = 0; + this.readyState = 0; + this.headers = {}; + } + + XHR.prototype.open = function(methodString, urlString, isAsync) { + if (isAsync == null) { + isAsync = true; + } + this.method = methodString; + this.url = urlString; + return this.async = isAsync; + }; + + XHR.prototype.send = function(data) { + if (!(this.method && this.url)) { + throw "Error: INVALID_STATE_ERR: DOM Exception 11"; + } + if (this.method !== "GET") { + throw "Method not implemented"; + } + return this.fetch({ + url: this.url, + filenameWithPath: "temp", + headers: this.headers + }); + }; + + XHR.prototype.setRequestHeader = function(name, value) { + return this.headers[name] = value; + }; + + XHR.prototype.fetch = function(options, callbacks) { + var destinationPath; + if (options == null) { + options = {}; + } + if (callbacks == null) { + callbacks = {}; + } + destinationPath = options.constructor.name === "String" ? options : options.absoluteDestinationPath; + return steroids.nativeBridge.nativeCall({ + method: "downloadFile", + parameters: { + url: options.url || this.url, + headers: options.headers || this.headers, + filenameWithPath: destinationPath + }, + successCallbacks: [callbacks.onSuccess], + failureCallbacks: [callbacks.onFailure] + }); + }; + + return XHR; + +})(); +;var Analytics; + +Analytics = (function() { + function Analytics() {} + + Analytics.prototype.track = function(event, callbacks) { + if (event == null) { + event = {}; + } + if (callbacks == null) { + callbacks = {}; + } + return steroids.nativeBridge.nativeCall({ + method: "recordEvent", + parameters: { + type: "custom", + attributes: event + }, + successCallbacks: [callbacks.onSuccess], + failureCallbacks: [callbacks.onFailure] + }); + }; + + return Analytics; + +})(); +;var Screen; + +Screen = (function() { + function Screen() {} + + Screen.prototype.edges = { + LEFT: "left", + RIGHT: "right", + TOP: "top", + BOTTOM: "bottom" + }; + + Screen.prototype.freeze = function(options, callbacks) { + if (options == null) { + options = {}; + } + if (callbacks == null) { + callbacks = {}; + } + return steroids.nativeBridge.nativeCall({ + method: "freeze", + parameters: options, + successCallbacks: [callbacks.onSuccess], + failureCallbacks: [callbacks.onFailure] + }); + }; + + Screen.prototype.unfreeze = function(options, callbacks) { + if (options == null) { + options = {}; + } + if (callbacks == null) { + callbacks = {}; + } + return steroids.nativeBridge.nativeCall({ + method: "unfreeze", + parameters: options, + successCallbacks: [callbacks.onSuccess], + failureCallbacks: [callbacks.onFailure] + }); + }; + + Screen.prototype.capture = function(options, callbacks) { + if (options == null) { + options = {}; + } + if (callbacks == null) { + callbacks = {}; + } + return steroids.nativeBridge.nativeCall({ + method: "takeScreenshot", + parameters: options, + successCallbacks: [callbacks.onSuccess], + failureCallbacks: [callbacks.onFailure] + }); + }; + + return Screen; + +})(); +;var File; + +File = (function() { + function File(options) { + var _ref; + if (options == null) { + options = {}; + } + this.path = options.constructor.name === "String" ? options : options.path; + this.relativeTo = (_ref = options.relativeTo) != null ? _ref : steroids.app.path; + } + + File.prototype.resizeImage = function(options, callbacks) { + var nativeCompression, parameters, userCompression, _ref, _ref1, _ref2, _ref3; + if (options == null) { + options = {}; + } + if (callbacks == null) { + callbacks = {}; + } + if (this.relativeTo !== steroids.app.userFilesPath) { + throw "Cannot resize images outside `steroids.app.userFilesPath`. Files must first be copied under application document root and then resized."; + } + userCompression = (_ref = (_ref1 = options.format) != null ? _ref1.compression : void 0) != null ? _ref : 100; + nativeCompression = 1 - (userCompression / 100); + parameters = { + filenameWithPath: "" + this.relativeTo + "/" + this.path, + format: (_ref2 = (_ref3 = options.format) != null ? _ref3.type : void 0) != null ? _ref2 : "jpg", + compression: nativeCompression + }; + if (options.constraint != null) { + switch (options.constraint.dimension) { + case "width": + parameters.size = { + width: options.constraint.length + }; + break; + case "height": + parameters.size = { + height: options.constraint.length + }; + break; + default: + throw "unknown constraint name"; + } + } else { + throw "constraint not specified"; + } + return steroids.nativeBridge.nativeCall({ + method: "resizeImage", + parameters: parameters, + successCallbacks: [callbacks.onSuccess], + failureCallbacks: [callbacks.onFailure] + }); + }; + + File.prototype.unzip = function(options, callbacks) { + var destinationPath, parameters, sourcePath; + if (options == null) { + options = {}; + } + if (callbacks == null) { + callbacks = {}; + } + sourcePath = "" + this.relativeTo + "/" + this.path; + destinationPath = options.constructor.name === "String" ? options : options.destinationPath; + parameters = { + filenameWithPath: sourcePath, + path: destinationPath + }; + return steroids.nativeBridge.nativeCall({ + method: "unzip", + parameters: parameters, + successCallbacks: [callbacks.onSuccess], + failureCallbacks: [callbacks.onFailure] + }); + }; + + return File; + +})(); +;var OpenURL; + +OpenURL = (function() { + function OpenURL() {} + + OpenURL.open = function(options, callbacks) { + var url; + if (options == null) { + options = {}; + } + if (callbacks == null) { + callbacks = {}; + } + url = options.constructor.name === "String" ? options : options.url; + return steroids.nativeBridge.nativeCall({ + method: "openURL", + parameters: { + url: url + }, + successCallbacks: [callbacks.onSuccess], + failureCallbacks: [callbacks.onFailure] + }); + }; + + return OpenURL; + +})(); +;var Notifications; + +Notifications = (function() { + function Notifications() {} + + Notifications.prototype.post = function(options, callbacks) { + var message; + if (options == null) { + options = {}; + } + if (callbacks == null) { + callbacks = {}; + } + message = options.constructor.name === "String" ? options : options.message; + return steroids.nativeBridge.nativeCall({ + method: "postNotification", + parameters: { + body: message + }, + successCallbacks: [callbacks.onSuccess], + failureCallbacks: [callbacks.onFailure] + }); + }; + + return Notifications; + +})(); +;var PostMessage; + +PostMessage = (function() { + function PostMessage() {} + + PostMessage.postMessage = function(message, targetOrigin) { + var escapedJSONMessage; + escapedJSONMessage = escape(JSON.stringify(message)); + return steroids.nativeBridge.nativeCall({ + method: "broadcastJavascript", + parameters: { + javascript: "steroids.PostMessage.dispatchMessageEvent('" + escapedJSONMessage + "', '*');" + }, + successCallbacks: [], + recurringCallbacks: [] + }); + }; + + PostMessage.dispatchMessageEvent = function(escapedJSONMessage, targetOrigin) { + var e, message; + message = JSON.parse(unescape(escapedJSONMessage)); + e = document.createEvent("MessageEvent"); + e.initMessageEvent("message", false, false, message, "", "", window, null); + return window.dispatchEvent(e); + }; + + return PostMessage; + +}).call(this); +;window.steroids = { + version: "3.1.2", + Animation: Animation, + XHR: XHR, + File: File, + views: { + WebView: WebView, + PreviewFileView: PreviewFileView + }, + buttons: { + NavigationBarButton: NavigationBarButton + }, + data: { + SQLiteDB: SQLiteDB, + TouchDB: TouchDB, + RSS: RSS, + OAuth2: OAuth2 + }, + openURL: OpenURL.open, + eventCallbacks: {}, + waitingForComponents: [], + debugMessages: [], + debugEnabled: false, + debug: function(msg) { + var blue, debugMessage, msgJSON, red, reset; + if (!steroids.debugEnabled) { + return; + } + msgJSON = JSON.stringify(msg); + red = '\u001b[31m'; + blue = '\u001b[34m'; + reset = '\u001b[0m'; + debugMessage = "[" + red + "DEBUG" + reset + "] - " + msgJSON + " - " + blue + " " + window.location.href + reset; + window.steroids.debugMessages.push(debugMessage); + return console.log(debugMessage); + }, + on: function(event, callback) { + var _base; + this.debug("on event " + event); + if (this["" + event + "_has_fired"] != null) { + this.debug("on event " + event + ", alrueady fierd"); + return callback(); + } else { + this.debug("on event " + event + ", waiting"); + (_base = this.eventCallbacks)[event] || (_base[event] = []); + return this.eventCallbacks[event].push(callback); + } + }, + fireSteroidsEvent: function(event) { + var callback, callbacks, _i, _len, _results; + this.debug("firign event " + event); + this["" + event + "_has_fired"] = new Date().getTime(); + if (this.eventCallbacks[event] != null) { + this.debug("firign event " + event + " callbacks"); + callbacks = this.eventCallbacks[event].splice(0); + _results = []; + for (_i = 0, _len = callbacks.length; _i < _len; _i++) { + callback = callbacks[_i]; + this.debug("firing event " + event + " callback"); + _results.push(callback()); + } + return _results; + } + }, + resetSteroidsEvent: function(event) { + this.debug("resettign event " + event); + return this["" + event + "_has_fired"] = void 0; + }, + markComponentReady: function(model) { + this.debug("" + model + " is ready"); + this.waitingForComponents.splice(this.waitingForComponents.indexOf(model), 1); + if (this.waitingForComponents.length === 0) { + this.debug("steroids is ready"); + return this.fireSteroidsEvent("ready"); + } + } +}; + +window.steroids.nativeBridge = Bridge.getBestNativeBridge(); + +window.steroids.waitingForComponents.push("App"); + +window.steroids.waitingForComponents.push("Events.focuslisteners"); + +window.steroids.waitingForComponents.push("Events.initialVisibility"); + +window.steroids.app = new App; + +Events.extend(); + +window.steroids.drawers = new DrawerCollection; + +window.steroids.layers = new LayerCollection; + +window.steroids.view = new steroids.views.WebView({ + location: window.location.href +}); + +window.steroids.modal = new Modal; + +window.steroids.audio = new Audio; + +window.steroids.navigationBar = new NavigationBar; + +window.steroids.statusBar = new StatusBar; + +window.steroids.tabBar = new TabBar; + +window.steroids.device = new Device; + +window.steroids.analytics = new Analytics; + +window.steroids.screen = new Screen; + +window.steroids.notifications = new Notifications; + +window.steroids.PostMessage = PostMessage; + +window.postMessage = PostMessage.postMessage; + +})(window); diff --git a/www/loading.html b/www/loading.html new file mode 100644 index 0000000..a044b85 --- /dev/null +++ b/www/loading.html @@ -0,0 +1,57 @@ + + + + + + Loading... + + + + + + + + +
+

Loading...

+ +
+ + diff --git a/www/loading.png b/www/loading.png new file mode 100644 index 0000000000000000000000000000000000000000..d79375f27c6aa52e468a928506fc9dfcda0af9a5 GIT binary patch literal 8807 zcmeHrcTiL9*6&6TkZu7~iXaF`RX}=2dVA?zI#FsU(mT>bK|pE<7L*n`(hNxN0wP8T z0YcA<5LyUD+TEOc?s@0j@1B3|%r|ppzO!fctl9Nh&#J%mOZr1!gO=(h6#xLVTAB}y z0N}#6^ON!dct_&Fw;@nmf@)g&0l;01z|8B71$MADR$s27Zef;7*mCMlLU->1YDCO#iLnhz~>|Jky?GJIM;p@1tV!0SdS z+9_$WG{p=bMA4M0uwR~w?d$HHUlLY|rs9SI43u@woPH-KRG9f0~pIWz;o5DI`Uu2vAZdiGt_w7z1y~0Q(^)$3@@| zA;6wDa%CKdf*<6Dk^t7PIT=abrU4vRT@oJxk7a@KQM2c2fW=f%Xvw>RN!32DoRK7 zYf2#>3UhN|cD@lUW`S!G4i_Bql!QBjb8m=7i_^~$z5>A8G)8c@gp;5Vy2_CeiIfI9 zJE31~inAIE1v>4ZB?o9N`B^uHY_3p)5(qA!st_fuYV;G9Y% zaeQvUl|sp!8+X9jp-FZnnVVxE@tWanowNs<_l=&LaF}Yc?a2FHkWR2s|C}b<4~WJb z$G2$Qe;r+GDF1_|UbVSI^5!%3_tf8<{qN_cGQEX;^Zj&F{)NOl+&9Ey`l(a})xLY} ze_p2$>-M-O+}ov6BPDn#!)d7Ib~z2A_hz+OIVm!U=rmdrNOmP!t^JY&S)dAs1G}=O zg|3DEq-F^RE4TRNsY{ZVNS_&Y^4`uU(fP#l`SM}+bw|oO;qic zVj6y2b1qtzN>%tGU8elEQN_{-sH*{m~wWnrI3Ct$RW@lw*+76S`u4g zS>oKWrh+>v`FuDqUf?qtbkn}E%&;uJOzx5+s%%=AXEamt&gAlgR4bK=cMV2Wh6yEC z#h>O$563cT>3pnspE-W>G4td7Cslv?f4)4E$*!OM&HVe&s>Yw$f0FJ7($K~;#`Yyb z_-??iQ(TAK2)tgEqg!-iJo!eS$vw&YYdN@F`dn{Q3;qWFFvhe&s!Z)no=g^g5tGug zqO#dCYEy#gkV$IkBjfN&byG3p#nMYZvJj?a@ITg!S&Sj2vLy*+kP>eb#SamdCrRX% zUAkQcsvivB*4Qn!^m0%;-KYx^yc&?yk&AGgG1_>hn5vjbPhN&tDO~3Mk>wroVPKnA@kUO; zmq$?ry57aJ!L7L8tl=UjCMTZ1i-{UE7UXp_+~gRVk?V3j4}84k*hKm;+lH#PT}rAS z9WouV=bxoDkI5CH)L*L8zj)GXv&g;Z+3VR`$V1M<$)lt9OK&63NUyo*Zjr36tZv`% z*WvfWKXV_zv)iR#9Wfo1y+o6HJ(3cha^ z6&B?rXGLc%?Y>I3H}*FU8FYCU*u`O0Be~9;&qB_|fa0h-BoNZ1Xys_@3r7bbVVrF# ziZU3Ny;?M0`Ni92Wk%)Hn2MO?jtb7l{p+tPIQMZmBWWW~=;Ho}`19vC3WpVk`FR{jd*zKg@bK3xnJ@kggKae!#C#ChR6RCHYzWvtqBX ztL0ae1>8c*Lx)vbn7>lO%i|077*9x8fGDOACoY@LwXB4ZL`iIb`}{OtNWn*4ep>Fa4N4}!US#6Aix zH$USoebu5%t2+aeDPYPA;P4ccmubBpo1XT{N2QEYFQWnS3$o%GFjVdmS9{vymE0)8 zo=Gv_UiYf}qNNa3gG$k#CRThC{1mki7jxIP;iN(7EJT68F#c=ZAm){1{^pxA{FTlt z^XUyA<8{o1*eq6B%iW}F<$QuMREvxk1>()f%jKG$H}HF+3=nwp?8=B%o)A6v=tmuc zF&*_J?rYShRLgPUYts{WTLTLbOKiQv?|3+i0%Owi%4-9WeQSF-86Xwg%jXt8FW@Weeej7at{9|jrQpxRv6CfC&B zQams+EURep!DQFuw~55Y_nCT!i36{(4VKWBJ@IuE#=2$yL}B0y#+1ZV59Nw-Inp|+ z+gGeiDqB6sI`Xuw(D(Gg_mO@lJ)z*DYnW*MfnxhEZ(@}CQ(#SluJ6{DQ}||}5Um8Q z>C61y1up2r;HB05OW1vOTA8VU7op|z6yvu7*dS~oZYp^@dFn9Zyd!Hz>(2&X6~=!4 znhiPDz}%wG7nidP)+U$?JegXJ8P9<1jJ|+p!owqk52x)h?;ApKP9s=1dhgB84F2=q z)y|S}vMsVBHakuJJGGeQtL9DSc~vrYp1=Hm$(?458}uRbk$IKPHtx+EA+7bHuKTMj z1(G8(yRE_7OlLn)1=8{}t%MNo{hoaymT4x!m-l332#F5l-Kc0WXtCQ>!YiXyXA)3~ z)~C~xo70hQ?SXFzW78V@x5*vUjpG+C0NPp8RTGyHSPd?d)a$G7uzo|Ix155xygE zI*@I%5KC{c6vh$BclP+OhG_h)_$cE>M#dQ#X%6AoNlXX>;!O@GO(Q)32)P3QQLzAU zcm~Q<0C;*20Djp6fJ_bmFng!l^{9g~UF)H;Nzl~#45tUn#A3V8=GmDRn{WFEQF>1y zsD-I7Q~+9%^yGq#mE%iPyJ;@Pd)gk3u^fuqj3^FN&cLVl*G+B`zC8~qU#HlpIxakr zKk|5k_ahuuKh;~vw{5G!wg&E_3N=zes0Q0rq$2@1qyV7fAA*wZZ&!Z_B`5%ZSLY&z z^#2kJtbe-+il{jN_-8>z@wc0xIA7qO#ebIjZ!zZIJ^BCi-G6c6U%or{>%a2dxnKX4 z@BXvgKl0)K+nDnV|0jchK8Gj!b~UqgHb6fJG&VIwH~QgJih9mSF}nb z5}ieFr1r@MKhsJVzxlGOt1G0n;A9|3u0WTkYaS{C_gaW@?mPdIm38{~n=Az`Wu4C@ z)l&wp&y%4iC&8boU2mnA&VBH__2hHw;V5hZ?<{(_yE^VH>O+HOwv!Lp?Kk8|1s7fQ z_iAIIBae+}vr7-en<1Y1`}>C~**+G(*&2QnAb!&mulyy1ST^>!`&6Y3dy9tr;%T>j z@witb^`RN4tQ>o)df|JOiWx7($kXG!p(o&XLEE=+*%NC-{o)MT?}0L<*iB|B8f zle_{ryy8sU6oD!%EHp#Z{}7Pa`$0nkm8V;^?tG9~otG3Wew|VqvHutU|?ka5z>FFlh-tO+F zcF7G7?#XXTncP~Z^UdR{ug?x9-0BGg!gqxqjyQU%^+mlvAxb*FCJA9-;T6Gni$ly_ zNUNTBpAmgMsPZYo(~GRNrA2W5TLHX*52XqQL}*%iwRAvfb>xm$hCpSups$bye+jXFnawzD1vc2dR><@Ri8hRTFE>%*=g# zeQFiCeA>n1H(sjWLEB{TIz#Mg>b%-ayf&q46DT`KSb{eTj9Jh;F^61wg=3oO&LhCL zRsY(?Qx$e-I(MBPkTJl`LIficg+k@~xLoZ>gE*`VV@pwPFVzcCZasrs?kTQymJQk3 z$Qfbi#f`z0sv)g$e<{{4;YSjqYZa4vy45cFrPT(tX(D@(M<=J_#Re3y9mn)xg<~Zc zyaa4`vI&Lb<>ig-c5woSkNOk&vu7c?eYs?&*D@ z;qYrI(wI?72W_&dtK_1ewPV=M7uYUCC_#QG|1X>vz9Wzw&)-ui0nT$CwTzsS#ySKOH5C?gu@ z1l9CA-tCWENIBd#+0jaw+iD)UEbwqk(7M75<5D#arD#!r))niUxsi4h0Bda5UfRC>NkgW)I(Jt_JM#*~jJQfI!hHoZt zSWXF^rd6=aWjb`)k2Dn!Ca_;7GgTy7ZSU-@!RA4nMJT^FOEFr!bi+FaVyf#~&J#d_ zHba=MQ0If)*w->Zb-lCAc*lj+<>%&pZ1I2$JSCPihIG%`BZO;|-&~BfM|=E}NuWRI z<7=*P_j}!+ANrMhNU>(&8;BfIQ5OWCsuA*^ER+upuIT#qOEIukS2+e=8Hk*yoSQOI zU6dh@Rff*?Ytx-S*!i2bp$$tgr~UWRF&a;g8Y}GVkTVKx%e%Wjide`fC{wguatU`c z4~QM0s)gL=&s!gD`pXOmy;NUZSm-oK^$+LAs`d*xjSuB_`Tl=fugxzM^1jMJ-yo%zVezXbj#t>Bswt%%m|tk zgEtDpXPuKPX+(|e9Xns~AZ?fV%K`&y{7vaxTIs|p*cG`8u$&Aq4AiDZnplvQ1D&I5 zH5#?==J-ZeCMV@R_8sF3YX@XMH%rM=((M^R0T6RcYNbpDRc}42>M*+WsG#MQ4?<3L z0!$=134hFQ`#w+;Nl#^{QfUu)wPWARTp&!BhZ@Nlw0NL0^0UwDxFLy6Mu75kAvnb% z_NomZq*;Y2yIVS+%x4Sc(q zWXRr>rsLLmysU3o_d496h#_U7EXbOjl3tx`x9gX01RLl*siN^!H!;?W8xb#FVv%f( zj@Ht>V0T>mkU4z*U5k@W&&40jeKrZPcVe6ZWE|WvcjCJow%%U@yV}^}^25^KD1^Dr z%Nvc6C$yf4t>dh9mVW;J*O0vZMWFU*f%M@U%|qUD?DPp;=oSlJ$hbId#3;8G=*B&I zlL|8=f&b=9b;24{)-Gl)%0`T}rs4yPp+(#|i@K&KGk7C2ab z6J>N(0$yaa+zbJ>?V7JsSZZrp@>rrsTN)uWKnA`Y)UrI>g~Q zDIkyo5sihXE>DJB#%#y^!Y$K`ni%xX=dl1}cyO?EvBchTh@Bq~H`SZ_GP1JCLJ>0Z z^7RE^ILzVl@cuI9=H~c-(9?u6(A;Z8VG$9hHDTQA;m)ZN zkCj?;*=bg51PU}J3S|nV9Ukt&jH6frAI(D`kT~<5e3padu%6EBd4xtPyEN6(Ywm%= z!^6(eg^U5`dgPOC{k-Y>IKMr-R0C`79T+PS{Wz zaF%rfU6YH8-PzvW?o?y3v@YM$^!=&sLSS(ugkiX~vgFgiGDl^@Ce5B|*Ai5tkl^6n?}bw+97Su{+>nI6-OsXBSv0Y+VYnlzNqSP zfuc)8@ZHz2uJdp_X)m#;*AYvh);e}}vX345f;!#qyX8IGa=4F;q^F}}R|v~FbJr*w z6KOmCjt?+LJVTG)sIqIDwSk5mA8a3Oww-MtH#ca`z~5M}%b%=OwMFbKX&J)LAGJlC z{KmbB6kZBE2B8_8QDSlXV8SkP_;6YAc&iJJ`;6Uei#+>MQWzc{&L-!cMf?dy#l+#t zCbsPsUBdZv0Zt;>AwA@FXOSnw2?NEGPg|VeG_f?00gEhqk|#Vp&;l2kKdsh@yTGkw zR5bxATpO2PQ@@KINt5-)qFYq*ih{jtYX4|(Cb~)v;x*Dw%3(7Cc3Tv?vJ@Z85H6!b z@XP)q&!=Dzex&3eIF&v9H7u`;HhYUXi`me9KE3|w^WnZPL0cm7d@?_X{Q19WnZM@G z{}3^Mu}%M;G*cJne<+o6!tw8n)IW>AD8|1+`rn$L`a3!H?-^?U;HUo1-u`9N|H);7 k^}@fTvHxqRZN#3@0jU(!YrDsNWB_<*sp&tgRI!iwUv`Cjng9R* literal 0 HcmV?d00001