├── .gitignore ├── .npmignore ├── src ├── index.js ├── module.js ├── ParseMock.js └── Parse.js ├── test ├── index.js ├── test.html └── Parse.spec.js ├── bower.json ├── webpack.config.js ├── package.json ├── karma.conf.js ├── LICENSE ├── README.md └── angular-parse.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | test 2 | .gitignore 3 | .npmignore 4 | karma.conf.js 5 | webpack.config.js 6 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | require('parse'); 2 | require('./Parse.js'); 3 | module.exports = require('./module.js').name; 4 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | require('angular'); 2 | require('angular-mocks'); 3 | require('parse'); 4 | require('../src/index.js'); 5 | require('../src/ParseMock.js'); 6 | 7 | var testsContext = require.context(__dirname, false, /\.spec\.js/); 8 | testsContext.keys().forEach(testsContext); 9 | -------------------------------------------------------------------------------- /src/module.js: -------------------------------------------------------------------------------- 1 | var angular = require('angular'); 2 | 3 | /** 4 | * @ngdoc overview 5 | * @name ngParse 6 | * 7 | * @description 8 | * Angular wrapper for [Parse.com JavaScript SDK]{@link https://parse.com/docs/js/api/}. 9 | */ 10 | module.exports = angular.module('ngParse', []); 11 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-parse-bower", 3 | "description": "Angular wrapper for Parse.com JavaScript SDK.", 4 | "main": "angular-parse.js", 5 | "authors": [ 6 | "" 7 | ], 8 | "license": "MIT", 9 | "keywords": [ 10 | "angular", 11 | "angularjs", 12 | "parse", 13 | "parsesdk" 14 | ], 15 | "homepage": "https://github.com/ivnivnch/angular-parse", 16 | "ignore": [ 17 | "**/.*", 18 | "node_modules", 19 | "bower_components", 20 | "test" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | 3 | module.exports = { 4 | context: __dirname, 5 | entry: './src/index.js', 6 | output: { 7 | filename: 'angular-parse.js', 8 | path: '.' 9 | }, 10 | externals: { 11 | angular: 'window.angular', 12 | parse: 'window.Parse' 13 | }, 14 | plugins: [ 15 | new webpack.optimize.DedupePlugin(), 16 | new webpack.optimize.OccurenceOrderPlugin(true), 17 | new webpack.NoErrorsPlugin(), 18 | new webpack.optimize.UglifyJsPlugin() 19 | ], 20 | target: 'web', 21 | devtool: '#inline-source-map', 22 | cache: true, 23 | watch: false 24 | }; 25 | -------------------------------------------------------------------------------- /test/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Angular Parse 6 | 7 | 8 | 9 | 15 | 16 | 17 |

Parse.com JavaScript SDK

18 | 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-parse", 3 | "version": "0.2.3", 4 | "description": "Angular wrapper for Parse.com JavaScript SDK.", 5 | "license": "MIT", 6 | "author": "", 7 | "main": "src/index.js", 8 | "keywords": [ 9 | "angular", 10 | "angularjs", 11 | "parse", 12 | "parsesdk" 13 | ], 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/ivnivnch/angular-parse.git" 17 | }, 18 | "homepage": "https://github.com/ivnivnch/angular-parse", 19 | "scripts": { 20 | "build": "webpack", 21 | "test": "karma start" 22 | }, 23 | "devDependencies": { 24 | "angular": "^1.4.6", 25 | "angular-mocks": "^1.4.6", 26 | "jasmine-core": "^2.3.4", 27 | "karma": "^0.13.10", 28 | "karma-chrome-launcher": "^0.2.0", 29 | "karma-jasmine": "^0.3.6", 30 | "karma-webpack": "^1.7.0", 31 | "parse": "^1.6.3", 32 | "webpack": "^1.12.2" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | 3 | module.exports = function (config) { 4 | config.set({ 5 | basePath: '', 6 | files: [ 7 | './test/index.js' 8 | ], 9 | preprocessors: { 10 | './test/index.js': ['webpack'] 11 | }, 12 | frameworks: ['jasmine'], 13 | plugins: [ 14 | require('karma-webpack'), 15 | require('karma-jasmine'), 16 | require('karma-chrome-launcher') 17 | ], 18 | port: 9876, 19 | reporters: ['progress'], 20 | colors: true, 21 | logLevel: config.LOG_INFO, 22 | autoWatch: false, 23 | singleRun: true, 24 | browsers: ['Chrome'], 25 | webpack: { 26 | context: __dirname, 27 | target: 'web', 28 | devtool: '#inline-source-map', 29 | cache: true, 30 | watch: false, 31 | plugins: [ 32 | new webpack.optimize.DedupePlugin(), 33 | new webpack.optimize.OccurenceOrderPlugin(true), 34 | new webpack.NoErrorsPlugin() 35 | ] 36 | }, 37 | webpackMiddleware: { 38 | noInfo: true 39 | } 40 | }); 41 | }; 42 | -------------------------------------------------------------------------------- /src/ParseMock.js: -------------------------------------------------------------------------------- 1 | var Parse = require('parse'); 2 | require('./Parse.js'); 3 | var ngParseModule = require('./module.js'); 4 | 5 | /** 6 | * @ngdoc object 7 | * @name ngParse.ParseMockProvider 8 | * 9 | * @description 10 | * Provider for ParseMock service. 11 | */ 12 | ParseMockProvider.$inject = []; 13 | function ParseMockProvider() { 14 | var provider = this; 15 | 16 | /** 17 | * @ngdoc service 18 | * @name ngParse.ParseMock 19 | * 20 | * @requires $q 21 | * 22 | * @description 23 | * Parse Mock. 24 | */ 25 | provider.$get = ParseMockFactory; 26 | ParseMockFactory.$inject = ['$q']; 27 | function ParseMockFactory($q) { 28 | function ParseMock(cb) { 29 | return function () { 30 | var args = Array.prototype.slice.call(arguments, 0); 31 | try { 32 | return $q.resolve(cb.apply(this, args)); 33 | } catch (err) { 34 | return $q.reject(err); 35 | } 36 | } 37 | } 38 | 39 | return ParseMock; 40 | } 41 | } 42 | 43 | ngParseModule 44 | .provider('ParseMock', ParseMockProvider); 45 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2015 ivnivnch@gmail.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /test/Parse.spec.js: -------------------------------------------------------------------------------- 1 | var Parse = require('parse'); 2 | 3 | describe('Parse', function () { 4 | beforeEach(angular.mock.module('ngParse')); 5 | 6 | describe('provider', function () { 7 | var ParseProvider; 8 | 9 | beforeEach(function () { 10 | angular.module('ngParse.test', ['ngParse']) 11 | .config(function (_ParseProvider_) { 12 | ParseProvider = _ParseProvider_; 13 | }); 14 | 15 | angular.mock.module('ngParse.test'); 16 | angular.mock.inject(function () { 17 | }); 18 | }); 19 | 20 | it('should equal', function () { 21 | expect(ParseProvider.ACL).toEqual(Parse.ACL); 22 | expect(ParseProvider.Cloud).toEqual(Parse.Cloud); 23 | expect(ParseProvider.Config).toEqual(Parse.Config); 24 | expect(ParseProvider.Error).toEqual(Parse.Error); 25 | expect(ParseProvider.FacebookUtils).toEqual(Parse.FacebookUtils); 26 | expect(ParseProvider.File).toEqual(Parse.File); 27 | expect(ParseProvider.GeoPoint).toEqual(Parse.GeoPoint); 28 | expect(ParseProvider.Object).toEqual(Parse.Object); 29 | expect(ParseProvider.Promise).toEqual(Parse.Promise); 30 | expect(ParseProvider.Push).toEqual(Parse.Push); 31 | expect(ParseProvider.Query).toEqual(Parse.Query); 32 | expect(ParseProvider.Role).toEqual(Parse.Role); 33 | expect(ParseProvider.Session).toEqual(Parse.Session); 34 | expect(ParseProvider.User).toEqual(Parse.User); 35 | }); 36 | 37 | describe('define attributes', function () { 38 | var Test; 39 | 40 | beforeEach(function () { 41 | Test = ParseProvider.Object.extend('Test'); 42 | }); 43 | 44 | it('should be defined', function () { 45 | expect(ParseProvider.defineAttributes).toBeDefined(); 46 | }); 47 | 48 | it('should define prototype attributes', function () { 49 | ParseProvider.defineAttributes(Test.prototype, ['a']); 50 | 51 | var object = new Test(); 52 | object.set('a', 123); 53 | expect(object.get('a')).toBe(123); 54 | expect(object.a).toBe(123); 55 | object.a = 456; 56 | expect(object.a).toBe(456); 57 | expect(object.get('a')).toBe(456); 58 | }); 59 | 60 | it('should define constructor attributes', function () { 61 | ParseProvider.defineAttributes(Test, ['b']); 62 | 63 | var object = new Test(); 64 | object.set('b', 123); 65 | expect(object.get('b')).toBe(123); 66 | expect(object.b).toBe(123); 67 | object.b = 456; 68 | expect(object.b).toBe(456); 69 | expect(object.get('b')).toBe(456); 70 | }); 71 | 72 | it('should define decorator attributes', function () { 73 | ParseProvider.defineAttributes(['c'])(Test); 74 | 75 | var object = new Test(); 76 | object.set('c', 123); 77 | expect(object.get('c')).toBe(123); 78 | expect(object.c).toBe(123); 79 | object.c = 456; 80 | expect(object.c).toBe(456); 81 | expect(object.get('c')).toBe(456); 82 | }); 83 | }); 84 | }); 85 | 86 | describe('factory', function () { 87 | it('should equal', function () { 88 | angular.mock.inject(function (_Parse_) { 89 | expect(_Parse_.ACL).toEqual(Parse.ACL); 90 | expect(_Parse_.Cloud).toEqual(Parse.Cloud); 91 | expect(_Parse_.Config).toEqual(Parse.Config); 92 | expect(_Parse_.Error).toEqual(Parse.Error); 93 | expect(_Parse_.FacebookUtils).toEqual(Parse.FacebookUtils); 94 | expect(_Parse_.File).toEqual(Parse.File); 95 | expect(_Parse_.GeoPoint).toEqual(Parse.GeoPoint); 96 | expect(_Parse_.Object).toEqual(Parse.Object); 97 | expect(_Parse_.Promise).toEqual(Parse.Promise); 98 | expect(_Parse_.Push).toEqual(Parse.Push); 99 | expect(_Parse_.Query).toEqual(Parse.Query); 100 | expect(_Parse_.Role).toEqual(Parse.Role); 101 | expect(_Parse_.Session).toEqual(Parse.Session); 102 | expect(_Parse_.User).toEqual(Parse.User); 103 | }); 104 | }); 105 | 106 | describe('define attributes', function () { 107 | angular.mock.inject(function (_Parse_) { 108 | expect(_Parse_.defineAttributes).toBeDefined(); 109 | }); 110 | }); 111 | 112 | describe('promise', function () { 113 | it('should be defined', function () { 114 | angular.mock.inject(function (_Parse_) { 115 | expect(_Parse_.wrapObject).toBeDefined(); 116 | }); 117 | }); 118 | }); 119 | }); 120 | }); 121 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Angular-Parse 2 | Angular wrapper for [Parse.com JavaScript SDK](https://parse.com/docs/js/api/). 3 | ## Features 4 | ### Getters and setters for attributes 5 | #### Define object attributes 6 | ```javascript 7 | var object = new Parse.Object('Test'); 8 | Parse.defineAttributes(object, ['a', 'b', 'c']); 9 | object.a = 123; 10 | console.assert(object.get('a') == 123); 11 | ``` 12 | #### Define subclass attributes 13 | ```javascript 14 | var MyClass = Parse.Object.extend("ClassName"); 15 | Parse.defineAttributes(MyClass, ['a', 'b', 'c']); 16 | var object = new MyClass(); 17 | object.a = 123; 18 | console.assert(object.get('a') == 123); 19 | ``` 20 | #### Use decorator 21 | ```javascript 22 | @Parse.defineAttributes(['a', 'b', 'c']) 23 | class MyClass extends Parse.Object { 24 | constructor() { 25 | super("ClassName"); 26 | } 27 | } 28 | var object = new MyClass(); 29 | object.a = 123; 30 | console.assert(object.get('a') == 123); 31 | ``` 32 | ### $q Promise 33 | ```javascript 34 | object.save() 35 | .then(function() { 36 | $scope.saved = true; 37 | }) 38 | .catch(function(err) { 39 | $scope.error = err; 40 | }); 41 | ``` 42 | ## Installation 43 | ### NPM 44 | `npm install angular-parse` 45 | ### Bower 46 | `bower install angular-parse-bower` 47 | ## Setup 48 | ### Browser 49 | ```html 50 | 51 | 52 | 53 | 56 | ``` 57 | ### CommonJS 58 | `npm install angular parse angular-parse` 59 | ```javascript 60 | var angular = require('angular'); 61 | var ngParse = require('angular-parse'); 62 | angular.module('demo', [ngParse]); 63 | ``` 64 | ## Usage 65 | ### Include `ngParse` module 66 | ```javascript 67 | angular.module('demo', ['ngParse']); 68 | ``` 69 | ### Initialize Parse 70 | ```javascript 71 | angular.module('demo') 72 | .config(['ParseProvider', function(ParseProvider) { 73 | ParseProvider.initialize(MY_PARSE_APP_ID, MY_PARSE_JS_KEY); 74 | }]); 75 | ``` 76 | ### Initialize Facebook 77 | ```html 78 | 79 | ``` 80 | ```javascript 81 | angular.module('demo') 82 | .config(['ParseProvider', function(ParseProvider) { 83 | ParseProvider.FacebookUtils.init({ 84 | appId: MY_FACEBOOK_APP_ID, 85 | version: 'v2.4',//Currently available versions https://developers.facebook.com/docs/apps/changelog 86 | xfbml: false 87 | }); 88 | }]); 89 | ``` 90 | ### Subclass 91 | ```javascript 92 | angular.module('demo') 93 | .factory('ParseComment', ['Parse', function(Parse) { 94 | var ParseComment = Parse.Object.extend('Comment', {/*...*/}, {/*...*/}); 95 | Parse.defineAttributes(ParseComment, ['user', 'text']); 96 | 97 | /* 98 | Or use decorator with Babel https://babeljs.io/ 99 | 100 | @Parse.defineAttributes('user', 'text') 101 | class ParseComment extends Parse.Object { 102 | constructor() { 103 | super("Comment"); 104 | } 105 | } 106 | Parse.Object.registerSubclass('Comment', ParseComment); 107 | */ 108 | 109 | return ParseComment; 110 | }]); 111 | ``` 112 | ### User attributes 113 | ```javascript 114 | angular.module('demo') 115 | .config(['ParseProvider', function(ParseProvider) { 116 | ParseProvider.defineAttributes(ParseProvider.User, ['first_name', 'last_name', 'picture', 'comments']); 117 | }]); 118 | ``` 119 | ### Authenticate 120 | ```javascript 121 | angular.module('demo') 122 | .run(['$rootScope', 'Parse', function($rootScope, Parse) { 123 | if (!Parse.User.authenticated()) { 124 | Parse.FacebookUtils.logIn('email', {}) 125 | .then(function(user) { 126 | $rootScope.user = user; 127 | }) 128 | .catch(function(err) {/*...*/}); 129 | } 130 | }]); 131 | ``` 132 | ### Class instance 133 | ```javascript 134 | angular.module('demo') 135 | .controller('CommentController', ['$scope', 'Parse', 'ParseComment', function($scope, Parse, ParseComment) { 136 | var user = Parse.User.current(); 137 | $scope.comment = new ParseComment(); 138 | $scope.comment.user = user; 139 | }]); 140 | ``` 141 | ```html 142 |
143 | 147 |

User: {{comment.user.username}}

148 |

Created At: {{comment.createdAt}}

149 | 150 |
151 | ``` 152 | ### Query 153 | ```javascript 154 | angular.module('demo') 155 | .controller('CommentsController', ['$scope', 'Parse', 'ParseComment', function($scope, Parse, ParseComment) { 156 | new Parse.Query(ParseComment) 157 | .include('user') 158 | .find() 159 | .then(function(comments) { 160 | $scope.comments = comments; 161 | }) 162 | .catch(function(err) { 163 | $scope.error = err; 164 | }); 165 | }]); 166 | ``` 167 | ```html 168 |
169 |
170 |

User: {{comment.user.username}}

171 | 172 |

{{comment.text}}

173 |

Created At: {{comment.createdAt}}

174 |
175 |
176 | ``` 177 | ## License 178 | [MIT](https://raw.githubusercontent.com/ivnivnch/angular-parse/master/LICENSE) 179 | -------------------------------------------------------------------------------- /src/Parse.js: -------------------------------------------------------------------------------- 1 | var Parse = require('parse'); 2 | var ngParseModule = require('./module.js'); 3 | 4 | /** 5 | * @ngdoc object 6 | * @name ngParse.ParseProvider 7 | * 8 | * @description 9 | * Provider for Parse service. 10 | */ 11 | ParseProvider.$inject = []; 12 | function ParseProvider() { 13 | /** 14 | * Defines getters and setters for the attributes 15 | * of the given object or function prototype. 16 | * Or create a decorator that defines getters 17 | * and setters for the subclass Parse.Object. 18 | * 19 | * @param {Object|Function|String|String[]} object 20 | * @param {...String|String[]=} attributes 21 | * @returns {*} 22 | */ 23 | function defineAttributes(object, attributes) { 24 | if (object instanceof Parse.Object) { 25 | if (!(attributes instanceof Array)) attributes = Array.prototype.slice.call(arguments, 1); 26 | attributes.forEach(function (attribute) { 27 | Object.defineProperty(object, attribute, { 28 | get: function () { 29 | return this.get(attribute); 30 | }, 31 | set: function (value) { 32 | this.set(attribute, value); 33 | }, 34 | configurable: true, 35 | enumerable: true 36 | }); 37 | }); 38 | } else if (typeof object == 'function') { 39 | return defineAttributes(object.prototype, attributes) 40 | } else { 41 | if (object instanceof Array) attributes = object; 42 | else attributes = Array.prototype.slice.call(arguments, 0); 43 | return function defineAttributesDecorator(target) { 44 | defineAttributes(target, attributes); 45 | } 46 | } 47 | } 48 | 49 | // Parse 50 | var AngularParse = Object.create(Parse); 51 | 52 | // ParseUser 53 | defineAttributes(AngularParse.User, ['email', 'password', 'username']); 54 | 55 | var provider = AngularParse; 56 | 57 | /** 58 | * @ngdoc method 59 | * @name ngParse.ParseProvider#defineAttributes 60 | * @methodOf ngParse.ParseProvider 61 | * @static 62 | * @see {@link defineAttributes} 63 | */ 64 | provider.defineAttributes = defineAttributes; 65 | 66 | /** 67 | * @ngdoc service 68 | * @name ngParse.Parse 69 | * 70 | * @requires $q 71 | * 72 | * @description 73 | * This is a wrapper for [Parse]{@link https://parse.com/docs/js/api/classes/Parse.html}. 74 | */ 75 | provider.$get = ParseFactory; 76 | ParseFactory.$inject = ['$q']; 77 | function ParseFactory($q) { 78 | /** 79 | * Wraps Promise. 80 | * 81 | * @param {Object} promise 82 | * @param {Object} parsePromise 83 | * @returns {Object} 84 | */ 85 | function wrapParsePromise(promise, parsePromise) { 86 | ['_rejected', '_rejectedCallbacks', '_resolved', '_resolvedCallbacks', '_result', 'reject', 'resolve'] 87 | .forEach(function (prop) { 88 | promise[prop] = parsePromise[prop]; 89 | }); 90 | 91 | ['_continueWith', '_thenRunCallbacks', 'always', 'done', 'fail'].forEach(function (method) { 92 | promise[method] = wrap(parsePromise[method]); 93 | }); 94 | 95 | ['then', 'catch'].forEach(function (method) { 96 | var func = promise[method]; 97 | promise[method] = function wrappedAngularPromise() { 98 | var args = Array.prototype.slice.call(arguments, 0); 99 | var promise = func.apply(this, args); 100 | wrapParsePromise(promise, parsePromise); 101 | return promise; 102 | }; 103 | }); 104 | 105 | return promise; 106 | } 107 | 108 | /** 109 | * Wraps function. 110 | * 111 | * @param {Function} func Function that returns 112 | * [Parse.Promise]{@link https://parse.com/docs/js/api/classes/Parse.Promise.html}. 113 | * @returns {Function} Function that returns $q promises. 114 | */ 115 | function wrap(func) { 116 | return function wrappedParsePromise() { 117 | var args = Array.prototype.slice.call(arguments, 0); 118 | var parsePromise = func.apply(this, args); 119 | var promise = $q(parsePromise.then.bind(parsePromise)); 120 | wrapParsePromise(promise, parsePromise); 121 | return promise; 122 | }; 123 | } 124 | 125 | /** 126 | * Wraps object. 127 | * 128 | * @param {Object} object 129 | * @param {...String|String[]=} methods 130 | */ 131 | function wrapObject(object, methods) { 132 | if (!(methods instanceof Array)) methods = Array.prototype.slice.call(arguments, 1); 133 | methods.forEach(function (method) { 134 | object[method] = wrap(object[method]); 135 | }); 136 | } 137 | 138 | /** 139 | * @ngdoc method 140 | * @name ngParse.Parse#wrapObject 141 | * @methodOf ngParse.Parse 142 | * @static 143 | * @see {@link wrapObject} 144 | */ 145 | AngularParse.wrapObject = wrapObject; 146 | 147 | // ParseCloud 148 | wrapObject(AngularParse.Cloud, ['run']); 149 | 150 | // ParseConfig 151 | wrapObject(AngularParse.Config, ['get']); 152 | 153 | //FacebookUtils 154 | wrapObject(AngularParse.FacebookUtils, ['link', 'logIn', 'unlink']); 155 | 156 | // ParseFile 157 | wrapObject(AngularParse.File.prototype, ['save']); 158 | 159 | // ParseObject 160 | wrapObject(AngularParse.Object, ['destroyAll', 'fetchAll', 'fetchAllIfNeeded', 'saveAll']); 161 | wrapObject(AngularParse.Object.prototype, ['destroy', 'fetch', 'save']); 162 | 163 | // ParsePromise 164 | wrapObject(AngularParse.Promise, ['_continueWhile', 'as', 'error', 'when']); 165 | 166 | // ParsePush 167 | wrapObject(AngularParse.Push, ['send']); 168 | 169 | // ParseQuery 170 | wrapObject(AngularParse.Query.prototype, ['count', 'each', 'find', 'first', 'get']); 171 | 172 | // ParseSession 173 | wrapObject(AngularParse.Session, ['current']); 174 | 175 | // ParseUser 176 | wrapObject(AngularParse.User, ['become', 'currentAsync', 'enableRevocableSession', 'logIn', 'logOut', 'requestPasswordReset', 'signUp']); 177 | wrapObject(AngularParse.User.prototype, ['logIn', 'signUp']); 178 | 179 | return AngularParse; 180 | } 181 | 182 | return provider; 183 | } 184 | 185 | ngParseModule 186 | .provider('Parse', ParseProvider); 187 | -------------------------------------------------------------------------------- /angular-parse.js: -------------------------------------------------------------------------------- 1 | !function(e){function t(n){if(r[n])return r[n].exports;var o=r[n]={exports:{},id:n,loaded:!1};return e[n].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var r={};return t.m=e,t.c=r,t.p="",t(0)}([function(e,t,r){r(2),r(3),e.exports=r(1).name},function(e,t,r){var n=r(4);e.exports=n.module("ngParse",[])},function(e,t){e.exports=window.Parse},function(e,t,r){function n(){function e(t,r){return t instanceof o.Object?(r instanceof Array||(r=Array.prototype.slice.call(arguments,1)),void r.forEach(function(e){Object.defineProperty(t,e,{get:function(){return this.get(e)},set:function(t){this.set(e,t)},configurable:!0,enumerable:!0})})):"function"==typeof t?e(t.prototype,r):(r=t instanceof Array?t:Array.prototype.slice.call(arguments,0),function(t){e(t,r)})}function t(e){function t(e,r){return["_rejected","_rejectedCallbacks","_resolved","_resolvedCallbacks","_result","reject","resolve"].forEach(function(t){e[t]=r[t]}),["_continueWith","_thenRunCallbacks","always","done","fail"].forEach(function(t){e[t]=n(r[t])}),["then","catch"].forEach(function(n){var o=e[n];e[n]=function(){var e=Array.prototype.slice.call(arguments,0),n=o.apply(this,e);return t(n,r),n}}),e}function n(r){return function(){var n=Array.prototype.slice.call(arguments,0),o=r.apply(this,n),c=e(o.then.bind(o));return t(c,o),c}}function o(e,t){t instanceof Array||(t=Array.prototype.slice.call(arguments,1)),t.forEach(function(t){e[t]=n(e[t])})}return r.wrapObject=o,o(r.Cloud,["run"]),o(r.Config,["get"]),o(r.FacebookUtils,["link","logIn","unlink"]),o(r.File.prototype,["save"]),o(r.Object,["destroyAll","fetchAll","fetchAllIfNeeded","saveAll"]),o(r.Object.prototype,["destroy","fetch","save"]),o(r.Promise,["_continueWhile","as","error","when"]),o(r.Push,["send"]),o(r.Query.prototype,["count","each","find","first","get"]),o(r.Session,["current"]),o(r.User,["become","currentAsync","enableRevocableSession","logIn","logOut","requestPasswordReset","signUp"]),o(r.User.prototype,["logIn","signUp"]),r}var r=Object.create(o);e(r.User,["email","password","username"]);var n=r;return n.defineAttributes=e,n.$get=t,t.$inject=["$q"],n}var o=r(2),c=r(1);n.$inject=[],c.provider("Parse",n)},function(e,t){e.exports=window.angular}]); 2 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vYW5ndWxhci1wYXJzZS5qcyIsIndlYnBhY2s6Ly8vd2VicGFjay9ib290c3RyYXAgOTI0MzgwYzZkODc1OWJkMWEyOGQiLCJ3ZWJwYWNrOi8vLy4vc3JjL2luZGV4LmpzIiwid2VicGFjazovLy8uL3NyYy9tb2R1bGUuanMiLCJ3ZWJwYWNrOi8vL2V4dGVybmFsIFwid2luZG93LlBhcnNlXCIiLCJ3ZWJwYWNrOi8vLy4vc3JjL1BhcnNlLmpzIiwid2VicGFjazovLy9leHRlcm5hbCBcIndpbmRvdy5hbmd1bGFyXCIiXSwibmFtZXMiOlsibW9kdWxlcyIsIl9fd2VicGFja19yZXF1aXJlX18iLCJtb2R1bGVJZCIsImluc3RhbGxlZE1vZHVsZXMiLCJleHBvcnRzIiwibW9kdWxlIiwiaWQiLCJsb2FkZWQiLCJjYWxsIiwibSIsImMiLCJwIiwibmFtZSIsImFuZ3VsYXIiLCJ3aW5kb3ciLCJQYXJzZSIsIlBhcnNlUHJvdmlkZXIiLCJkZWZpbmVBdHRyaWJ1dGVzIiwib2JqZWN0IiwiYXR0cmlidXRlcyIsIk9iamVjdCIsIkFycmF5IiwicHJvdG90eXBlIiwic2xpY2UiLCJhcmd1bWVudHMiLCJmb3JFYWNoIiwiYXR0cmlidXRlIiwiZGVmaW5lUHJvcGVydHkiLCJnZXQiLCJ0aGlzIiwic2V0IiwidmFsdWUiLCJjb25maWd1cmFibGUiLCJlbnVtZXJhYmxlIiwidGFyZ2V0IiwiUGFyc2VGYWN0b3J5IiwiJHEiLCJ3cmFwUGFyc2VQcm9taXNlIiwicHJvbWlzZSIsInBhcnNlUHJvbWlzZSIsInByb3AiLCJtZXRob2QiLCJ3cmFwIiwiZnVuYyIsImFyZ3MiLCJhcHBseSIsInRoZW4iLCJiaW5kIiwid3JhcE9iamVjdCIsIm1ldGhvZHMiLCJBbmd1bGFyUGFyc2UiLCJDbG91ZCIsIkNvbmZpZyIsIkZhY2Vib29rVXRpbHMiLCJGaWxlIiwiUHJvbWlzZSIsIlB1c2giLCJRdWVyeSIsIlNlc3Npb24iLCJVc2VyIiwiY3JlYXRlIiwicHJvdmlkZXIi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U0FHQVIsRUFBQUUsRUFBQU8sTUFBQW5DLFdBQUEsc0NBR0EwQixFQUFBRSxFQUFBUSxTQUFBLFlBR0FWLEVBQUFFLEVBQUFTLE1BQUEsb0dBQ0FYLEVBQUFFLEVBQUFTLEtBQUFyQyxXQUFBLG1CQUVBNEIsRUFqSUEsR0FBQUEsR0FBQTlCLE9BQUF3QyxPQUFBN0MsRUFHQUUsR0FBQWlDLEVBQUFTLE1BQUEsK0JBRUEsSUFBQUUsR0FBQVgsQ0ErSEEsT0F0SEFXLEdBQUE1QyxtQkFXQTRDLEVBQUFDLEtBQUEzQixFQUNBQSxFQUFBNEIsU0FBQSxNQTBHQUYsRUFyTEEsR0FBQTlDLEdBQUFkLEVBQUEsR0FDQStELEVBQUEvRCxFQUFBLEVBU0FlLEdBQUErQyxXQThLQUMsRUFDQUgsU0FBQSxRQUFBN0MsSUxrRk0sU0FBU1gsRUFBUUQsR00zUXZCQyxFQUFBRCxRQUFBVSxPQUFBRCIsImZpbGUiOiJhbmd1bGFyLXBhcnNlLmpzIiwic291cmNlc0NvbnRlbnQiOlsiLyoqKioqKi8gKGZ1bmN0aW9uKG1vZHVsZXMpIHsgLy8gd2VicGFja0Jvb3RzdHJhcFxuLyoqKioqKi8gXHQvLyBUaGUgbW9kdWxlIGNhY2hlXG4vKioqKioqLyBcdHZhciBpbnN0YWxsZWRNb2R1bGVzID0ge307XG4vKioqKioqL1xuLyoqKioqKi8gXHQvLyBUaGUgcmVxdWlyZSBmdW5jdGlvblxuLyoqKioqKi8gXHRmdW5jdGlvbiBfX3dlYnBhY2tfcmVxdWlyZV9fKG1vZHVsZUlkKSB7XG4vKioqKioqL1xuLyoqKioqKi8gXHRcdC8vIENoZWNrIGlmIG1vZHVsZSBpcyBpbiBjYWNoZVxuLyoqKioqKi8gXHRcdGlmKGluc3RhbGxlZE1vZHVsZXNbbW9kdWxlSWRdKVxuLyoqKioqKi8gXHRcdFx0cmV0dXJuIGluc3RhbGxlZE1vZHVsZXNbbW9kdWxlSWRdLmV4cG9ydHM7XG4vKioqKioqL1xuLyoqKioqKi8gXHRcdC8vIENyZWF0ZSBhIG5ldyBtb2R1bGUgKGFuZCBwdXQgaXQgaW50byB0aGUgY2FjaGUpXG4vKioqKioqLyBcdFx0dmFyIG1vZHVsZSA9IGluc3RhbGxlZE1vZHVsZXNbbW9kdWxlSWRdID0ge1xuLyoqKioqKi8gXHRcdFx0ZXhwb3J0czoge30sXG4vKioqKioqLyBcdFx0XHRpZDogbW9kdWxlSWQsXG4vKioqKioqLyBcdFx0XHRsb2FkZWQ6IGZhbHNlXG4vKioqKioqLyBcdFx0fTtcbi8qKioqKiovXG4vKioqKioqLyBcdFx0Ly8gRXhlY3V0ZSB0aGUgbW9kdWxlIGZ1bmN0aW9uXG4vKioqKioqLyBcdFx0bW9kdWxlc1ttb2R1bGVJZF0uY2FsbChtb2R1bGUuZXhwb3J0cywgbW9kdWxlLCBtb2R1bGUuZXhwb3J0cywgX193ZWJwYWNrX3JlcXVpcmVfXyk7XG4vKioqKioqL1xuLyoqKioqKi8gXHRcdC8vIEZsYWcgdGhlIG1vZHVsZSBhcyBsb2FkZWRcbi8qKioqKiovIFx0XHRtb2R1bGUubG9hZGVkID0gdHJ1ZTtcbi8qKioqKiovXG4vKioqKioqLyBcdFx0Ly8gUmV0dXJuIHRoZSBleHBvcnRzIG9mIHRoZSBtb2R1bGVcbi8qKioqKiovIFx0XHRyZXR1cm4gbW9kdWxlLmV4cG9ydHM7XG4vKioqKioqLyBcdH1cbi8qKioqKiovXG4vKioqKioqL1xuLyoqKioqKi8gXHQvLyBleHBvc2UgdGhlIG1vZHVsZXMgb2JqZWN0IChfX3dlYnBhY2tfbW9kdWxlc19fKVxuLyoqKioqKi8gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLm0gPSBtb2R1bGVzO1xuLyoqKioqKi9cbi8qKioqKiovIFx0Ly8gZXhwb3NlIHRoZSBtb2R1bGUgY2FjaGVcbi8qKioqKiovIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5jID0gaW5zdGFsbGVkTW9kdWxlcztcbi8qKioqKiovXG4vKioqKioqLyBcdC8vIF9fd2VicGFja19wdWJsaWNfcGF0aF9fXG4vKioqKioqLyBcdF9fd2VicGFja19yZXF1aXJlX18ucCA9IFwiXCI7XG4vKioqKioqL1xuLyoqKioqKi8gXHQvLyBMb2FkIGVudHJ5IG1vZHVsZSBhbmQgcmV0dXJuIGV4cG9ydHNcbi8qKioqKiovIFx0cmV0dXJuIF9fd2VicGFja19yZXF1aXJlX18oMCk7XG4vKioqKioqLyB9KVxuLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cbi8qKioqKiovIChbXG4vKiAwICovXG4vKioqLyBmdW5jdGlvbihtb2R1bGUsIGV4cG9ydHMsIF9fd2VicGFja19yZXF1aXJlX18pIHtcblxuXHRfX3dlYnBhY2tfcmVxdWlyZV9fKDIpO1xyXG5cdF9fd2VicGFja19yZXF1aXJlX18oMyk7XHJcblx0bW9kdWxlLmV4cG9ydHMgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDEpLm5hbWU7XHJcblxuXG4vKioqLyB9LFxuLyogMSAqL1xuLyoqKi8gZnVuY3Rpb24obW9kdWxlLCBleHBvcnRzLCBfX3dlYnBhY2tfcmVxdWlyZV9fKSB7XG5cblx0dmFyIGFuZ3VsYXIgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDQpO1xyXG5cdFxyXG5cdC8qKlxyXG5cdCAqIEBuZ2RvYyBvdmVydmlld1xyXG5cdCAqIEBuYW1lIG5nUGFyc2VcclxuXHQgKlxyXG5cdCAqIEBkZXNjcmlwdGlvblxyXG5cdCAqIEFuZ3VsYXIgd3JhcHBlciBmb3IgW1BhcnNlLmNvbSBKYXZhU2NyaXB0IFNES117QGxpbmsgaHR0cHM6Ly9wYXJzZS5jb20vZG9jcy9qcy9hcGkvfS5cclxuXHQgKi9cclxuXHRtb2R1bGUuZXhwb3J0cyA9IGFuZ3VsYXIubW9kdWxlKCduZ1BhcnNlJywgW10pO1xyXG5cblxuLyoqKi8gfSxcbi8qIDIgKi9cbi8qKiovIGZ1bmN0aW9uKG1vZHVsZSwgZXhwb3J0cykge1xuXG5cdG1vZHVsZS5leHBvcnRzID0gd2luZG93LlBhcnNlO1xuXG4vKioqLyB9LFxuLyogMyAqL1xuLyoqKi8gZnVuY3Rpb24obW9kdWxlLCBleHBvcnRzLCBfX3dlYnBhY2tfcmVxdWlyZV9fKSB7XG5cblx0dmFyIFBhcnNlID0gX193ZWJwYWNrX3JlcXVpcmVfXygyKTtcclxuXHR2YXIgbmdQYXJzZU1vZHVsZSA9IF9fd2VicGFja19yZXF1aXJlX18oMSk7XHJcblx0XHJcblx0LyoqXHJcblx0ICogQG5nZG9jIG9iamVjdFxyXG5cdCAqIEBuYW1lIG5nUGFyc2UuUGFyc2VQcm92aWRlclxyXG5cdCAqXHJcblx0ICogQGRlc2NyaXB0aW9uXHJcblx0ICogUHJvdmlkZXIgZm9yIFBhcnNlIHNlcnZpY2UuXHJcblx0ICovXHJcblx0UGFyc2VQcm92aWRlci4kaW5qZWN0ID0gW107XHJcblx0ZnVuY3Rpb24gUGFyc2VQcm92aWRlcigpIHtcclxuXHQgIC8qKlxyXG5cdCAgICogRGVmaW5lcyBnZXR0ZXJzIGFuZCBzZXR0ZXJzIGZvciB0aGUgYXR0cmlidXRlc1xyXG5cdCAgICogb2YgdGhlIGdpdmVuIG9iamVjdCBvciBmdW5jdGlvbiBwcm90b3R5cGUuXHJcblx0ICAgKiBPciBjcmVhdGUgYSBkZWNvcmF0b3IgdGhhdCBkZWZpbmVzIGdldHRlcnNcclxuXHQgICAqIGFuZCBzZXR0ZXJzIGZvciB0aGUgc3ViY2xhc3MgUGFyc2UuT2JqZWN0LlxyXG5cdCAgICpcclxuXHQgICAqIEBwYXJhbSB7T2JqZWN0fEZ1bmN0aW9ufFN0cmluZ3xTdHJpbmdbXX0gb2JqZWN0XHJcblx0ICAgKiBAcGFyYW0gey4uLlN0cmluZ3xTdHJpbmdbXT19IGF0dHJpYnV0ZXNcclxuXHQgICAqIEByZXR1cm5zIHsqfVxyXG5cdCAgICovXHJcblx0ICBmdW5jdGlvbiBkZWZpbmVBdHRyaWJ1dGVzKG9iamVjdCwgYXR0cmlidXRlcykge1xyXG5cdCAgICBpZiAob2JqZWN0IGluc3RhbmNlb2YgUGFyc2UuT2JqZWN0KSB7XHJcblx0ICAgICAgaWYgKCEoYXR0cmlidXRlcyBpbnN0YW5jZW9mIEFycmF5KSkgYXR0cmlidXRlcyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywgMSk7XHJcblx0ICAgICAgYXR0cmlidXRlcy5mb3JFYWNoKGZ1bmN0aW9uIChhdHRyaWJ1dGUpIHtcclxuXHQgICAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShvYmplY3QsIGF0dHJpYnV0ZSwge1xyXG5cdCAgICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcclxuXHQgICAgICAgICAgICByZXR1cm4gdGhpcy5nZXQoYXR0cmlidXRlKTtcclxuXHQgICAgICAgICAgfSxcclxuXHQgICAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcclxuXHQgICAgICAgICAgICB0aGlzLnNldChhdHRyaWJ1dGUsIHZhbHVlKTtcclxuXHQgICAgICAgICAgfSxcclxuXHQgICAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxyXG5cdCAgICAgICAgICBlbnVtZXJhYmxlOiB0cnVlXHJcblx0ICAgICAgICB9KTtcclxuXHQgICAgICB9KTtcclxuXHQgICAgfSBlbHNlIGlmICh0eXBlb2Ygb2JqZWN0ID09ICdmdW5jdGlvbicpIHtcclxuXHQgICAgICByZXR1cm4gZGVmaW5lQXR0cmlidXRlcyhvYmplY3QucHJvdG90eXBlLCBhdHRyaWJ1dGVzKVxyXG5cdCAgICB9IGVsc2Uge1xyXG5cdCAgICAgIGlmIChvYmplY3QgaW5zdGFuY2VvZiBBcnJheSkgYXR0cmlidXRlcyA9IG9iamVjdDtcclxuXHQgICAgICBlbHNlIGF0dHJpYnV0ZXMgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDApO1xyXG5cdCAgICAgIHJldHVybiBmdW5jdGlvbiBkZWZpbmVBdHRyaWJ1dGVzRGVjb3JhdG9yKHRhcmdldCkge1xyXG5cdCAgICAgICAgZGVmaW5lQXR0cmlidXRlcyh0YXJnZXQsIGF0dHJpYnV0ZXMpO1xyXG5cdCAgICAgIH1cclxuXHQgICAgfVxyXG5cdCAgfVxyXG5cdFxyXG5cdCAgLy8gUGFyc2VcclxuXHQgIHZhciBBbmd1bGFyUGFyc2UgPSBPYmplY3QuY3JlYXRlKFBhcnNlKTtcclxuXHRcclxuXHQgIC8vIFBhcnNlVXNlclxyXG5cdCAgZGVmaW5lQXR0cmlidXRlcyhBbmd1bGFyUGFyc2UuVXNlciwgWydlbWFpbCcsICdwYXNzd29yZCcsICd1c2VybmFtZSddKTtcclxuXHRcclxuXHQgIHZhciBwcm92aWRlciA9IEFuZ3VsYXJQYXJzZTtcclxuXHRcclxuXHQgIC8qKlxyXG5cdCAgICogQG5nZG9jIG1ldGhvZFxyXG5cdCAgICogQG5hbWUgbmdQYXJzZS5QYXJzZVByb3ZpZGVyI2RlZmluZUF0dHJpYnV0ZXNcclxuXHQgICAqIEBtZXRob2RPZiBuZ1BhcnNlLlBhcnNlUHJvdmlkZXJcclxuXHQgICAqIEBzdGF0aWNcclxuXHQgICAqIEBzZWUge0BsaW5rIGRlZmluZUF0dHJpYnV0ZXN9XHJcblx0ICAgKi9cclxuXHQgIHByb3ZpZGVyLmRlZmluZUF0dHJpYnV0ZXMgPSBkZWZpbmVBdHRyaWJ1dGVzO1xyXG5cdFxyXG5cdCAgLyoqXHJcblx0ICAgKiBAbmdkb2Mgc2VydmljZVxyXG5cdCAgICogQG5hbWUgbmdQYXJzZS5QYXJzZVxyXG5cdCAgICpcclxuXHQgICAqIEByZXF1aXJlcyAkcVxyXG5cdCAgICpcclxuXHQgICAqIEBkZXNjcmlwdGlvblxyXG5cdCAgICogVGhpcyBpcyBhIHdyYXBwZXIgZm9yIFtQYXJzZV17QGxpbmsgaHR0cHM6Ly9wYXJzZS5jb20vZG9jcy9qcy9hcGkvY2xhc3Nlcy9QYXJzZS5odG1sfS5cclxuXHQgICAqL1xyXG5cdCAgcHJvdmlkZXIuJGdldCA9IFBhcnNlRmFjdG9yeTtcclxuXHQgIFBhcnNlRmFjdG9yeS4kaW5qZWN0ID0gWyckcSddO1xyXG5cdCAgZnVuY3Rpb24gUGFyc2VGYWN0b3J5KCRxKSB7XHJcblx0ICAgIC8qKlxyXG5cdCAgICAgKiBXcmFwcyBQcm9taXNlLlxyXG5cdCAgICAgKlxyXG5cdCAgICAgKiBAcGFyYW0ge09iamVjdH0gcHJvbWlzZVxyXG5cdCAgICAgKiBAcGFyYW0ge09iamVjdH0gcGFyc2VQcm9taXNlXHJcblx0ICAgICAqIEByZXR1cm5zIHtPYmplY3R9XHJcblx0ICAgICAqL1xyXG5cdCAgICBmdW5jdGlvbiB3cmFwUGFyc2VQcm9taXNlKHByb21pc2UsIHBhcnNlUHJvbWlzZSkge1xyXG5cdCAgICAgIFsnX3JlamVjdGVkJywgJ19yZWplY3RlZENhbGxiYWNrcycsICdfcmVzb2x2ZWQnLCAnX3Jlc29sdmVkQ2FsbGJhY2tzJywgJ19yZXN1bHQnLCAncmVqZWN0JywgJ3Jlc29sdmUnXVxyXG5cdCAgICAgICAgLmZvckVhY2goZnVuY3Rpb24gKHByb3ApIHtcclxuXHQgICAgICAgICAgcHJvbWlzZVtwcm9wXSA9IHBhcnNlUHJvbWlzZVtwcm9wXTtcclxuXHQgICAgICAgIH0pO1xyXG5cdFxyXG5cdCAgICAgIFsnX2NvbnRpbnVlV2l0aCcsICdfdGhlblJ1bkNhbGxiYWNrcycsICdhbHdheXMnLCAnZG9uZScsICdmYWlsJ10uZm9yRWFjaChmdW5jdGlvbiAobWV0aG9kKSB7XHJcblx0ICAgICAgICBwcm9taXNlW21ldGhvZF0gPSB3cmFwKHBhcnNlUHJvbWlzZVttZXRob2RdKTtcclxuXHQgICAgICB9KTtcclxuXHRcclxuXHQgICAgICBbJ3RoZW4nLCAnY2F0Y2gnXS5mb3JFYWNoKGZ1bmN0aW9uIChtZXRob2QpIHtcclxuXHQgICAgICAgIHZhciBmdW5jID0gcHJvbWlzZVttZXRob2RdO1xyXG5cdCAgICAgICAgcHJvbWlzZVttZXRob2RdID0gZnVuY3Rpb24gd3JhcHBlZEFuZ3VsYXJQcm9taXNlKCkge1xyXG5cdCAgICAgICAgICB2YXIgYXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywgMCk7XHJcblx0ICAgICAgICAgIHZhciBwcm9taXNlID0gZnVuYy5hcHBseSh0aGlzLCBhcmdzKTtcclxuXHQgICAgICAgICAgd3JhcFBhcnNlUHJvbWlzZShwcm9taXNlLCBwYXJzZVByb21pc2UpO1xyXG5cdCAgICAgICAgICByZXR1cm4gcHJvbWlzZTtcclxuXHQgICAgICAgIH07XHJcblx0ICAgICAgfSk7XHJcblx0XHJcblx0ICAgICAgcmV0dXJuIHByb21pc2U7XHJcblx0ICAgIH1cclxuXHRcclxuXHQgICAgLyoqXHJcblx0ICAgICAqIFdyYXBzIGZ1bmN0aW9uLlxyXG5cdCAgICAgKlxyXG5cdCAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBmdW5jIEZ1bmN0aW9uIHRoYXQgcmV0dXJuc1xyXG5cdCAgICAgKiBbUGFyc2UuUHJvbWlzZV17QGxpbmsgaHR0cHM6Ly9wYXJzZS5jb20vZG9jcy9qcy9hcGkvY2xhc3Nlcy9QYXJzZS5Qcm9taXNlLmh0bWx9LlxyXG5cdCAgICAgKiBAcmV0dXJucyB7RnVuY3Rpb259IEZ1bmN0aW9uIHRoYXQgcmV0dXJucyAkcSBwcm9taXNlcy5cclxuXHQgICAgICovXHJcblx0ICAgIGZ1bmN0aW9uIHdyYXAoZnVuYykge1xyXG5cdCAgICAgIHJldHVybiBmdW5jdGlvbiB3cmFwcGVkUGFyc2VQcm9taXNlKCkge1xyXG5cdCAgICAgICAgdmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDApO1xyXG5cdCAgICAgICAgdmFyIHBhcnNlUHJvbWlzZSA9IGZ1bmMuYXBwbHkodGhpcywgYXJncyk7XHJcblx0ICAgICAgICB2YXIgcHJvbWlzZSA9ICRxKHBhcnNlUHJvbWlzZS50aGVuLmJpbmQocGFyc2VQcm9taXNlKSk7XHJcblx0ICAgICAgICB3cmFwUGFyc2VQcm9taXNlKHByb21pc2UsIHBhcnNlUHJvbWlzZSk7XHJcblx0ICAgICAgICByZXR1cm4gcHJvbWlzZTtcclxuXHQgICAgICB9O1xyXG5cdCAgICB9XHJcblx0XHJcblx0ICAgIC8qKlxyXG5cdCAgICAgKiBXcmFwcyBvYmplY3QuXHJcblx0ICAgICAqXHJcblx0ICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3RcclxuXHQgICAgICogQHBhcmFtIHsuLi5TdHJpbmd8U3RyaW5nW109fSBtZXRob2RzXHJcblx0ICAgICAqL1xyXG5cdCAgICBmdW5jdGlvbiB3cmFwT2JqZWN0KG9iamVjdCwgbWV0aG9kcykge1xyXG5cdCAgICAgIGlmICghKG1ldGhvZHMgaW5zdGFuY2VvZiBBcnJheSkpIG1ldGhvZHMgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpO1xyXG5cdCAgICAgIG1ldGhvZHMuZm9yRWFjaChmdW5jdGlvbiAobWV0aG9kKSB7XHJcblx0ICAgICAgICBvYmplY3RbbWV0aG9kXSA9IHdyYXAob2JqZWN0W21ldGhvZF0pO1xyXG5cdCAgICAgIH0pO1xyXG5cdCAgICB9XHJcblx0XHJcblx0ICAgIC8qKlxyXG5cdCAgICAgKiBAbmdkb2MgbWV0aG9kXHJcblx0ICAgICAqIEBuYW1lIG5nUGFyc2UuUGFyc2Ujd3JhcE9iamVjdFxyXG5cdCAgICAgKiBAbWV0aG9kT2YgbmdQYXJzZS5QYXJzZVxyXG5cdCAgICAgKiBAc3RhdGljXHJcblx0ICAgICAqIEBzZWUge0BsaW5rIHdyYXBPYmplY3R9XHJcblx0ICAgICAqL1xyXG5cdCAgICBBbmd1bGFyUGFyc2Uud3JhcE9iamVjdCA9IHdyYXBPYmplY3Q7XHJcblx0XHJcblx0ICAgIC8vIFBhcnNlQ2xvdWRcclxuXHQgICAgd3JhcE9iamVjdChBbmd1bGFyUGFyc2UuQ2xvdWQsIFsncnVuJ10pO1xyXG5cdFxyXG5cdCAgICAvLyBQYXJzZUNvbmZpZ1xyXG5cdCAgICB3cmFwT2JqZWN0KEFuZ3VsYXJQYXJzZS5Db25maWcsIFsnZ2V0J10pO1xyXG5cdFxyXG5cdCAgICAvL0ZhY2Vib29rVXRpbHNcclxuXHQgICAgd3JhcE9iamVjdChBbmd1bGFyUGFyc2UuRmFjZWJvb2tVdGlscywgWydsaW5rJywgJ2xvZ0luJywgJ3VubGluayddKTtcclxuXHRcclxuXHQgICAgLy8gUGFyc2VGaWxlXHJcblx0ICAgIHdyYXBPYmplY3QoQW5ndWxhclBhcnNlLkZpbGUucHJvdG90eXBlLCBbJ3NhdmUnXSk7XHJcblx0XHJcblx0ICAgIC8vIFBhcnNlT2JqZWN0XHJcblx0ICAgIHdyYXBPYmplY3QoQW5ndWxhclBhcnNlLk9iamVjdCwgWydkZXN0cm95QWxsJywgJ2ZldGNoQWxsJywgJ2ZldGNoQWxsSWZOZWVkZWQnLCAnc2F2ZUFsbCddKTtcclxuXHQgICAgd3JhcE9iamVjdChBbmd1bGFyUGFyc2UuT2JqZWN0LnByb3RvdHlwZSwgWydkZXN0cm95JywgJ2ZldGNoJywgJ3NhdmUnXSk7XHJcblx0XHJcblx0ICAgIC8vIFBhcnNlUHJvbWlzZVxyXG5cdCAgICB3cmFwT2JqZWN0KEFuZ3VsYXJQYXJzZS5Qcm9taXNlLCBbJ19jb250aW51ZVdoaWxlJywgJ2FzJywgJ2Vycm9yJywgJ3doZW4nXSk7XHJcblx0XHJcblx0ICAgIC8vIFBhcnNlUHVzaFxyXG5cdCAgICB3cmFwT2JqZWN0KEFuZ3VsYXJQYXJzZS5QdXNoLCBbJ3NlbmQnXSk7XHJcblx0XHJcblx0ICAgIC8vIFBhcnNlUXVlcnlcclxuXHQgICAgd3JhcE9iamVjdChBbmd1bGFyUGFyc2UuUXVlcnkucHJvdG90eXBlLCBbJ2NvdW50JywgJ2VhY2gnLCAnZmluZCcsICdmaXJzdCcsICdnZXQnXSk7XHJcblx0XHJcblx0ICAgIC8vIFBhcnNlU2Vzc2lvblxyXG5cdCAgICB3cmFwT2JqZWN0KEFuZ3VsYXJQYXJzZS5TZXNzaW9uLCBbJ2N1cnJlbnQnXSk7XHJcblx0XHJcblx0ICAgIC8vIFBhcnNlVXNlclxyXG5cdCAgICB3cmFwT2JqZWN0KEFuZ3VsYXJQYXJzZS5Vc2VyLCBbJ2JlY29tZScsICdjdXJyZW50QXN5bmMnLCAnZW5hYmxlUmV2b2NhYmxlU2Vzc2lvbicsICdsb2dJbicsICdsb2dPdXQnLCAncmVxdWVzdFBhc3N3b3JkUmVzZXQnLCAnc2lnblVwJ10pO1xyXG5cdCAgICB3cmFwT2JqZWN0KEFuZ3VsYXJQYXJzZS5Vc2VyLnByb3RvdHlwZSwgWydsb2dJbicsICdzaWduVXAnXSk7XHJcblx0XHJcblx0ICAgIHJldHVybiBBbmd1bGFyUGFyc2U7XHJcblx0ICB9XHJcblx0XHJcblx0ICByZXR1cm4gcHJvdmlkZXI7XHJcblx0fVxyXG5cdFxyXG5cdG5nUGFyc2VNb2R1bGVcclxuXHQgIC5wcm92aWRlcignUGFyc2UnLCBQYXJzZVByb3ZpZGVyKTtcclxuXG5cbi8qKiovIH0sXG4vKiA0ICovXG4vKioqLyBmdW5jdGlvbihtb2R1bGUsIGV4cG9ydHMpIHtcblxuXHRtb2R1bGUuZXhwb3J0cyA9IHdpbmRvdy5hbmd1bGFyO1xuXG4vKioqLyB9XG4vKioqKioqLyBdKTtcblxuXG4vKiogV0VCUEFDSyBGT09URVIgKipcbiAqKiBhbmd1bGFyLXBhcnNlLmpzXG4gKiovIiwiIFx0Ly8gVGhlIG1vZHVsZSBjYWNoZVxuIFx0dmFyIGluc3RhbGxlZE1vZHVsZXMgPSB7fTtcblxuIFx0Ly8gVGhlIHJlcXVpcmUgZnVuY3Rpb25cbiBcdGZ1bmN0aW9uIF9fd2VicGFja19yZXF1aXJlX18obW9kdWxlSWQpIHtcblxuIFx0XHQvLyBDaGVjayBpZiBtb2R1bGUgaXMgaW4gY2FjaGVcbiBcdFx0aWYoaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0pXG4gXHRcdFx0cmV0dXJuIGluc3RhbGxlZE1vZHVsZXNbbW9kdWxlSWRdLmV4cG9ydHM7XG5cbiBcdFx0Ly8gQ3JlYXRlIGEgbmV3IG1vZHVsZSAoYW5kIHB1dCBpdCBpbnRvIHRoZSBjYWNoZSlcbiBcdFx0dmFyIG1vZHVsZSA9IGluc3RhbGxlZE1vZHVsZXNbbW9kdWxlSWRdID0ge1xuIFx0XHRcdGV4cG9ydHM6IHt9LFxuIFx0XHRcdGlkOiBtb2R1bGVJZCxcbiBcdFx0XHRsb2FkZWQ6IGZhbHNlXG4gXHRcdH07XG5cbiBcdFx0Ly8gRXhlY3V0ZSB0aGUgbW9kdWxlIGZ1bmN0aW9uXG4gXHRcdG1vZHVsZXNbbW9kdWxlSWRdLmNhbGwobW9kdWxlLmV4cG9ydHMsIG1vZHVsZSwgbW9kdWxlLmV4cG9ydHMsIF9fd2VicGFja19yZXF1aXJlX18pO1xuXG4gXHRcdC8vIEZsYWcgdGhlIG1vZHVsZSBhcyBsb2FkZWRcbiBcdFx0bW9kdWxlLmxvYWRlZCA9IHRydWU7XG5cbiBcdFx0Ly8gUmV0dXJuIHRoZSBleHBvcnRzIG9mIHRoZSBtb2R1bGVcbiBcdFx0cmV0dXJuIG1vZHVsZS5leHBvcnRzO1xuIFx0fVxuXG5cbiBcdC8vIGV4cG9zZSB0aGUgbW9kdWxlcyBvYmplY3QgKF9fd2VicGFja19tb2R1bGVzX18pXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLm0gPSBtb2R1bGVzO1xuXG4gXHQvLyBleHBvc2UgdGhlIG1vZHVsZSBjYWNoZVxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5jID0gaW5zdGFsbGVkTW9kdWxlcztcblxuIFx0Ly8gX193ZWJwYWNrX3B1YmxpY19wYXRoX19cbiBcdF9fd2VicGFja19yZXF1aXJlX18ucCA9IFwiXCI7XG5cbiBcdC8vIExvYWQgZW50cnkgbW9kdWxlIGFuZCByZXR1cm4gZXhwb3J0c1xuIFx0cmV0dXJuIF9fd2VicGFja19yZXF1aXJlX18oMCk7XG5cblxuXG4vKiogV0VCUEFDSyBGT09URVIgKipcbiAqKiB3ZWJwYWNrL2Jvb3RzdHJhcCA5MjQzODBjNmQ4NzU5YmQxYTI4ZFxuICoqLyIsInJlcXVpcmUoJ3BhcnNlJyk7XHJcbnJlcXVpcmUoJy4vUGFyc2UuanMnKTtcclxubW9kdWxlLmV4cG9ydHMgPSByZXF1aXJlKCcuL21vZHVsZS5qcycpLm5hbWU7XHJcblxuXG5cbi8qKioqKioqKioqKioqKioqKlxuICoqIFdFQlBBQ0sgRk9PVEVSXG4gKiogLi9zcmMvaW5kZXguanNcbiAqKiBtb2R1bGUgaWQgPSAwXG4gKiogbW9kdWxlIGNodW5rcyA9IDBcbiAqKi8iLCJ2YXIgYW5ndWxhciA9IHJlcXVpcmUoJ2FuZ3VsYXInKTtcclxuXHJcbi8qKlxyXG4gKiBAbmdkb2Mgb3ZlcnZpZXdcclxuICogQG5hbWUgbmdQYXJzZVxyXG4gKlxyXG4gKiBAZGVzY3JpcHRpb25cclxuICogQW5ndWxhciB3cmFwcGVyIGZvciBbUGFyc2UuY29tIEphdmFTY3JpcHQgU0RLXXtAbGluayBodHRwczovL3BhcnNlLmNvbS9kb2NzL2pzL2FwaS99LlxyXG4gKi9cclxubW9kdWxlLmV4cG9ydHMgPSBhbmd1bGFyLm1vZHVsZSgnbmdQYXJzZScsIFtdKTtcclxuXG5cblxuLyoqKioqKioqKioqKioqKioqXG4gKiogV0VCUEFDSyBGT09URVJcbiAqKiAuL3NyYy9tb2R1bGUuanNcbiAqKiBtb2R1bGUgaWQgPSAxXG4gKiogbW9kdWxlIGNodW5rcyA9IDBcbiAqKi8iLCJtb2R1bGUuZXhwb3J0cyA9IHdpbmRvdy5QYXJzZTtcblxuXG4vKioqKioqKioqKioqKioqKipcbiAqKiBXRUJQQUNLIEZPT1RFUlxuICoqIGV4dGVybmFsIFwid2luZG93LlBhcnNlXCJcbiAqKiBtb2R1bGUgaWQgPSAyXG4gKiogbW9kdWxlIGNodW5rcyA9IDBcbiAqKi8iLCJ2YXIgUGFyc2UgPSByZXF1aXJlKCdwYXJzZScpO1xyXG52YXIgbmdQYXJzZU1vZHVsZSA9IHJlcXVpcmUoJy4vbW9kdWxlLmpzJyk7XHJcblxyXG4vKipcclxuICogQG5nZG9jIG9iamVjdFxyXG4gKiBAbmFtZSBuZ1BhcnNlLlBhcnNlUHJvdmlkZXJcclxuICpcclxuICogQGRlc2NyaXB0aW9uXHJcbiAqIFByb3ZpZGVyIGZvciBQYXJzZSBzZXJ2aWNlLlxyXG4gKi9cclxuUGFyc2VQcm92aWRlci4kaW5qZWN0ID0gW107XHJcbmZ1bmN0aW9uIFBhcnNlUHJvdmlkZXIoKSB7XHJcbiAgLyoqXHJcbiAgICogRGVmaW5lcyBnZXR0ZXJzIGFuZCBzZXR0ZXJzIGZvciB0aGUgYXR0cmlidXRlc1xyXG4gICAqIG9mIHRoZSBnaXZlbiBvYmplY3Qgb3IgZnVuY3Rpb24gcHJvdG90eXBlLlxyXG4gICAqIE9yIGNyZWF0ZSBhIGRlY29yYXRvciB0aGF0IGRlZmluZXMgZ2V0dGVyc1xyXG4gICAqIGFuZCBzZXR0ZXJzIGZvciB0aGUgc3ViY2xhc3MgUGFyc2UuT2JqZWN0LlxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtPYmplY3R8RnVuY3Rpb258U3RyaW5nfFN0cmluZ1tdfSBvYmplY3RcclxuICAgKiBAcGFyYW0gey4uLlN0cmluZ3xTdHJpbmdbXT19IGF0dHJpYnV0ZXNcclxuICAgKiBAcmV0dXJucyB7Kn1cclxuICAgKi9cclxuICBmdW5jdGlvbiBkZWZpbmVBdHRyaWJ1dGVzKG9iamVjdCwgYXR0cmlidXRlcykge1xyXG4gICAgaWYgKG9iamVjdCBpbnN0YW5jZW9mIFBhcnNlLk9iamVjdCkge1xyXG4gICAgICBpZiAoIShhdHRyaWJ1dGVzIGluc3RhbmNlb2YgQXJyYXkpKSBhdHRyaWJ1dGVzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcclxuICAgICAgYXR0cmlidXRlcy5mb3JFYWNoKGZ1bmN0aW9uIChhdHRyaWJ1dGUpIHtcclxuICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkob2JqZWN0LCBhdHRyaWJ1dGUsIHtcclxuICAgICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5nZXQoYXR0cmlidXRlKTtcclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWx1ZSkge1xyXG4gICAgICAgICAgICB0aGlzLnNldChhdHRyaWJ1dGUsIHZhbHVlKTtcclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgICBjb25maWd1cmFibGU6IHRydWUsXHJcbiAgICAgICAgICBlbnVtZXJhYmxlOiB0cnVlXHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH0pO1xyXG4gICAgfSBlbHNlIGlmICh0eXBlb2Ygb2JqZWN0ID09ICdmdW5jdGlvbicpIHtcclxuICAgICAgcmV0dXJuIGRlZmluZUF0dHJpYnV0ZXMob2JqZWN0LnByb3RvdHlwZSwgYXR0cmlidXRlcylcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGlmIChvYmplY3QgaW5zdGFuY2VvZiBBcnJheSkgYXR0cmlidXRlcyA9IG9iamVjdDtcclxuICAgICAgZWxzZSBhdHRyaWJ1dGVzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAwKTtcclxuICAgICAgcmV0dXJuIGZ1bmN0aW9uIGRlZmluZUF0dHJpYnV0ZXNEZWNvcmF0b3IodGFyZ2V0KSB7XHJcbiAgICAgICAgZGVmaW5lQXR0cmlidXRlcyh0YXJnZXQsIGF0dHJpYnV0ZXMpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBQYXJzZVxyXG4gIHZhciBBbmd1bGFyUGFyc2UgPSBPYmplY3QuY3JlYXRlKFBhcnNlKTtcclxuXHJcbiAgLy8gUGFyc2VVc2VyXHJcbiAgZGVmaW5lQXR0cmlidXRlcyhBbmd1bGFyUGFyc2UuVXNlciwgWydlbWFpbCcsICdwYXNzd29yZCcsICd1c2VybmFtZSddKTtcclxuXHJcbiAgdmFyIHByb3ZpZGVyID0gQW5ndWxhclBhcnNlO1xyXG5cclxuICAvKipcclxuICAgKiBAbmdkb2MgbWV0aG9kXHJcbiAgICogQG5hbWUgbmdQYXJzZS5QYXJzZVByb3ZpZGVyI2RlZmluZUF0dHJpYnV0ZXNcclxuICAgKiBAbWV0aG9kT2YgbmdQYXJzZS5QYXJzZVByb3ZpZGVyXHJcbiAgICogQHN0YXRpY1xyXG4gICAqIEBzZWUge0BsaW5rIGRlZmluZUF0dHJpYnV0ZXN9XHJcbiAgICovXHJcbiAgcHJvdmlkZXIuZGVmaW5lQXR0cmlidXRlcyA9IGRlZmluZUF0dHJpYnV0ZXM7XHJcblxyXG4gIC8qKlxyXG4gICAqIEBuZ2RvYyBzZXJ2aWNlXHJcbiAgICogQG5hbWUgbmdQYXJzZS5QYXJzZVxyXG4gICAqXHJcbiAgICogQHJlcXVpcmVzICRxXHJcbiAgICpcclxuICAgKiBAZGVzY3JpcHRpb25cclxuICAgKiBUaGlzIGlzIGEgd3JhcHBlciBmb3IgW1BhcnNlXXtAbGluayBodHRwczovL3BhcnNlLmNvbS9kb2NzL2pzL2FwaS9jbGFzc2VzL1BhcnNlLmh0bWx9LlxyXG4gICAqL1xyXG4gIHByb3ZpZGVyLiRnZXQgPSBQYXJzZUZhY3Rvcnk7XHJcbiAgUGFyc2VGYWN0b3J5LiRpbmplY3QgPSBbJyRxJ107XHJcbiAgZnVuY3Rpb24gUGFyc2VGYWN0b3J5KCRxKSB7XHJcbiAgICAvKipcclxuICAgICAqIFdyYXBzIFByb21pc2UuXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIHtPYmplY3R9IHByb21pc2VcclxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBwYXJzZVByb21pc2VcclxuICAgICAqIEByZXR1cm5zIHtPYmplY3R9XHJcbiAgICAgKi9cclxuICAgIGZ1bmN0aW9uIHdyYXBQYXJzZVByb21pc2UocHJvbWlzZSwgcGFyc2VQcm9taXNlKSB7XHJcbiAgICAgIFsnX3JlamVjdGVkJywgJ19yZWplY3RlZENhbGxiYWNrcycsICdfcmVzb2x2ZWQnLCAnX3Jlc29sdmVkQ2FsbGJhY2tzJywgJ19yZXN1bHQnLCAncmVqZWN0JywgJ3Jlc29sdmUnXVxyXG4gICAgICAgIC5mb3JFYWNoKGZ1bmN0aW9uIChwcm9wKSB7XHJcbiAgICAgICAgICBwcm9taXNlW3Byb3BdID0gcGFyc2VQcm9taXNlW3Byb3BdO1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgWydfY29udGludWVXaXRoJywgJ190aGVuUnVuQ2FsbGJhY2tzJywgJ2Fsd2F5cycsICdkb25lJywgJ2ZhaWwnXS5mb3JFYWNoKGZ1bmN0aW9uIChtZXRob2QpIHtcclxuICAgICAgICBwcm9taXNlW21ldGhvZF0gPSB3cmFwKHBhcnNlUHJvbWlzZVttZXRob2RdKTtcclxuICAgICAgfSk7XHJcblxyXG4gICAgICBbJ3RoZW4nLCAnY2F0Y2gnXS5mb3JFYWNoKGZ1bmN0aW9uIChtZXRob2QpIHtcclxuICAgICAgICB2YXIgZnVuYyA9IHByb21pc2VbbWV0aG9kXTtcclxuICAgICAgICBwcm9taXNlW21ldGhvZF0gPSBmdW5jdGlvbiB3cmFwcGVkQW5ndWxhclByb21pc2UoKSB7XHJcbiAgICAgICAgICB2YXIgYXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywgMCk7XHJcbiAgICAgICAgICB2YXIgcHJvbWlzZSA9IGZ1bmMuYXBwbHkodGhpcywgYXJncyk7XHJcbiAgICAgICAgICB3cmFwUGFyc2VQcm9taXNlKHByb21pc2UsIHBhcnNlUHJvbWlzZSk7XHJcbiAgICAgICAgICByZXR1cm4gcHJvbWlzZTtcclxuICAgICAgICB9O1xyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIHJldHVybiBwcm9taXNlO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogV3JhcHMgZnVuY3Rpb24uXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbn0gZnVuYyBGdW5jdGlvbiB0aGF0IHJldHVybnNcclxuICAgICAqIFtQYXJzZS5Qcm9taXNlXXtAbGluayBodHRwczovL3BhcnNlLmNvbS9kb2NzL2pzL2FwaS9jbGFzc2VzL1BhcnNlLlByb21pc2UuaHRtbH0uXHJcbiAgICAgKiBAcmV0dXJucyB7RnVuY3Rpb259IEZ1bmN0aW9uIHRoYXQgcmV0dXJucyAkcSBwcm9taXNlcy5cclxuICAgICAqL1xyXG4gICAgZnVuY3Rpb24gd3JhcChmdW5jKSB7XHJcbiAgICAgIHJldHVybiBmdW5jdGlvbiB3cmFwcGVkUGFyc2VQcm9taXNlKCkge1xyXG4gICAgICAgIHZhciBhcmdzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAwKTtcclxuICAgICAgICB2YXIgcGFyc2VQcm9taXNlID0gZnVuYy5hcHBseSh0aGlzLCBhcmdzKTtcclxuICAgICAgICB2YXIgcHJvbWlzZSA9ICRxKHBhcnNlUHJvbWlzZS50aGVuLmJpbmQocGFyc2VQcm9taXNlKSk7XHJcbiAgICAgICAgd3JhcFBhcnNlUHJvbWlzZShwcm9taXNlLCBwYXJzZVByb21pc2UpO1xyXG4gICAgICAgIHJldHVybiBwcm9taXNlO1xyXG4gICAgICB9O1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogV3JhcHMgb2JqZWN0LlxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3RcclxuICAgICAqIEBwYXJhbSB7Li4uU3RyaW5nfFN0cmluZ1tdPX0gbWV0aG9kc1xyXG4gICAgICovXHJcbiAgICBmdW5jdGlvbiB3cmFwT2JqZWN0KG9iamVjdCwgbWV0aG9kcykge1xyXG4gICAgICBpZiAoIShtZXRob2RzIGluc3RhbmNlb2YgQXJyYXkpKSBtZXRob2RzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcclxuICAgICAgbWV0aG9kcy5mb3JFYWNoKGZ1bmN0aW9uIChtZXRob2QpIHtcclxuICAgICAgICBvYmplY3RbbWV0aG9kXSA9IHdyYXAob2JqZWN0W21ldGhvZF0pO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIEBuZ2RvYyBtZXRob2RcclxuICAgICAqIEBuYW1lIG5nUGFyc2UuUGFyc2Ujd3JhcE9iamVjdFxyXG4gICAgICogQG1ldGhvZE9mIG5nUGFyc2UuUGFyc2VcclxuICAgICAqIEBzdGF0aWNcclxuICAgICAqIEBzZWUge0BsaW5rIHdyYXBPYmplY3R9XHJcbiAgICAgKi9cclxuICAgIEFuZ3VsYXJQYXJzZS53cmFwT2JqZWN0ID0gd3JhcE9iamVjdDtcclxuXHJcbiAgICAvLyBQYXJzZUNsb3VkXHJcbiAgICB3cmFwT2JqZWN0KEFuZ3VsYXJQYXJzZS5DbG91ZCwgWydydW4nXSk7XHJcblxyXG4gICAgLy8gUGFyc2VDb25maWdcclxuICAgIHdyYXBPYmplY3QoQW5ndWxhclBhcnNlLkNvbmZpZywgWydnZXQnXSk7XHJcblxyXG4gICAgLy9GYWNlYm9va1V0aWxzXHJcbiAgICB3cmFwT2JqZWN0KEFuZ3VsYXJQYXJzZS5GYWNlYm9va1V0aWxzLCBbJ2xpbmsnLCAnbG9nSW4nLCAndW5saW5rJ10pO1xyXG5cclxuICAgIC8vIFBhcnNlRmlsZVxyXG4gICAgd3JhcE9iamVjdChBbmd1bGFyUGFyc2UuRmlsZS5wcm90b3R5cGUsIFsnc2F2ZSddKTtcclxuXHJcbiAgICAvLyBQYXJzZU9iamVjdFxyXG4gICAgd3JhcE9iamVjdChBbmd1bGFyUGFyc2UuT2JqZWN0LCBbJ2Rlc3Ryb3lBbGwnLCAnZmV0Y2hBbGwnLCAnZmV0Y2hBbGxJZk5lZWRlZCcsICdzYXZlQWxsJ10pO1xyXG4gICAgd3JhcE9iamVjdChBbmd1bGFyUGFyc2UuT2JqZWN0LnByb3RvdHlwZSwgWydkZXN0cm95JywgJ2ZldGNoJywgJ3NhdmUnXSk7XHJcblxyXG4gICAgLy8gUGFyc2VQcm9taXNlXHJcbiAgICB3cmFwT2JqZWN0KEFuZ3VsYXJQYXJzZS5Qcm9taXNlLCBbJ19jb250aW51ZVdoaWxlJywgJ2FzJywgJ2Vycm9yJywgJ3doZW4nXSk7XHJcblxyXG4gICAgLy8gUGFyc2VQdXNoXHJcbiAgICB3cmFwT2JqZWN0KEFuZ3VsYXJQYXJzZS5QdXNoLCBbJ3NlbmQnXSk7XHJcblxyXG4gICAgLy8gUGFyc2VRdWVyeVxyXG4gICAgd3JhcE9iamVjdChBbmd1bGFyUGFyc2UuUXVlcnkucHJvdG90eXBlLCBbJ2NvdW50JywgJ2VhY2gnLCAnZmluZCcsICdmaXJzdCcsICdnZXQnXSk7XHJcblxyXG4gICAgLy8gUGFyc2VTZXNzaW9uXHJcbiAgICB3cmFwT2JqZWN0KEFuZ3VsYXJQYXJzZS5TZXNzaW9uLCBbJ2N1cnJlbnQnXSk7XHJcblxyXG4gICAgLy8gUGFyc2VVc2VyXHJcbiAgICB3cmFwT2JqZWN0KEFuZ3VsYXJQYXJzZS5Vc2VyLCBbJ2JlY29tZScsICdjdXJyZW50QXN5bmMnLCAnZW5hYmxlUmV2b2NhYmxlU2Vzc2lvbicsICdsb2dJbicsICdsb2dPdXQnLCAncmVxdWVzdFBhc3N3b3JkUmVzZXQnLCAnc2lnblVwJ10pO1xyXG4gICAgd3JhcE9iamVjdChBbmd1bGFyUGFyc2UuVXNlci5wcm90b3R5cGUsIFsnbG9nSW4nLCAnc2lnblVwJ10pO1xyXG5cclxuICAgIHJldHVybiBBbmd1bGFyUGFyc2U7XHJcbiAgfVxyXG5cclxuICByZXR1cm4gcHJvdmlkZXI7XHJcbn1cclxuXHJcbm5nUGFyc2VNb2R1bGVcclxuICAucHJvdmlkZXIoJ1BhcnNlJywgUGFyc2VQcm92aWRlcik7XHJcblxuXG5cbi8qKioqKioqKioqKioqKioqKlxuICoqIFdFQlBBQ0sgRk9PVEVSXG4gKiogLi9zcmMvUGFyc2UuanNcbiAqKiBtb2R1bGUgaWQgPSAzXG4gKiogbW9kdWxlIGNodW5rcyA9IDBcbiAqKi8iLCJtb2R1bGUuZXhwb3J0cyA9IHdpbmRvdy5hbmd1bGFyO1xuXG5cbi8qKioqKioqKioqKioqKioqKlxuICoqIFdFQlBBQ0sgRk9PVEVSXG4gKiogZXh0ZXJuYWwgXCJ3aW5kb3cuYW5ndWxhclwiXG4gKiogbW9kdWxlIGlkID0gNFxuICoqIG1vZHVsZSBjaHVua3MgPSAwXG4gKiovIl0sInNvdXJjZVJvb3QiOiIifQ== --------------------------------------------------------------------------------