diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..c13c5f6 --- /dev/null +++ b/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["es2015"] +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fd4f2b0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules +.DS_Store diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 0000000..51209b8 --- /dev/null +++ b/.jshintrc @@ -0,0 +1,36 @@ +{ + "bitwise": true, + "camelcase": true, + "curly": true, + "esnext": true, + "immed": true, + "newcap": true, + "noarg": true, + "node": true, + "strict": false, + "undef": true, + "unused": "vars", + "boss": true, + "browser": true, + "debug": false, + "devel": true, + "eqeqeq": true, + "eqnull": true, + "evil": true, + "expr": true, + "forin": false, + "laxbreak": false, + "noempty": false, + "nomen": false, + "nonew": false, + "onevar": false, + "plusplus": false, + "predef": [ + "describe", + "it", + "define" + ], + "regexp": false, + "sub": true, + "white": false +} diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..24a8ab9 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,3 @@ +language: node_js +node_js: + - "5" diff --git a/README.md b/README.md index 7cf31ac..c9daae2 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # xAPI Validator +![Test Passing Travis CI](https://travis-ci.org/elenatorro/xAPI-Validator-JS.svg?branch=master) A stand-alone Javascript validator for Experience API (xAPI) statements. @@ -22,7 +23,7 @@ The input `statement` may either be JSON string of an xAPI statement or a Javasc "actor": { "mbox": "mailto:bob@example.com" }, - "verb": { + "verb": { "id": "http://adlnet.gov/expapi/verbs/created", "display" :{"en-US": "created"} }, @@ -59,7 +60,7 @@ The produced report object contains three key properties: a collection of any `e "actor": { "mbox": "mailto:charles@example.com" }, - "verb": { + "verb": { "id": "http://adlnet.gov/expapi/verbs/created", "display" :{"en-US": "created"} }, @@ -92,4 +93,4 @@ Community feedback, criticism, and collaboration are most welcome. On the less-technical side, if an error message appears cryptic or unhelpful, please report it as an Issue and it should be addressed. ## License -MIT License (C) 2013 Zachary Pierce, Measured Progress \ No newline at end of file +MIT License (C) 2013 Zachary Pierce, Measured Progress diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..32ecea3 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,91 @@ +'use strict'; + +/* Libraries */ +let + browserify = require('browserify'), + buffer = require('vinyl-buffer'), + connect = require('gulp-connect'), + gulp = require('gulp'), + livereload = require('gulp-livereload'), + source = require('vinyl-source-stream'), + sourcemaps = require('gulp-sourcemaps'), + uglify = require('gulp-uglify') +; + +/* Config */ +const + BABEL_CONFIG = Object.freeze({ + presets: ['es2015'] + }), + BROWSERIFY_TRANSFORM = 'babelify', + BROWSERIFY_CONFIG = Object.freeze({ + debug: true, + json: true, + standalone: 'xapi-validator' + }), + DIST_FILENAME = 'xapiValidator.js', + DIST_FILENAME_MIN = 'xapiValidator.min.js', + DIST_TEST_FILENAME = 'xapiValidator.test.js', + DIST_PATH = 'lib', + DIST_MAIN_PATH = './', + DIST_TEST_PATH = 'spec', + MAPS_PATH = './maps', + SRC_FILE = 'src/xapiValidator.js', + SRC_TEST_FILE = 'test/xapiValidator.test.js', + WATCH_FILES = ['src/*.js', 'constants/*.js', 'spec/*.js', 'spec/lib/*.js'] +; + +/* Task Config */ + +const + BUILD_TASK = 'build', + BUILD_PROD_TASK = 'build-prod', + BUILD_TEST_TASK = 'build-test', + CONNECT_TASK = 'connect', + DEFAULT_TASK = 'default', + DEFAULT_TASKS = [BUILD_TASK, BUILD_TEST_TASK], + WATCH_TASK = 'watch', + WATCH_TASKS = [BUILD_TASK, BUILD_TEST_TASK, CONNECT_TASK] +; + +gulp.task(BUILD_TASK, () => { + return browserify(SRC_FILE, BROWSERIFY_CONFIG) + .transform(BROWSERIFY_TRANSFORM, BABEL_CONFIG) + .bundle() + .pipe(source(DIST_FILENAME)) + .pipe(gulp.dest(DIST_MAIN_PATH)) + .pipe(livereload()); +}); + +gulp.task(BUILD_TEST_TASK, () => { + return browserify(SRC_TEST_FILE, BROWSERIFY_CONFIG) + .transform(BROWSERIFY_TRANSFORM, BABEL_CONFIG) + .bundle() + .pipe(source(DIST_TEST_FILENAME)) + .pipe(gulp.dest(DIST_TEST_PATH)) + .pipe(livereload()); +}); + +gulp.task(BUILD_PROD_TASK, () => { + return browserify(SRC_FILE, BROWSERIFY_CONFIG) + .transform(BROWSERIFY_TRANSFORM, BABEL_CONFIG) + .bundle() + .pipe(source(DIST_FILENAME_MIN)) + .pipe(buffer()) + .pipe(sourcemaps.init()) + .pipe(uglify()) + .pipe(sourcemaps.write(MAPS_PATH)) + .pipe(gulp.dest(DIST_PATH)) + .pipe(livereload()); +}); + +gulp.task(WATCH_TASK, WATCH_TASKS, () => { + livereload.listen(); + gulp.watch(WATCH_FILES, WATCH_TASKS); +}); + +gulp.task(CONNECT_TASK, () => { + connect.server(); +}); + +gulp.task(DEFAULT_TASK, DEFAULT_TASKS); diff --git a/index.js b/index.js new file mode 100644 index 0000000..54ca5b9 --- /dev/null +++ b/index.js @@ -0,0 +1,2 @@ +var xapiValidator = require('./xapiValidator'); +module.exports = xapiValidator; diff --git a/package.json b/package.json index 0c3da03..b8b4cfb 100644 --- a/package.json +++ b/package.json @@ -4,14 +4,45 @@ "main": "./xapiValidator", "author": "Zachary Pierce", "description": "A validator for Experience API (xAPI) statements", - "keywords":["xAPI", "validator", "lrs", "json", "TinCan"], + "scripts": { + "lint": "eslint src/xAPI-validator.js", + "test": "mocha --compilers js:babel-core/register" + }, + "keywords": [ + "xAPI", + "validator", + "lrs", + "json", + "TinCan" + ], "license": "MIT", "engines": { "node": ">=0.6.6" }, - "devDependencies":{ - "chai": "*", - "mocha": "*", - "underscore": "*" + "devDependencies": { + "babel": "^6.5.2", + "babel-cli": "^6.18.0", + "babel-core": "^6.18.2", + "babel-eslint": "^7.1.0", + "babel-plugin-add-module-exports": "^0.2.1", + "babel-preset-es2015": "^6.18.0", + "babelify": "^7.3.0", + "browserify": "^13.1.1", + "chai": "^3.5.0", + "coveralls": "^2.11.14", + "eslint": "^3.9.1", + "gulp": "^3.9.1", + "gulp-babel": "^6.1.2", + "gulp-browserify": "^0.5.1", + "gulp-connect": "^5.0.0", + "gulp-livereload": "^3.8.1", + "gulp-rename": "^1.2.2", + "gulp-sourcemaps": "^2.2.0", + "gulp-uglify": "^2.0.0", + "mocha": "^3.1.2", + "sinon": "^1.17.6", + "underscore": "*", + "vinyl-buffer": "^1.0.0", + "vinyl-source-stream": "^1.1.0" } -} \ No newline at end of file +} diff --git a/spec/mocha_runner.html b/spec/mocha_runner.html index 66e16b4..4c40df2 100644 --- a/spec/mocha_runner.html +++ b/spec/mocha_runner.html @@ -1,6 +1,7 @@ - + + xAPI Validator @@ -9,14 +10,14 @@ - - + + - \ No newline at end of file + diff --git a/spec/xapiValidator.test.js b/spec/xapiValidator.test.js new file mode 100644 index 0000000..7976a39 --- /dev/null +++ b/spec/xapiValidator.test.js @@ -0,0 +1,11322 @@ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.xapiValidator = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o + * MIT Licensed + */ + +/*! + * Return a function that will copy properties from + * one object to another excluding any originally + * listed. Returned function will create a new `{}`. + * + * @param {String} excluded properties ... + * @return {Function} + */ + +function exclude () { + var excludes = [].slice.call(arguments); + + function excludeProps (res, obj) { + Object.keys(obj).forEach(function (key) { + if (!~excludes.indexOf(key)) res[key] = obj[key]; + }); + } + + return function extendExclude () { + var args = [].slice.call(arguments) + , i = 0 + , res = {}; + + for (; i < args.length; i++) { + excludeProps(res, args[i]); + } + + return res; + }; +}; + +/*! + * Primary Exports + */ + +module.exports = AssertionError; + +/** + * ### AssertionError + * + * An extension of the JavaScript `Error` constructor for + * assertion and validation scenarios. + * + * @param {String} message + * @param {Object} properties to include (optional) + * @param {callee} start stack function (optional) + */ + +function AssertionError (message, _props, ssf) { + var extend = exclude('name', 'message', 'stack', 'constructor', 'toJSON') + , props = extend(_props || {}); + + // default values + this.message = message || 'Unspecified AssertionError'; + this.showDiff = false; + + // copy from properties + for (var key in props) { + this[key] = props[key]; + } + + // capture stack trace + ssf = ssf || arguments.callee; + if (ssf && Error.captureStackTrace) { + Error.captureStackTrace(this, ssf); + } else { + try { + throw new Error(); + } catch(e) { + this.stack = e.stack; + } + } +} + +/*! + * Inherit from Error.prototype + */ + +AssertionError.prototype = Object.create(Error.prototype); + +/*! + * Statically set name + */ + +AssertionError.prototype.name = 'AssertionError'; + +/*! + * Ensure correct constructor + */ + +AssertionError.prototype.constructor = AssertionError; + +/** + * Allow errors to be converted to JSON for static transfer. + * + * @param {Boolean} include stack (default: `true`) + * @return {Object} object that can be `JSON.stringify` + */ + +AssertionError.prototype.toJSON = function (stack) { + var extend = exclude('constructor', 'toJSON', 'stack') + , props = extend({ name: this.name }, this); + + // include stack if exists and not turned off + if (false !== stack && this.stack) { + props.stack = this.stack; + } + + return props; +}; + +},{}],2:[function(require,module,exports){ +'use strict' + +exports.byteLength = byteLength +exports.toByteArray = toByteArray +exports.fromByteArray = fromByteArray + +var lookup = [] +var revLookup = [] +var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array + +var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' +for (var i = 0, len = code.length; i < len; ++i) { + lookup[i] = code[i] + revLookup[code.charCodeAt(i)] = i +} + +revLookup['-'.charCodeAt(0)] = 62 +revLookup['_'.charCodeAt(0)] = 63 + +function placeHoldersCount (b64) { + var len = b64.length + if (len % 4 > 0) { + throw new Error('Invalid string. Length must be a multiple of 4') + } + + // the number of equal signs (place holders) + // if there are two placeholders, than the two characters before it + // represent one byte + // if there is only one, then the three characters before it represent 2 bytes + // this is just a cheap hack to not do indexOf twice + return b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0 +} + +function byteLength (b64) { + // base64 is 4/3 + up to two characters of the original data + return b64.length * 3 / 4 - placeHoldersCount(b64) +} + +function toByteArray (b64) { + var i, j, l, tmp, placeHolders, arr + var len = b64.length + placeHolders = placeHoldersCount(b64) + + arr = new Arr(len * 3 / 4 - placeHolders) + + // if there are placeholders, only get up to the last complete 4 chars + l = placeHolders > 0 ? len - 4 : len + + var L = 0 + + for (i = 0, j = 0; i < l; i += 4, j += 3) { + tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)] + arr[L++] = (tmp >> 16) & 0xFF + arr[L++] = (tmp >> 8) & 0xFF + arr[L++] = tmp & 0xFF + } + + if (placeHolders === 2) { + tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4) + arr[L++] = tmp & 0xFF + } else if (placeHolders === 1) { + tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2) + arr[L++] = (tmp >> 8) & 0xFF + arr[L++] = tmp & 0xFF + } + + return arr +} + +function tripletToBase64 (num) { + return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F] +} + +function encodeChunk (uint8, start, end) { + var tmp + var output = [] + for (var i = start; i < end; i += 3) { + tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]) + output.push(tripletToBase64(tmp)) + } + return output.join('') +} + +function fromByteArray (uint8) { + var tmp + var len = uint8.length + var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes + var output = '' + var parts = [] + var maxChunkLength = 16383 // must be multiple of 3 + + // go through the array every three bytes, we'll deal with trailing stuff later + for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { + parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength))) + } + + // pad the end with zeros, but make sure to not forget the extra bytes + if (extraBytes === 1) { + tmp = uint8[len - 1] + output += lookup[tmp >> 2] + output += lookup[(tmp << 4) & 0x3F] + output += '==' + } else if (extraBytes === 2) { + tmp = (uint8[len - 2] << 8) + (uint8[len - 1]) + output += lookup[tmp >> 10] + output += lookup[(tmp >> 4) & 0x3F] + output += lookup[(tmp << 2) & 0x3F] + output += '=' + } + + parts.push(output) + + return parts.join('') +} + +},{}],3:[function(require,module,exports){ +(function (global){ +/*! + * The buffer module from node.js, for the browser. + * + * @author Feross Aboukhadijeh + * @license MIT + */ +/* eslint-disable no-proto */ + +'use strict' + +var base64 = require('base64-js') +var ieee754 = require('ieee754') +var isArray = require('isarray') + +exports.Buffer = Buffer +exports.SlowBuffer = SlowBuffer +exports.INSPECT_MAX_BYTES = 50 + +/** + * If `Buffer.TYPED_ARRAY_SUPPORT`: + * === true Use Uint8Array implementation (fastest) + * === false Use Object implementation (most compatible, even IE6) + * + * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+, + * Opera 11.6+, iOS 4.2+. + * + * Due to various browser bugs, sometimes the Object implementation will be used even + * when the browser supports typed arrays. + * + * Note: + * + * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances, + * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438. + * + * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function. + * + * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of + * incorrect length in some situations. + + * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they + * get the Object implementation, which is slower but behaves correctly. + */ +Buffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined + ? global.TYPED_ARRAY_SUPPORT + : typedArraySupport() + +/* + * Export kMaxLength after typed array support is determined. + */ +exports.kMaxLength = kMaxLength() + +function typedArraySupport () { + try { + var arr = new Uint8Array(1) + arr.__proto__ = {__proto__: Uint8Array.prototype, foo: function () { return 42 }} + return arr.foo() === 42 && // typed array instances can be augmented + typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray` + arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray` + } catch (e) { + return false + } +} + +function kMaxLength () { + return Buffer.TYPED_ARRAY_SUPPORT + ? 0x7fffffff + : 0x3fffffff +} + +function createBuffer (that, length) { + if (kMaxLength() < length) { + throw new RangeError('Invalid typed array length') + } + if (Buffer.TYPED_ARRAY_SUPPORT) { + // Return an augmented `Uint8Array` instance, for best performance + that = new Uint8Array(length) + that.__proto__ = Buffer.prototype + } else { + // Fallback: Return an object instance of the Buffer class + if (that === null) { + that = new Buffer(length) + } + that.length = length + } + + return that +} + +/** + * The Buffer constructor returns instances of `Uint8Array` that have their + * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of + * `Uint8Array`, so the returned instances will have all the node `Buffer` methods + * and the `Uint8Array` methods. Square bracket notation works as expected -- it + * returns a single octet. + * + * The `Uint8Array` prototype remains unmodified. + */ + +function Buffer (arg, encodingOrOffset, length) { + if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) { + return new Buffer(arg, encodingOrOffset, length) + } + + // Common case. + if (typeof arg === 'number') { + if (typeof encodingOrOffset === 'string') { + throw new Error( + 'If encoding is specified then the first argument must be a string' + ) + } + return allocUnsafe(this, arg) + } + return from(this, arg, encodingOrOffset, length) +} + +Buffer.poolSize = 8192 // not used by this implementation + +// TODO: Legacy, not needed anymore. Remove in next major version. +Buffer._augment = function (arr) { + arr.__proto__ = Buffer.prototype + return arr +} + +function from (that, value, encodingOrOffset, length) { + if (typeof value === 'number') { + throw new TypeError('"value" argument must not be a number') + } + + if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) { + return fromArrayBuffer(that, value, encodingOrOffset, length) + } + + if (typeof value === 'string') { + return fromString(that, value, encodingOrOffset) + } + + return fromObject(that, value) +} + +/** + * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError + * if value is a number. + * Buffer.from(str[, encoding]) + * Buffer.from(array) + * Buffer.from(buffer) + * Buffer.from(arrayBuffer[, byteOffset[, length]]) + **/ +Buffer.from = function (value, encodingOrOffset, length) { + return from(null, value, encodingOrOffset, length) +} + +if (Buffer.TYPED_ARRAY_SUPPORT) { + Buffer.prototype.__proto__ = Uint8Array.prototype + Buffer.__proto__ = Uint8Array + if (typeof Symbol !== 'undefined' && Symbol.species && + Buffer[Symbol.species] === Buffer) { + // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97 + Object.defineProperty(Buffer, Symbol.species, { + value: null, + configurable: true + }) + } +} + +function assertSize (size) { + if (typeof size !== 'number') { + throw new TypeError('"size" argument must be a number') + } else if (size < 0) { + throw new RangeError('"size" argument must not be negative') + } +} + +function alloc (that, size, fill, encoding) { + assertSize(size) + if (size <= 0) { + return createBuffer(that, size) + } + if (fill !== undefined) { + // Only pay attention to encoding if it's a string. This + // prevents accidentally sending in a number that would + // be interpretted as a start offset. + return typeof encoding === 'string' + ? createBuffer(that, size).fill(fill, encoding) + : createBuffer(that, size).fill(fill) + } + return createBuffer(that, size) +} + +/** + * Creates a new filled Buffer instance. + * alloc(size[, fill[, encoding]]) + **/ +Buffer.alloc = function (size, fill, encoding) { + return alloc(null, size, fill, encoding) +} + +function allocUnsafe (that, size) { + assertSize(size) + that = createBuffer(that, size < 0 ? 0 : checked(size) | 0) + if (!Buffer.TYPED_ARRAY_SUPPORT) { + for (var i = 0; i < size; ++i) { + that[i] = 0 + } + } + return that +} + +/** + * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance. + * */ +Buffer.allocUnsafe = function (size) { + return allocUnsafe(null, size) +} +/** + * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance. + */ +Buffer.allocUnsafeSlow = function (size) { + return allocUnsafe(null, size) +} + +function fromString (that, string, encoding) { + if (typeof encoding !== 'string' || encoding === '') { + encoding = 'utf8' + } + + if (!Buffer.isEncoding(encoding)) { + throw new TypeError('"encoding" must be a valid string encoding') + } + + var length = byteLength(string, encoding) | 0 + that = createBuffer(that, length) + + var actual = that.write(string, encoding) + + if (actual !== length) { + // Writing a hex string, for example, that contains invalid characters will + // cause everything after the first invalid character to be ignored. (e.g. + // 'abxxcd' will be treated as 'ab') + that = that.slice(0, actual) + } + + return that +} + +function fromArrayLike (that, array) { + var length = array.length < 0 ? 0 : checked(array.length) | 0 + that = createBuffer(that, length) + for (var i = 0; i < length; i += 1) { + that[i] = array[i] & 255 + } + return that +} + +function fromArrayBuffer (that, array, byteOffset, length) { + array.byteLength // this throws if `array` is not a valid ArrayBuffer + + if (byteOffset < 0 || array.byteLength < byteOffset) { + throw new RangeError('\'offset\' is out of bounds') + } + + if (array.byteLength < byteOffset + (length || 0)) { + throw new RangeError('\'length\' is out of bounds') + } + + if (byteOffset === undefined && length === undefined) { + array = new Uint8Array(array) + } else if (length === undefined) { + array = new Uint8Array(array, byteOffset) + } else { + array = new Uint8Array(array, byteOffset, length) + } + + if (Buffer.TYPED_ARRAY_SUPPORT) { + // Return an augmented `Uint8Array` instance, for best performance + that = array + that.__proto__ = Buffer.prototype + } else { + // Fallback: Return an object instance of the Buffer class + that = fromArrayLike(that, array) + } + return that +} + +function fromObject (that, obj) { + if (Buffer.isBuffer(obj)) { + var len = checked(obj.length) | 0 + that = createBuffer(that, len) + + if (that.length === 0) { + return that + } + + obj.copy(that, 0, 0, len) + return that + } + + if (obj) { + if ((typeof ArrayBuffer !== 'undefined' && + obj.buffer instanceof ArrayBuffer) || 'length' in obj) { + if (typeof obj.length !== 'number' || isnan(obj.length)) { + return createBuffer(that, 0) + } + return fromArrayLike(that, obj) + } + + if (obj.type === 'Buffer' && isArray(obj.data)) { + return fromArrayLike(that, obj.data) + } + } + + throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.') +} + +function checked (length) { + // Note: cannot use `length < kMaxLength()` here because that fails when + // length is NaN (which is otherwise coerced to zero.) + if (length >= kMaxLength()) { + throw new RangeError('Attempt to allocate Buffer larger than maximum ' + + 'size: 0x' + kMaxLength().toString(16) + ' bytes') + } + return length | 0 +} + +function SlowBuffer (length) { + if (+length != length) { // eslint-disable-line eqeqeq + length = 0 + } + return Buffer.alloc(+length) +} + +Buffer.isBuffer = function isBuffer (b) { + return !!(b != null && b._isBuffer) +} + +Buffer.compare = function compare (a, b) { + if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) { + throw new TypeError('Arguments must be Buffers') + } + + if (a === b) return 0 + + var x = a.length + var y = b.length + + for (var i = 0, len = Math.min(x, y); i < len; ++i) { + if (a[i] !== b[i]) { + x = a[i] + y = b[i] + break + } + } + + if (x < y) return -1 + if (y < x) return 1 + return 0 +} + +Buffer.isEncoding = function isEncoding (encoding) { + switch (String(encoding).toLowerCase()) { + case 'hex': + case 'utf8': + case 'utf-8': + case 'ascii': + case 'latin1': + case 'binary': + case 'base64': + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return true + default: + return false + } +} + +Buffer.concat = function concat (list, length) { + if (!isArray(list)) { + throw new TypeError('"list" argument must be an Array of Buffers') + } + + if (list.length === 0) { + return Buffer.alloc(0) + } + + var i + if (length === undefined) { + length = 0 + for (i = 0; i < list.length; ++i) { + length += list[i].length + } + } + + var buffer = Buffer.allocUnsafe(length) + var pos = 0 + for (i = 0; i < list.length; ++i) { + var buf = list[i] + if (!Buffer.isBuffer(buf)) { + throw new TypeError('"list" argument must be an Array of Buffers') + } + buf.copy(buffer, pos) + pos += buf.length + } + return buffer +} + +function byteLength (string, encoding) { + if (Buffer.isBuffer(string)) { + return string.length + } + if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' && + (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) { + return string.byteLength + } + if (typeof string !== 'string') { + string = '' + string + } + + var len = string.length + if (len === 0) return 0 + + // Use a for loop to avoid recursion + var loweredCase = false + for (;;) { + switch (encoding) { + case 'ascii': + case 'latin1': + case 'binary': + return len + case 'utf8': + case 'utf-8': + case undefined: + return utf8ToBytes(string).length + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return len * 2 + case 'hex': + return len >>> 1 + case 'base64': + return base64ToBytes(string).length + default: + if (loweredCase) return utf8ToBytes(string).length // assume utf8 + encoding = ('' + encoding).toLowerCase() + loweredCase = true + } + } +} +Buffer.byteLength = byteLength + +function slowToString (encoding, start, end) { + var loweredCase = false + + // No need to verify that "this.length <= MAX_UINT32" since it's a read-only + // property of a typed array. + + // This behaves neither like String nor Uint8Array in that we set start/end + // to their upper/lower bounds if the value passed is out of range. + // undefined is handled specially as per ECMA-262 6th Edition, + // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization. + if (start === undefined || start < 0) { + start = 0 + } + // Return early if start > this.length. Done here to prevent potential uint32 + // coercion fail below. + if (start > this.length) { + return '' + } + + if (end === undefined || end > this.length) { + end = this.length + } + + if (end <= 0) { + return '' + } + + // Force coersion to uint32. This will also coerce falsey/NaN values to 0. + end >>>= 0 + start >>>= 0 + + if (end <= start) { + return '' + } + + if (!encoding) encoding = 'utf8' + + while (true) { + switch (encoding) { + case 'hex': + return hexSlice(this, start, end) + + case 'utf8': + case 'utf-8': + return utf8Slice(this, start, end) + + case 'ascii': + return asciiSlice(this, start, end) + + case 'latin1': + case 'binary': + return latin1Slice(this, start, end) + + case 'base64': + return base64Slice(this, start, end) + + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return utf16leSlice(this, start, end) + + default: + if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) + encoding = (encoding + '').toLowerCase() + loweredCase = true + } + } +} + +// The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect +// Buffer instances. +Buffer.prototype._isBuffer = true + +function swap (b, n, m) { + var i = b[n] + b[n] = b[m] + b[m] = i +} + +Buffer.prototype.swap16 = function swap16 () { + var len = this.length + if (len % 2 !== 0) { + throw new RangeError('Buffer size must be a multiple of 16-bits') + } + for (var i = 0; i < len; i += 2) { + swap(this, i, i + 1) + } + return this +} + +Buffer.prototype.swap32 = function swap32 () { + var len = this.length + if (len % 4 !== 0) { + throw new RangeError('Buffer size must be a multiple of 32-bits') + } + for (var i = 0; i < len; i += 4) { + swap(this, i, i + 3) + swap(this, i + 1, i + 2) + } + return this +} + +Buffer.prototype.swap64 = function swap64 () { + var len = this.length + if (len % 8 !== 0) { + throw new RangeError('Buffer size must be a multiple of 64-bits') + } + for (var i = 0; i < len; i += 8) { + swap(this, i, i + 7) + swap(this, i + 1, i + 6) + swap(this, i + 2, i + 5) + swap(this, i + 3, i + 4) + } + return this +} + +Buffer.prototype.toString = function toString () { + var length = this.length | 0 + if (length === 0) return '' + if (arguments.length === 0) return utf8Slice(this, 0, length) + return slowToString.apply(this, arguments) +} + +Buffer.prototype.equals = function equals (b) { + if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer') + if (this === b) return true + return Buffer.compare(this, b) === 0 +} + +Buffer.prototype.inspect = function inspect () { + var str = '' + var max = exports.INSPECT_MAX_BYTES + if (this.length > 0) { + str = this.toString('hex', 0, max).match(/.{2}/g).join(' ') + if (this.length > max) str += ' ... ' + } + return '' +} + +Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) { + if (!Buffer.isBuffer(target)) { + throw new TypeError('Argument must be a Buffer') + } + + if (start === undefined) { + start = 0 + } + if (end === undefined) { + end = target ? target.length : 0 + } + if (thisStart === undefined) { + thisStart = 0 + } + if (thisEnd === undefined) { + thisEnd = this.length + } + + if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) { + throw new RangeError('out of range index') + } + + if (thisStart >= thisEnd && start >= end) { + return 0 + } + if (thisStart >= thisEnd) { + return -1 + } + if (start >= end) { + return 1 + } + + start >>>= 0 + end >>>= 0 + thisStart >>>= 0 + thisEnd >>>= 0 + + if (this === target) return 0 + + var x = thisEnd - thisStart + var y = end - start + var len = Math.min(x, y) + + var thisCopy = this.slice(thisStart, thisEnd) + var targetCopy = target.slice(start, end) + + for (var i = 0; i < len; ++i) { + if (thisCopy[i] !== targetCopy[i]) { + x = thisCopy[i] + y = targetCopy[i] + break + } + } + + if (x < y) return -1 + if (y < x) return 1 + return 0 +} + +// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`, +// OR the last index of `val` in `buffer` at offset <= `byteOffset`. +// +// Arguments: +// - buffer - a Buffer to search +// - val - a string, Buffer, or number +// - byteOffset - an index into `buffer`; will be clamped to an int32 +// - encoding - an optional encoding, relevant is val is a string +// - dir - true for indexOf, false for lastIndexOf +function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) { + // Empty buffer means no match + if (buffer.length === 0) return -1 + + // Normalize byteOffset + if (typeof byteOffset === 'string') { + encoding = byteOffset + byteOffset = 0 + } else if (byteOffset > 0x7fffffff) { + byteOffset = 0x7fffffff + } else if (byteOffset < -0x80000000) { + byteOffset = -0x80000000 + } + byteOffset = +byteOffset // Coerce to Number. + if (isNaN(byteOffset)) { + // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer + byteOffset = dir ? 0 : (buffer.length - 1) + } + + // Normalize byteOffset: negative offsets start from the end of the buffer + if (byteOffset < 0) byteOffset = buffer.length + byteOffset + if (byteOffset >= buffer.length) { + if (dir) return -1 + else byteOffset = buffer.length - 1 + } else if (byteOffset < 0) { + if (dir) byteOffset = 0 + else return -1 + } + + // Normalize val + if (typeof val === 'string') { + val = Buffer.from(val, encoding) + } + + // Finally, search either indexOf (if dir is true) or lastIndexOf + if (Buffer.isBuffer(val)) { + // Special case: looking for empty string/buffer always fails + if (val.length === 0) { + return -1 + } + return arrayIndexOf(buffer, val, byteOffset, encoding, dir) + } else if (typeof val === 'number') { + val = val & 0xFF // Search for a byte value [0-255] + if (Buffer.TYPED_ARRAY_SUPPORT && + typeof Uint8Array.prototype.indexOf === 'function') { + if (dir) { + return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset) + } else { + return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset) + } + } + return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir) + } + + throw new TypeError('val must be string, number or Buffer') +} + +function arrayIndexOf (arr, val, byteOffset, encoding, dir) { + var indexSize = 1 + var arrLength = arr.length + var valLength = val.length + + if (encoding !== undefined) { + encoding = String(encoding).toLowerCase() + if (encoding === 'ucs2' || encoding === 'ucs-2' || + encoding === 'utf16le' || encoding === 'utf-16le') { + if (arr.length < 2 || val.length < 2) { + return -1 + } + indexSize = 2 + arrLength /= 2 + valLength /= 2 + byteOffset /= 2 + } + } + + function read (buf, i) { + if (indexSize === 1) { + return buf[i] + } else { + return buf.readUInt16BE(i * indexSize) + } + } + + var i + if (dir) { + var foundIndex = -1 + for (i = byteOffset; i < arrLength; i++) { + if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) { + if (foundIndex === -1) foundIndex = i + if (i - foundIndex + 1 === valLength) return foundIndex * indexSize + } else { + if (foundIndex !== -1) i -= i - foundIndex + foundIndex = -1 + } + } + } else { + if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength + for (i = byteOffset; i >= 0; i--) { + var found = true + for (var j = 0; j < valLength; j++) { + if (read(arr, i + j) !== read(val, j)) { + found = false + break + } + } + if (found) return i + } + } + + return -1 +} + +Buffer.prototype.includes = function includes (val, byteOffset, encoding) { + return this.indexOf(val, byteOffset, encoding) !== -1 +} + +Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) { + return bidirectionalIndexOf(this, val, byteOffset, encoding, true) +} + +Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) { + return bidirectionalIndexOf(this, val, byteOffset, encoding, false) +} + +function hexWrite (buf, string, offset, length) { + offset = Number(offset) || 0 + var remaining = buf.length - offset + if (!length) { + length = remaining + } else { + length = Number(length) + if (length > remaining) { + length = remaining + } + } + + // must be an even number of digits + var strLen = string.length + if (strLen % 2 !== 0) throw new TypeError('Invalid hex string') + + if (length > strLen / 2) { + length = strLen / 2 + } + for (var i = 0; i < length; ++i) { + var parsed = parseInt(string.substr(i * 2, 2), 16) + if (isNaN(parsed)) return i + buf[offset + i] = parsed + } + return i +} + +function utf8Write (buf, string, offset, length) { + return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length) +} + +function asciiWrite (buf, string, offset, length) { + return blitBuffer(asciiToBytes(string), buf, offset, length) +} + +function latin1Write (buf, string, offset, length) { + return asciiWrite(buf, string, offset, length) +} + +function base64Write (buf, string, offset, length) { + return blitBuffer(base64ToBytes(string), buf, offset, length) +} + +function ucs2Write (buf, string, offset, length) { + return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length) +} + +Buffer.prototype.write = function write (string, offset, length, encoding) { + // Buffer#write(string) + if (offset === undefined) { + encoding = 'utf8' + length = this.length + offset = 0 + // Buffer#write(string, encoding) + } else if (length === undefined && typeof offset === 'string') { + encoding = offset + length = this.length + offset = 0 + // Buffer#write(string, offset[, length][, encoding]) + } else if (isFinite(offset)) { + offset = offset | 0 + if (isFinite(length)) { + length = length | 0 + if (encoding === undefined) encoding = 'utf8' + } else { + encoding = length + length = undefined + } + // legacy write(string, encoding, offset, length) - remove in v0.13 + } else { + throw new Error( + 'Buffer.write(string, encoding, offset[, length]) is no longer supported' + ) + } + + var remaining = this.length - offset + if (length === undefined || length > remaining) length = remaining + + if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) { + throw new RangeError('Attempt to write outside buffer bounds') + } + + if (!encoding) encoding = 'utf8' + + var loweredCase = false + for (;;) { + switch (encoding) { + case 'hex': + return hexWrite(this, string, offset, length) + + case 'utf8': + case 'utf-8': + return utf8Write(this, string, offset, length) + + case 'ascii': + return asciiWrite(this, string, offset, length) + + case 'latin1': + case 'binary': + return latin1Write(this, string, offset, length) + + case 'base64': + // Warning: maxLength not taken into account in base64Write + return base64Write(this, string, offset, length) + + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return ucs2Write(this, string, offset, length) + + default: + if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) + encoding = ('' + encoding).toLowerCase() + loweredCase = true + } + } +} + +Buffer.prototype.toJSON = function toJSON () { + return { + type: 'Buffer', + data: Array.prototype.slice.call(this._arr || this, 0) + } +} + +function base64Slice (buf, start, end) { + if (start === 0 && end === buf.length) { + return base64.fromByteArray(buf) + } else { + return base64.fromByteArray(buf.slice(start, end)) + } +} + +function utf8Slice (buf, start, end) { + end = Math.min(buf.length, end) + var res = [] + + var i = start + while (i < end) { + var firstByte = buf[i] + var codePoint = null + var bytesPerSequence = (firstByte > 0xEF) ? 4 + : (firstByte > 0xDF) ? 3 + : (firstByte > 0xBF) ? 2 + : 1 + + if (i + bytesPerSequence <= end) { + var secondByte, thirdByte, fourthByte, tempCodePoint + + switch (bytesPerSequence) { + case 1: + if (firstByte < 0x80) { + codePoint = firstByte + } + break + case 2: + secondByte = buf[i + 1] + if ((secondByte & 0xC0) === 0x80) { + tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F) + if (tempCodePoint > 0x7F) { + codePoint = tempCodePoint + } + } + break + case 3: + secondByte = buf[i + 1] + thirdByte = buf[i + 2] + if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) { + tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F) + if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) { + codePoint = tempCodePoint + } + } + break + case 4: + secondByte = buf[i + 1] + thirdByte = buf[i + 2] + fourthByte = buf[i + 3] + if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) { + tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F) + if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) { + codePoint = tempCodePoint + } + } + } + } + + if (codePoint === null) { + // we did not generate a valid codePoint so insert a + // replacement char (U+FFFD) and advance only 1 byte + codePoint = 0xFFFD + bytesPerSequence = 1 + } else if (codePoint > 0xFFFF) { + // encode to utf16 (surrogate pair dance) + codePoint -= 0x10000 + res.push(codePoint >>> 10 & 0x3FF | 0xD800) + codePoint = 0xDC00 | codePoint & 0x3FF + } + + res.push(codePoint) + i += bytesPerSequence + } + + return decodeCodePointsArray(res) +} + +// Based on http://stackoverflow.com/a/22747272/680742, the browser with +// the lowest limit is Chrome, with 0x10000 args. +// We go 1 magnitude less, for safety +var MAX_ARGUMENTS_LENGTH = 0x1000 + +function decodeCodePointsArray (codePoints) { + var len = codePoints.length + if (len <= MAX_ARGUMENTS_LENGTH) { + return String.fromCharCode.apply(String, codePoints) // avoid extra slice() + } + + // Decode in chunks to avoid "call stack size exceeded". + var res = '' + var i = 0 + while (i < len) { + res += String.fromCharCode.apply( + String, + codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH) + ) + } + return res +} + +function asciiSlice (buf, start, end) { + var ret = '' + end = Math.min(buf.length, end) + + for (var i = start; i < end; ++i) { + ret += String.fromCharCode(buf[i] & 0x7F) + } + return ret +} + +function latin1Slice (buf, start, end) { + var ret = '' + end = Math.min(buf.length, end) + + for (var i = start; i < end; ++i) { + ret += String.fromCharCode(buf[i]) + } + return ret +} + +function hexSlice (buf, start, end) { + var len = buf.length + + if (!start || start < 0) start = 0 + if (!end || end < 0 || end > len) end = len + + var out = '' + for (var i = start; i < end; ++i) { + out += toHex(buf[i]) + } + return out +} + +function utf16leSlice (buf, start, end) { + var bytes = buf.slice(start, end) + var res = '' + for (var i = 0; i < bytes.length; i += 2) { + res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256) + } + return res +} + +Buffer.prototype.slice = function slice (start, end) { + var len = this.length + start = ~~start + end = end === undefined ? len : ~~end + + if (start < 0) { + start += len + if (start < 0) start = 0 + } else if (start > len) { + start = len + } + + if (end < 0) { + end += len + if (end < 0) end = 0 + } else if (end > len) { + end = len + } + + if (end < start) end = start + + var newBuf + if (Buffer.TYPED_ARRAY_SUPPORT) { + newBuf = this.subarray(start, end) + newBuf.__proto__ = Buffer.prototype + } else { + var sliceLen = end - start + newBuf = new Buffer(sliceLen, undefined) + for (var i = 0; i < sliceLen; ++i) { + newBuf[i] = this[i + start] + } + } + + return newBuf +} + +/* + * Need to make sure that buffer isn't trying to write out of bounds. + */ +function checkOffset (offset, ext, length) { + if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint') + if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length') +} + +Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) { + offset = offset | 0 + byteLength = byteLength | 0 + if (!noAssert) checkOffset(offset, byteLength, this.length) + + var val = this[offset] + var mul = 1 + var i = 0 + while (++i < byteLength && (mul *= 0x100)) { + val += this[offset + i] * mul + } + + return val +} + +Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) { + offset = offset | 0 + byteLength = byteLength | 0 + if (!noAssert) { + checkOffset(offset, byteLength, this.length) + } + + var val = this[offset + --byteLength] + var mul = 1 + while (byteLength > 0 && (mul *= 0x100)) { + val += this[offset + --byteLength] * mul + } + + return val +} + +Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) { + if (!noAssert) checkOffset(offset, 1, this.length) + return this[offset] +} + +Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 2, this.length) + return this[offset] | (this[offset + 1] << 8) +} + +Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 2, this.length) + return (this[offset] << 8) | this[offset + 1] +} + +Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 4, this.length) + + return ((this[offset]) | + (this[offset + 1] << 8) | + (this[offset + 2] << 16)) + + (this[offset + 3] * 0x1000000) +} + +Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 4, this.length) + + return (this[offset] * 0x1000000) + + ((this[offset + 1] << 16) | + (this[offset + 2] << 8) | + this[offset + 3]) +} + +Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) { + offset = offset | 0 + byteLength = byteLength | 0 + if (!noAssert) checkOffset(offset, byteLength, this.length) + + var val = this[offset] + var mul = 1 + var i = 0 + while (++i < byteLength && (mul *= 0x100)) { + val += this[offset + i] * mul + } + mul *= 0x80 + + if (val >= mul) val -= Math.pow(2, 8 * byteLength) + + return val +} + +Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) { + offset = offset | 0 + byteLength = byteLength | 0 + if (!noAssert) checkOffset(offset, byteLength, this.length) + + var i = byteLength + var mul = 1 + var val = this[offset + --i] + while (i > 0 && (mul *= 0x100)) { + val += this[offset + --i] * mul + } + mul *= 0x80 + + if (val >= mul) val -= Math.pow(2, 8 * byteLength) + + return val +} + +Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) { + if (!noAssert) checkOffset(offset, 1, this.length) + if (!(this[offset] & 0x80)) return (this[offset]) + return ((0xff - this[offset] + 1) * -1) +} + +Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 2, this.length) + var val = this[offset] | (this[offset + 1] << 8) + return (val & 0x8000) ? val | 0xFFFF0000 : val +} + +Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 2, this.length) + var val = this[offset + 1] | (this[offset] << 8) + return (val & 0x8000) ? val | 0xFFFF0000 : val +} + +Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 4, this.length) + + return (this[offset]) | + (this[offset + 1] << 8) | + (this[offset + 2] << 16) | + (this[offset + 3] << 24) +} + +Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 4, this.length) + + return (this[offset] << 24) | + (this[offset + 1] << 16) | + (this[offset + 2] << 8) | + (this[offset + 3]) +} + +Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 4, this.length) + return ieee754.read(this, offset, true, 23, 4) +} + +Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 4, this.length) + return ieee754.read(this, offset, false, 23, 4) +} + +Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 8, this.length) + return ieee754.read(this, offset, true, 52, 8) +} + +Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 8, this.length) + return ieee754.read(this, offset, false, 52, 8) +} + +function checkInt (buf, value, offset, ext, max, min) { + if (!Buffer.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance') + if (value > max || value < min) throw new RangeError('"value" argument is out of bounds') + if (offset + ext > buf.length) throw new RangeError('Index out of range') +} + +Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) { + value = +value + offset = offset | 0 + byteLength = byteLength | 0 + if (!noAssert) { + var maxBytes = Math.pow(2, 8 * byteLength) - 1 + checkInt(this, value, offset, byteLength, maxBytes, 0) + } + + var mul = 1 + var i = 0 + this[offset] = value & 0xFF + while (++i < byteLength && (mul *= 0x100)) { + this[offset + i] = (value / mul) & 0xFF + } + + return offset + byteLength +} + +Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) { + value = +value + offset = offset | 0 + byteLength = byteLength | 0 + if (!noAssert) { + var maxBytes = Math.pow(2, 8 * byteLength) - 1 + checkInt(this, value, offset, byteLength, maxBytes, 0) + } + + var i = byteLength - 1 + var mul = 1 + this[offset + i] = value & 0xFF + while (--i >= 0 && (mul *= 0x100)) { + this[offset + i] = (value / mul) & 0xFF + } + + return offset + byteLength +} + +Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) { + value = +value + offset = offset | 0 + if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0) + if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) + this[offset] = (value & 0xff) + return offset + 1 +} + +function objectWriteUInt16 (buf, value, offset, littleEndian) { + if (value < 0) value = 0xffff + value + 1 + for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) { + buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>> + (littleEndian ? i : 1 - i) * 8 + } +} + +Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) { + value = +value + offset = offset | 0 + if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = (value & 0xff) + this[offset + 1] = (value >>> 8) + } else { + objectWriteUInt16(this, value, offset, true) + } + return offset + 2 +} + +Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) { + value = +value + offset = offset | 0 + if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = (value >>> 8) + this[offset + 1] = (value & 0xff) + } else { + objectWriteUInt16(this, value, offset, false) + } + return offset + 2 +} + +function objectWriteUInt32 (buf, value, offset, littleEndian) { + if (value < 0) value = 0xffffffff + value + 1 + for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) { + buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff + } +} + +Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) { + value = +value + offset = offset | 0 + if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset + 3] = (value >>> 24) + this[offset + 2] = (value >>> 16) + this[offset + 1] = (value >>> 8) + this[offset] = (value & 0xff) + } else { + objectWriteUInt32(this, value, offset, true) + } + return offset + 4 +} + +Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) { + value = +value + offset = offset | 0 + if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = (value >>> 24) + this[offset + 1] = (value >>> 16) + this[offset + 2] = (value >>> 8) + this[offset + 3] = (value & 0xff) + } else { + objectWriteUInt32(this, value, offset, false) + } + return offset + 4 +} + +Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) { + value = +value + offset = offset | 0 + if (!noAssert) { + var limit = Math.pow(2, 8 * byteLength - 1) + + checkInt(this, value, offset, byteLength, limit - 1, -limit) + } + + var i = 0 + var mul = 1 + var sub = 0 + this[offset] = value & 0xFF + while (++i < byteLength && (mul *= 0x100)) { + if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) { + sub = 1 + } + this[offset + i] = ((value / mul) >> 0) - sub & 0xFF + } + + return offset + byteLength +} + +Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) { + value = +value + offset = offset | 0 + if (!noAssert) { + var limit = Math.pow(2, 8 * byteLength - 1) + + checkInt(this, value, offset, byteLength, limit - 1, -limit) + } + + var i = byteLength - 1 + var mul = 1 + var sub = 0 + this[offset + i] = value & 0xFF + while (--i >= 0 && (mul *= 0x100)) { + if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) { + sub = 1 + } + this[offset + i] = ((value / mul) >> 0) - sub & 0xFF + } + + return offset + byteLength +} + +Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) { + value = +value + offset = offset | 0 + if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80) + if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) + if (value < 0) value = 0xff + value + 1 + this[offset] = (value & 0xff) + return offset + 1 +} + +Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) { + value = +value + offset = offset | 0 + if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = (value & 0xff) + this[offset + 1] = (value >>> 8) + } else { + objectWriteUInt16(this, value, offset, true) + } + return offset + 2 +} + +Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) { + value = +value + offset = offset | 0 + if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = (value >>> 8) + this[offset + 1] = (value & 0xff) + } else { + objectWriteUInt16(this, value, offset, false) + } + return offset + 2 +} + +Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) { + value = +value + offset = offset | 0 + if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = (value & 0xff) + this[offset + 1] = (value >>> 8) + this[offset + 2] = (value >>> 16) + this[offset + 3] = (value >>> 24) + } else { + objectWriteUInt32(this, value, offset, true) + } + return offset + 4 +} + +Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) { + value = +value + offset = offset | 0 + if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) + if (value < 0) value = 0xffffffff + value + 1 + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = (value >>> 24) + this[offset + 1] = (value >>> 16) + this[offset + 2] = (value >>> 8) + this[offset + 3] = (value & 0xff) + } else { + objectWriteUInt32(this, value, offset, false) + } + return offset + 4 +} + +function checkIEEE754 (buf, value, offset, ext, max, min) { + if (offset + ext > buf.length) throw new RangeError('Index out of range') + if (offset < 0) throw new RangeError('Index out of range') +} + +function writeFloat (buf, value, offset, littleEndian, noAssert) { + if (!noAssert) { + checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38) + } + ieee754.write(buf, value, offset, littleEndian, 23, 4) + return offset + 4 +} + +Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) { + return writeFloat(this, value, offset, true, noAssert) +} + +Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) { + return writeFloat(this, value, offset, false, noAssert) +} + +function writeDouble (buf, value, offset, littleEndian, noAssert) { + if (!noAssert) { + checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308) + } + ieee754.write(buf, value, offset, littleEndian, 52, 8) + return offset + 8 +} + +Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) { + return writeDouble(this, value, offset, true, noAssert) +} + +Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) { + return writeDouble(this, value, offset, false, noAssert) +} + +// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) +Buffer.prototype.copy = function copy (target, targetStart, start, end) { + if (!start) start = 0 + if (!end && end !== 0) end = this.length + if (targetStart >= target.length) targetStart = target.length + if (!targetStart) targetStart = 0 + if (end > 0 && end < start) end = start + + // Copy 0 bytes; we're done + if (end === start) return 0 + if (target.length === 0 || this.length === 0) return 0 + + // Fatal error conditions + if (targetStart < 0) { + throw new RangeError('targetStart out of bounds') + } + if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds') + if (end < 0) throw new RangeError('sourceEnd out of bounds') + + // Are we oob? + if (end > this.length) end = this.length + if (target.length - targetStart < end - start) { + end = target.length - targetStart + start + } + + var len = end - start + var i + + if (this === target && start < targetStart && targetStart < end) { + // descending copy from end + for (i = len - 1; i >= 0; --i) { + target[i + targetStart] = this[i + start] + } + } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) { + // ascending copy from start + for (i = 0; i < len; ++i) { + target[i + targetStart] = this[i + start] + } + } else { + Uint8Array.prototype.set.call( + target, + this.subarray(start, start + len), + targetStart + ) + } + + return len +} + +// Usage: +// buffer.fill(number[, offset[, end]]) +// buffer.fill(buffer[, offset[, end]]) +// buffer.fill(string[, offset[, end]][, encoding]) +Buffer.prototype.fill = function fill (val, start, end, encoding) { + // Handle string cases: + if (typeof val === 'string') { + if (typeof start === 'string') { + encoding = start + start = 0 + end = this.length + } else if (typeof end === 'string') { + encoding = end + end = this.length + } + if (val.length === 1) { + var code = val.charCodeAt(0) + if (code < 256) { + val = code + } + } + if (encoding !== undefined && typeof encoding !== 'string') { + throw new TypeError('encoding must be a string') + } + if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) { + throw new TypeError('Unknown encoding: ' + encoding) + } + } else if (typeof val === 'number') { + val = val & 255 + } + + // Invalid ranges are not set to a default, so can range check early. + if (start < 0 || this.length < start || this.length < end) { + throw new RangeError('Out of range index') + } + + if (end <= start) { + return this + } + + start = start >>> 0 + end = end === undefined ? this.length : end >>> 0 + + if (!val) val = 0 + + var i + if (typeof val === 'number') { + for (i = start; i < end; ++i) { + this[i] = val + } + } else { + var bytes = Buffer.isBuffer(val) + ? val + : utf8ToBytes(new Buffer(val, encoding).toString()) + var len = bytes.length + for (i = 0; i < end - start; ++i) { + this[i + start] = bytes[i % len] + } + } + + return this +} + +// HELPER FUNCTIONS +// ================ + +var INVALID_BASE64_RE = /[^+\/0-9A-Za-z-_]/g + +function base64clean (str) { + // Node strips out invalid characters like \n and \t from the string, base64-js does not + str = stringtrim(str).replace(INVALID_BASE64_RE, '') + // Node converts strings with length < 2 to '' + if (str.length < 2) return '' + // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not + while (str.length % 4 !== 0) { + str = str + '=' + } + return str +} + +function stringtrim (str) { + if (str.trim) return str.trim() + return str.replace(/^\s+|\s+$/g, '') +} + +function toHex (n) { + if (n < 16) return '0' + n.toString(16) + return n.toString(16) +} + +function utf8ToBytes (string, units) { + units = units || Infinity + var codePoint + var length = string.length + var leadSurrogate = null + var bytes = [] + + for (var i = 0; i < length; ++i) { + codePoint = string.charCodeAt(i) + + // is surrogate component + if (codePoint > 0xD7FF && codePoint < 0xE000) { + // last char was a lead + if (!leadSurrogate) { + // no lead yet + if (codePoint > 0xDBFF) { + // unexpected trail + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + continue + } else if (i + 1 === length) { + // unpaired lead + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + continue + } + + // valid lead + leadSurrogate = codePoint + + continue + } + + // 2 leads in a row + if (codePoint < 0xDC00) { + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + leadSurrogate = codePoint + continue + } + + // valid surrogate pair + codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000 + } else if (leadSurrogate) { + // valid bmp char, but last char was a lead + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + } + + leadSurrogate = null + + // encode utf8 + if (codePoint < 0x80) { + if ((units -= 1) < 0) break + bytes.push(codePoint) + } else if (codePoint < 0x800) { + if ((units -= 2) < 0) break + bytes.push( + codePoint >> 0x6 | 0xC0, + codePoint & 0x3F | 0x80 + ) + } else if (codePoint < 0x10000) { + if ((units -= 3) < 0) break + bytes.push( + codePoint >> 0xC | 0xE0, + codePoint >> 0x6 & 0x3F | 0x80, + codePoint & 0x3F | 0x80 + ) + } else if (codePoint < 0x110000) { + if ((units -= 4) < 0) break + bytes.push( + codePoint >> 0x12 | 0xF0, + codePoint >> 0xC & 0x3F | 0x80, + codePoint >> 0x6 & 0x3F | 0x80, + codePoint & 0x3F | 0x80 + ) + } else { + throw new Error('Invalid code point') + } + } + + return bytes +} + +function asciiToBytes (str) { + var byteArray = [] + for (var i = 0; i < str.length; ++i) { + // Node's code seems to be doing this and not & 0x7F.. + byteArray.push(str.charCodeAt(i) & 0xFF) + } + return byteArray +} + +function utf16leToBytes (str, units) { + var c, hi, lo + var byteArray = [] + for (var i = 0; i < str.length; ++i) { + if ((units -= 2) < 0) break + + c = str.charCodeAt(i) + hi = c >> 8 + lo = c % 256 + byteArray.push(lo) + byteArray.push(hi) + } + + return byteArray +} + +function base64ToBytes (str) { + return base64.toByteArray(base64clean(str)) +} + +function blitBuffer (src, dst, offset, length) { + for (var i = 0; i < length; ++i) { + if ((i + offset >= dst.length) || (i >= src.length)) break + dst[i + offset] = src[i] + } + return i +} + +function isnan (val) { + return val !== val // eslint-disable-line no-self-compare +} + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"base64-js":2,"ieee754":37,"isarray":38}],4:[function(require,module,exports){ +module.exports = require('./lib/chai'); + +},{"./lib/chai":5}],5:[function(require,module,exports){ +/*! + * chai + * Copyright(c) 2011-2014 Jake Luer + * MIT Licensed + */ + +var used = [] + , exports = module.exports = {}; + +/*! + * Chai version + */ + +exports.version = '3.5.0'; + +/*! + * Assertion Error + */ + +exports.AssertionError = require('assertion-error'); + +/*! + * Utils for plugins (not exported) + */ + +var util = require('./chai/utils'); + +/** + * # .use(function) + * + * Provides a way to extend the internals of Chai + * + * @param {Function} + * @returns {this} for chaining + * @api public + */ + +exports.use = function (fn) { + if (!~used.indexOf(fn)) { + fn(this, util); + used.push(fn); + } + + return this; +}; + +/*! + * Utility Functions + */ + +exports.util = util; + +/*! + * Configuration + */ + +var config = require('./chai/config'); +exports.config = config; + +/*! + * Primary `Assertion` prototype + */ + +var assertion = require('./chai/assertion'); +exports.use(assertion); + +/*! + * Core Assertions + */ + +var core = require('./chai/core/assertions'); +exports.use(core); + +/*! + * Expect interface + */ + +var expect = require('./chai/interface/expect'); +exports.use(expect); + +/*! + * Should interface + */ + +var should = require('./chai/interface/should'); +exports.use(should); + +/*! + * Assert interface + */ + +var assert = require('./chai/interface/assert'); +exports.use(assert); + +},{"./chai/assertion":6,"./chai/config":7,"./chai/core/assertions":8,"./chai/interface/assert":9,"./chai/interface/expect":10,"./chai/interface/should":11,"./chai/utils":25,"assertion-error":1}],6:[function(require,module,exports){ +/*! + * chai + * http://chaijs.com + * Copyright(c) 2011-2014 Jake Luer + * MIT Licensed + */ + +var config = require('./config'); + +module.exports = function (_chai, util) { + /*! + * Module dependencies. + */ + + var AssertionError = _chai.AssertionError + , flag = util.flag; + + /*! + * Module export. + */ + + _chai.Assertion = Assertion; + + /*! + * Assertion Constructor + * + * Creates object for chaining. + * + * @api private + */ + + function Assertion (obj, msg, stack) { + flag(this, 'ssfi', stack || arguments.callee); + flag(this, 'object', obj); + flag(this, 'message', msg); + } + + Object.defineProperty(Assertion, 'includeStack', { + get: function() { + console.warn('Assertion.includeStack is deprecated, use chai.config.includeStack instead.'); + return config.includeStack; + }, + set: function(value) { + console.warn('Assertion.includeStack is deprecated, use chai.config.includeStack instead.'); + config.includeStack = value; + } + }); + + Object.defineProperty(Assertion, 'showDiff', { + get: function() { + console.warn('Assertion.showDiff is deprecated, use chai.config.showDiff instead.'); + return config.showDiff; + }, + set: function(value) { + console.warn('Assertion.showDiff is deprecated, use chai.config.showDiff instead.'); + config.showDiff = value; + } + }); + + Assertion.addProperty = function (name, fn) { + util.addProperty(this.prototype, name, fn); + }; + + Assertion.addMethod = function (name, fn) { + util.addMethod(this.prototype, name, fn); + }; + + Assertion.addChainableMethod = function (name, fn, chainingBehavior) { + util.addChainableMethod(this.prototype, name, fn, chainingBehavior); + }; + + Assertion.overwriteProperty = function (name, fn) { + util.overwriteProperty(this.prototype, name, fn); + }; + + Assertion.overwriteMethod = function (name, fn) { + util.overwriteMethod(this.prototype, name, fn); + }; + + Assertion.overwriteChainableMethod = function (name, fn, chainingBehavior) { + util.overwriteChainableMethod(this.prototype, name, fn, chainingBehavior); + }; + + /** + * ### .assert(expression, message, negateMessage, expected, actual, showDiff) + * + * Executes an expression and check expectations. Throws AssertionError for reporting if test doesn't pass. + * + * @name assert + * @param {Philosophical} expression to be tested + * @param {String|Function} message or function that returns message to display if expression fails + * @param {String|Function} negatedMessage or function that returns negatedMessage to display if negated expression fails + * @param {Mixed} expected value (remember to check for negation) + * @param {Mixed} actual (optional) will default to `this.obj` + * @param {Boolean} showDiff (optional) when set to `true`, assert will display a diff in addition to the message if expression fails + * @api private + */ + + Assertion.prototype.assert = function (expr, msg, negateMsg, expected, _actual, showDiff) { + var ok = util.test(this, arguments); + if (true !== showDiff) showDiff = false; + if (true !== config.showDiff) showDiff = false; + + if (!ok) { + var msg = util.getMessage(this, arguments) + , actual = util.getActual(this, arguments); + throw new AssertionError(msg, { + actual: actual + , expected: expected + , showDiff: showDiff + }, (config.includeStack) ? this.assert : flag(this, 'ssfi')); + } + }; + + /*! + * ### ._obj + * + * Quick reference to stored `actual` value for plugin developers. + * + * @api private + */ + + Object.defineProperty(Assertion.prototype, '_obj', + { get: function () { + return flag(this, 'object'); + } + , set: function (val) { + flag(this, 'object', val); + } + }); +}; + +},{"./config":7}],7:[function(require,module,exports){ +module.exports = { + + /** + * ### config.includeStack + * + * User configurable property, influences whether stack trace + * is included in Assertion error message. Default of false + * suppresses stack trace in the error message. + * + * chai.config.includeStack = true; // enable stack on error + * + * @param {Boolean} + * @api public + */ + + includeStack: false, + + /** + * ### config.showDiff + * + * User configurable property, influences whether or not + * the `showDiff` flag should be included in the thrown + * AssertionErrors. `false` will always be `false`; `true` + * will be true when the assertion has requested a diff + * be shown. + * + * @param {Boolean} + * @api public + */ + + showDiff: true, + + /** + * ### config.truncateThreshold + * + * User configurable property, sets length threshold for actual and + * expected values in assertion errors. If this threshold is exceeded, for + * example for large data structures, the value is replaced with something + * like `[ Array(3) ]` or `{ Object (prop1, prop2) }`. + * + * Set it to zero if you want to disable truncating altogether. + * + * This is especially userful when doing assertions on arrays: having this + * set to a reasonable large value makes the failure messages readily + * inspectable. + * + * chai.config.truncateThreshold = 0; // disable truncating + * + * @param {Number} + * @api public + */ + + truncateThreshold: 40 + +}; + +},{}],8:[function(require,module,exports){ +/*! + * chai + * http://chaijs.com + * Copyright(c) 2011-2014 Jake Luer + * MIT Licensed + */ + +module.exports = function (chai, _) { + var Assertion = chai.Assertion + , toString = Object.prototype.toString + , flag = _.flag; + + /** + * ### Language Chains + * + * The following are provided as chainable getters to + * improve the readability of your assertions. They + * do not provide testing capabilities unless they + * have been overwritten by a plugin. + * + * **Chains** + * + * - to + * - be + * - been + * - is + * - that + * - which + * - and + * - has + * - have + * - with + * - at + * - of + * - same + * + * @name language chains + * @namespace BDD + * @api public + */ + + [ 'to', 'be', 'been' + , 'is', 'and', 'has', 'have' + , 'with', 'that', 'which', 'at' + , 'of', 'same' ].forEach(function (chain) { + Assertion.addProperty(chain, function () { + return this; + }); + }); + + /** + * ### .not + * + * Negates any of assertions following in the chain. + * + * expect(foo).to.not.equal('bar'); + * expect(goodFn).to.not.throw(Error); + * expect({ foo: 'baz' }).to.have.property('foo') + * .and.not.equal('bar'); + * + * @name not + * @namespace BDD + * @api public + */ + + Assertion.addProperty('not', function () { + flag(this, 'negate', true); + }); + + /** + * ### .deep + * + * Sets the `deep` flag, later used by the `equal` and + * `property` assertions. + * + * expect(foo).to.deep.equal({ bar: 'baz' }); + * expect({ foo: { bar: { baz: 'quux' } } }) + * .to.have.deep.property('foo.bar.baz', 'quux'); + * + * `.deep.property` special characters can be escaped + * by adding two slashes before the `.` or `[]`. + * + * var deepCss = { '.link': { '[target]': 42 }}; + * expect(deepCss).to.have.deep.property('\\.link.\\[target\\]', 42); + * + * @name deep + * @namespace BDD + * @api public + */ + + Assertion.addProperty('deep', function () { + flag(this, 'deep', true); + }); + + /** + * ### .any + * + * Sets the `any` flag, (opposite of the `all` flag) + * later used in the `keys` assertion. + * + * expect(foo).to.have.any.keys('bar', 'baz'); + * + * @name any + * @namespace BDD + * @api public + */ + + Assertion.addProperty('any', function () { + flag(this, 'any', true); + flag(this, 'all', false) + }); + + + /** + * ### .all + * + * Sets the `all` flag (opposite of the `any` flag) + * later used by the `keys` assertion. + * + * expect(foo).to.have.all.keys('bar', 'baz'); + * + * @name all + * @namespace BDD + * @api public + */ + + Assertion.addProperty('all', function () { + flag(this, 'all', true); + flag(this, 'any', false); + }); + + /** + * ### .a(type) + * + * The `a` and `an` assertions are aliases that can be + * used either as language chains or to assert a value's + * type. + * + * // typeof + * expect('test').to.be.a('string'); + * expect({ foo: 'bar' }).to.be.an('object'); + * expect(null).to.be.a('null'); + * expect(undefined).to.be.an('undefined'); + * expect(new Error).to.be.an('error'); + * expect(new Promise).to.be.a('promise'); + * expect(new Float32Array()).to.be.a('float32array'); + * expect(Symbol()).to.be.a('symbol'); + * + * // es6 overrides + * expect({[Symbol.toStringTag]:()=>'foo'}).to.be.a('foo'); + * + * // language chain + * expect(foo).to.be.an.instanceof(Foo); + * + * @name a + * @alias an + * @param {String} type + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function an (type, msg) { + if (msg) flag(this, 'message', msg); + type = type.toLowerCase(); + var obj = flag(this, 'object') + , article = ~[ 'a', 'e', 'i', 'o', 'u' ].indexOf(type.charAt(0)) ? 'an ' : 'a '; + + this.assert( + type === _.type(obj) + , 'expected #{this} to be ' + article + type + , 'expected #{this} not to be ' + article + type + ); + } + + Assertion.addChainableMethod('an', an); + Assertion.addChainableMethod('a', an); + + /** + * ### .include(value) + * + * The `include` and `contain` assertions can be used as either property + * based language chains or as methods to assert the inclusion of an object + * in an array or a substring in a string. When used as language chains, + * they toggle the `contains` flag for the `keys` assertion. + * + * expect([1,2,3]).to.include(2); + * expect('foobar').to.contain('foo'); + * expect({ foo: 'bar', hello: 'universe' }).to.include.keys('foo'); + * + * @name include + * @alias contain + * @alias includes + * @alias contains + * @param {Object|String|Number} obj + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function includeChainingBehavior () { + flag(this, 'contains', true); + } + + function include (val, msg) { + _.expectTypes(this, ['array', 'object', 'string']); + + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + var expected = false; + + if (_.type(obj) === 'array' && _.type(val) === 'object') { + for (var i in obj) { + if (_.eql(obj[i], val)) { + expected = true; + break; + } + } + } else if (_.type(val) === 'object') { + if (!flag(this, 'negate')) { + for (var k in val) new Assertion(obj).property(k, val[k]); + return; + } + var subset = {}; + for (var k in val) subset[k] = obj[k]; + expected = _.eql(subset, val); + } else { + expected = (obj != undefined) && ~obj.indexOf(val); + } + this.assert( + expected + , 'expected #{this} to include ' + _.inspect(val) + , 'expected #{this} to not include ' + _.inspect(val)); + } + + Assertion.addChainableMethod('include', include, includeChainingBehavior); + Assertion.addChainableMethod('contain', include, includeChainingBehavior); + Assertion.addChainableMethod('contains', include, includeChainingBehavior); + Assertion.addChainableMethod('includes', include, includeChainingBehavior); + + /** + * ### .ok + * + * Asserts that the target is truthy. + * + * expect('everything').to.be.ok; + * expect(1).to.be.ok; + * expect(false).to.not.be.ok; + * expect(undefined).to.not.be.ok; + * expect(null).to.not.be.ok; + * + * @name ok + * @namespace BDD + * @api public + */ + + Assertion.addProperty('ok', function () { + this.assert( + flag(this, 'object') + , 'expected #{this} to be truthy' + , 'expected #{this} to be falsy'); + }); + + /** + * ### .true + * + * Asserts that the target is `true`. + * + * expect(true).to.be.true; + * expect(1).to.not.be.true; + * + * @name true + * @namespace BDD + * @api public + */ + + Assertion.addProperty('true', function () { + this.assert( + true === flag(this, 'object') + , 'expected #{this} to be true' + , 'expected #{this} to be false' + , this.negate ? false : true + ); + }); + + /** + * ### .false + * + * Asserts that the target is `false`. + * + * expect(false).to.be.false; + * expect(0).to.not.be.false; + * + * @name false + * @namespace BDD + * @api public + */ + + Assertion.addProperty('false', function () { + this.assert( + false === flag(this, 'object') + , 'expected #{this} to be false' + , 'expected #{this} to be true' + , this.negate ? true : false + ); + }); + + /** + * ### .null + * + * Asserts that the target is `null`. + * + * expect(null).to.be.null; + * expect(undefined).to.not.be.null; + * + * @name null + * @namespace BDD + * @api public + */ + + Assertion.addProperty('null', function () { + this.assert( + null === flag(this, 'object') + , 'expected #{this} to be null' + , 'expected #{this} not to be null' + ); + }); + + /** + * ### .undefined + * + * Asserts that the target is `undefined`. + * + * expect(undefined).to.be.undefined; + * expect(null).to.not.be.undefined; + * + * @name undefined + * @namespace BDD + * @api public + */ + + Assertion.addProperty('undefined', function () { + this.assert( + undefined === flag(this, 'object') + , 'expected #{this} to be undefined' + , 'expected #{this} not to be undefined' + ); + }); + + /** + * ### .NaN + * Asserts that the target is `NaN`. + * + * expect('foo').to.be.NaN; + * expect(4).not.to.be.NaN; + * + * @name NaN + * @namespace BDD + * @api public + */ + + Assertion.addProperty('NaN', function () { + this.assert( + isNaN(flag(this, 'object')) + , 'expected #{this} to be NaN' + , 'expected #{this} not to be NaN' + ); + }); + + /** + * ### .exist + * + * Asserts that the target is neither `null` nor `undefined`. + * + * var foo = 'hi' + * , bar = null + * , baz; + * + * expect(foo).to.exist; + * expect(bar).to.not.exist; + * expect(baz).to.not.exist; + * + * @name exist + * @namespace BDD + * @api public + */ + + Assertion.addProperty('exist', function () { + this.assert( + null != flag(this, 'object') + , 'expected #{this} to exist' + , 'expected #{this} to not exist' + ); + }); + + + /** + * ### .empty + * + * Asserts that the target's length is `0`. For arrays and strings, it checks + * the `length` property. For objects, it gets the count of + * enumerable keys. + * + * expect([]).to.be.empty; + * expect('').to.be.empty; + * expect({}).to.be.empty; + * + * @name empty + * @namespace BDD + * @api public + */ + + Assertion.addProperty('empty', function () { + var obj = flag(this, 'object') + , expected = obj; + + if (Array.isArray(obj) || 'string' === typeof object) { + expected = obj.length; + } else if (typeof obj === 'object') { + expected = Object.keys(obj).length; + } + + this.assert( + !expected + , 'expected #{this} to be empty' + , 'expected #{this} not to be empty' + ); + }); + + /** + * ### .arguments + * + * Asserts that the target is an arguments object. + * + * function test () { + * expect(arguments).to.be.arguments; + * } + * + * @name arguments + * @alias Arguments + * @namespace BDD + * @api public + */ + + function checkArguments () { + var obj = flag(this, 'object') + , type = Object.prototype.toString.call(obj); + this.assert( + '[object Arguments]' === type + , 'expected #{this} to be arguments but got ' + type + , 'expected #{this} to not be arguments' + ); + } + + Assertion.addProperty('arguments', checkArguments); + Assertion.addProperty('Arguments', checkArguments); + + /** + * ### .equal(value) + * + * Asserts that the target is strictly equal (`===`) to `value`. + * Alternately, if the `deep` flag is set, asserts that + * the target is deeply equal to `value`. + * + * expect('hello').to.equal('hello'); + * expect(42).to.equal(42); + * expect(1).to.not.equal(true); + * expect({ foo: 'bar' }).to.not.equal({ foo: 'bar' }); + * expect({ foo: 'bar' }).to.deep.equal({ foo: 'bar' }); + * + * @name equal + * @alias equals + * @alias eq + * @alias deep.equal + * @param {Mixed} value + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function assertEqual (val, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + if (flag(this, 'deep')) { + return this.eql(val); + } else { + this.assert( + val === obj + , 'expected #{this} to equal #{exp}' + , 'expected #{this} to not equal #{exp}' + , val + , this._obj + , true + ); + } + } + + Assertion.addMethod('equal', assertEqual); + Assertion.addMethod('equals', assertEqual); + Assertion.addMethod('eq', assertEqual); + + /** + * ### .eql(value) + * + * Asserts that the target is deeply equal to `value`. + * + * expect({ foo: 'bar' }).to.eql({ foo: 'bar' }); + * expect([ 1, 2, 3 ]).to.eql([ 1, 2, 3 ]); + * + * @name eql + * @alias eqls + * @param {Mixed} value + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function assertEql(obj, msg) { + if (msg) flag(this, 'message', msg); + this.assert( + _.eql(obj, flag(this, 'object')) + , 'expected #{this} to deeply equal #{exp}' + , 'expected #{this} to not deeply equal #{exp}' + , obj + , this._obj + , true + ); + } + + Assertion.addMethod('eql', assertEql); + Assertion.addMethod('eqls', assertEql); + + /** + * ### .above(value) + * + * Asserts that the target is greater than `value`. + * + * expect(10).to.be.above(5); + * + * Can also be used in conjunction with `length` to + * assert a minimum length. The benefit being a + * more informative error message than if the length + * was supplied directly. + * + * expect('foo').to.have.length.above(2); + * expect([ 1, 2, 3 ]).to.have.length.above(2); + * + * @name above + * @alias gt + * @alias greaterThan + * @param {Number} value + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function assertAbove (n, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + if (flag(this, 'doLength')) { + new Assertion(obj, msg).to.have.property('length'); + var len = obj.length; + this.assert( + len > n + , 'expected #{this} to have a length above #{exp} but got #{act}' + , 'expected #{this} to not have a length above #{exp}' + , n + , len + ); + } else { + this.assert( + obj > n + , 'expected #{this} to be above ' + n + , 'expected #{this} to be at most ' + n + ); + } + } + + Assertion.addMethod('above', assertAbove); + Assertion.addMethod('gt', assertAbove); + Assertion.addMethod('greaterThan', assertAbove); + + /** + * ### .least(value) + * + * Asserts that the target is greater than or equal to `value`. + * + * expect(10).to.be.at.least(10); + * + * Can also be used in conjunction with `length` to + * assert a minimum length. The benefit being a + * more informative error message than if the length + * was supplied directly. + * + * expect('foo').to.have.length.of.at.least(2); + * expect([ 1, 2, 3 ]).to.have.length.of.at.least(3); + * + * @name least + * @alias gte + * @param {Number} value + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function assertLeast (n, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + if (flag(this, 'doLength')) { + new Assertion(obj, msg).to.have.property('length'); + var len = obj.length; + this.assert( + len >= n + , 'expected #{this} to have a length at least #{exp} but got #{act}' + , 'expected #{this} to have a length below #{exp}' + , n + , len + ); + } else { + this.assert( + obj >= n + , 'expected #{this} to be at least ' + n + , 'expected #{this} to be below ' + n + ); + } + } + + Assertion.addMethod('least', assertLeast); + Assertion.addMethod('gte', assertLeast); + + /** + * ### .below(value) + * + * Asserts that the target is less than `value`. + * + * expect(5).to.be.below(10); + * + * Can also be used in conjunction with `length` to + * assert a maximum length. The benefit being a + * more informative error message than if the length + * was supplied directly. + * + * expect('foo').to.have.length.below(4); + * expect([ 1, 2, 3 ]).to.have.length.below(4); + * + * @name below + * @alias lt + * @alias lessThan + * @param {Number} value + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function assertBelow (n, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + if (flag(this, 'doLength')) { + new Assertion(obj, msg).to.have.property('length'); + var len = obj.length; + this.assert( + len < n + , 'expected #{this} to have a length below #{exp} but got #{act}' + , 'expected #{this} to not have a length below #{exp}' + , n + , len + ); + } else { + this.assert( + obj < n + , 'expected #{this} to be below ' + n + , 'expected #{this} to be at least ' + n + ); + } + } + + Assertion.addMethod('below', assertBelow); + Assertion.addMethod('lt', assertBelow); + Assertion.addMethod('lessThan', assertBelow); + + /** + * ### .most(value) + * + * Asserts that the target is less than or equal to `value`. + * + * expect(5).to.be.at.most(5); + * + * Can also be used in conjunction with `length` to + * assert a maximum length. The benefit being a + * more informative error message than if the length + * was supplied directly. + * + * expect('foo').to.have.length.of.at.most(4); + * expect([ 1, 2, 3 ]).to.have.length.of.at.most(3); + * + * @name most + * @alias lte + * @param {Number} value + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function assertMost (n, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + if (flag(this, 'doLength')) { + new Assertion(obj, msg).to.have.property('length'); + var len = obj.length; + this.assert( + len <= n + , 'expected #{this} to have a length at most #{exp} but got #{act}' + , 'expected #{this} to have a length above #{exp}' + , n + , len + ); + } else { + this.assert( + obj <= n + , 'expected #{this} to be at most ' + n + , 'expected #{this} to be above ' + n + ); + } + } + + Assertion.addMethod('most', assertMost); + Assertion.addMethod('lte', assertMost); + + /** + * ### .within(start, finish) + * + * Asserts that the target is within a range. + * + * expect(7).to.be.within(5,10); + * + * Can also be used in conjunction with `length` to + * assert a length range. The benefit being a + * more informative error message than if the length + * was supplied directly. + * + * expect('foo').to.have.length.within(2,4); + * expect([ 1, 2, 3 ]).to.have.length.within(2,4); + * + * @name within + * @param {Number} start lowerbound inclusive + * @param {Number} finish upperbound inclusive + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + Assertion.addMethod('within', function (start, finish, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object') + , range = start + '..' + finish; + if (flag(this, 'doLength')) { + new Assertion(obj, msg).to.have.property('length'); + var len = obj.length; + this.assert( + len >= start && len <= finish + , 'expected #{this} to have a length within ' + range + , 'expected #{this} to not have a length within ' + range + ); + } else { + this.assert( + obj >= start && obj <= finish + , 'expected #{this} to be within ' + range + , 'expected #{this} to not be within ' + range + ); + } + }); + + /** + * ### .instanceof(constructor) + * + * Asserts that the target is an instance of `constructor`. + * + * var Tea = function (name) { this.name = name; } + * , Chai = new Tea('chai'); + * + * expect(Chai).to.be.an.instanceof(Tea); + * expect([ 1, 2, 3 ]).to.be.instanceof(Array); + * + * @name instanceof + * @param {Constructor} constructor + * @param {String} message _optional_ + * @alias instanceOf + * @namespace BDD + * @api public + */ + + function assertInstanceOf (constructor, msg) { + if (msg) flag(this, 'message', msg); + var name = _.getName(constructor); + this.assert( + flag(this, 'object') instanceof constructor + , 'expected #{this} to be an instance of ' + name + , 'expected #{this} to not be an instance of ' + name + ); + }; + + Assertion.addMethod('instanceof', assertInstanceOf); + Assertion.addMethod('instanceOf', assertInstanceOf); + + /** + * ### .property(name, [value]) + * + * Asserts that the target has a property `name`, optionally asserting that + * the value of that property is strictly equal to `value`. + * If the `deep` flag is set, you can use dot- and bracket-notation for deep + * references into objects and arrays. + * + * // simple referencing + * var obj = { foo: 'bar' }; + * expect(obj).to.have.property('foo'); + * expect(obj).to.have.property('foo', 'bar'); + * + * // deep referencing + * var deepObj = { + * green: { tea: 'matcha' } + * , teas: [ 'chai', 'matcha', { tea: 'konacha' } ] + * }; + * + * expect(deepObj).to.have.deep.property('green.tea', 'matcha'); + * expect(deepObj).to.have.deep.property('teas[1]', 'matcha'); + * expect(deepObj).to.have.deep.property('teas[2].tea', 'konacha'); + * + * You can also use an array as the starting point of a `deep.property` + * assertion, or traverse nested arrays. + * + * var arr = [ + * [ 'chai', 'matcha', 'konacha' ] + * , [ { tea: 'chai' } + * , { tea: 'matcha' } + * , { tea: 'konacha' } ] + * ]; + * + * expect(arr).to.have.deep.property('[0][1]', 'matcha'); + * expect(arr).to.have.deep.property('[1][2].tea', 'konacha'); + * + * Furthermore, `property` changes the subject of the assertion + * to be the value of that property from the original object. This + * permits for further chainable assertions on that property. + * + * expect(obj).to.have.property('foo') + * .that.is.a('string'); + * expect(deepObj).to.have.property('green') + * .that.is.an('object') + * .that.deep.equals({ tea: 'matcha' }); + * expect(deepObj).to.have.property('teas') + * .that.is.an('array') + * .with.deep.property('[2]') + * .that.deep.equals({ tea: 'konacha' }); + * + * Note that dots and bracket in `name` must be backslash-escaped when + * the `deep` flag is set, while they must NOT be escaped when the `deep` + * flag is not set. + * + * // simple referencing + * var css = { '.link[target]': 42 }; + * expect(css).to.have.property('.link[target]', 42); + * + * // deep referencing + * var deepCss = { '.link': { '[target]': 42 }}; + * expect(deepCss).to.have.deep.property('\\.link.\\[target\\]', 42); + * + * @name property + * @alias deep.property + * @param {String} name + * @param {Mixed} value (optional) + * @param {String} message _optional_ + * @returns value of property for chaining + * @namespace BDD + * @api public + */ + + Assertion.addMethod('property', function (name, val, msg) { + if (msg) flag(this, 'message', msg); + + var isDeep = !!flag(this, 'deep') + , descriptor = isDeep ? 'deep property ' : 'property ' + , negate = flag(this, 'negate') + , obj = flag(this, 'object') + , pathInfo = isDeep ? _.getPathInfo(name, obj) : null + , hasProperty = isDeep + ? pathInfo.exists + : _.hasProperty(name, obj) + , value = isDeep + ? pathInfo.value + : obj[name]; + + if (negate && arguments.length > 1) { + if (undefined === value) { + msg = (msg != null) ? msg + ': ' : ''; + throw new Error(msg + _.inspect(obj) + ' has no ' + descriptor + _.inspect(name)); + } + } else { + this.assert( + hasProperty + , 'expected #{this} to have a ' + descriptor + _.inspect(name) + , 'expected #{this} to not have ' + descriptor + _.inspect(name)); + } + + if (arguments.length > 1) { + this.assert( + val === value + , 'expected #{this} to have a ' + descriptor + _.inspect(name) + ' of #{exp}, but got #{act}' + , 'expected #{this} to not have a ' + descriptor + _.inspect(name) + ' of #{act}' + , val + , value + ); + } + + flag(this, 'object', value); + }); + + + /** + * ### .ownProperty(name) + * + * Asserts that the target has an own property `name`. + * + * expect('test').to.have.ownProperty('length'); + * + * @name ownProperty + * @alias haveOwnProperty + * @param {String} name + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function assertOwnProperty (name, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + this.assert( + obj.hasOwnProperty(name) + , 'expected #{this} to have own property ' + _.inspect(name) + , 'expected #{this} to not have own property ' + _.inspect(name) + ); + } + + Assertion.addMethod('ownProperty', assertOwnProperty); + Assertion.addMethod('haveOwnProperty', assertOwnProperty); + + /** + * ### .ownPropertyDescriptor(name[, descriptor[, message]]) + * + * Asserts that the target has an own property descriptor `name`, that optionally matches `descriptor`. + * + * expect('test').to.have.ownPropertyDescriptor('length'); + * expect('test').to.have.ownPropertyDescriptor('length', { enumerable: false, configurable: false, writable: false, value: 4 }); + * expect('test').not.to.have.ownPropertyDescriptor('length', { enumerable: false, configurable: false, writable: false, value: 3 }); + * expect('test').ownPropertyDescriptor('length').to.have.property('enumerable', false); + * expect('test').ownPropertyDescriptor('length').to.have.keys('value'); + * + * @name ownPropertyDescriptor + * @alias haveOwnPropertyDescriptor + * @param {String} name + * @param {Object} descriptor _optional_ + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function assertOwnPropertyDescriptor (name, descriptor, msg) { + if (typeof descriptor === 'string') { + msg = descriptor; + descriptor = null; + } + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + var actualDescriptor = Object.getOwnPropertyDescriptor(Object(obj), name); + if (actualDescriptor && descriptor) { + this.assert( + _.eql(descriptor, actualDescriptor) + , 'expected the own property descriptor for ' + _.inspect(name) + ' on #{this} to match ' + _.inspect(descriptor) + ', got ' + _.inspect(actualDescriptor) + , 'expected the own property descriptor for ' + _.inspect(name) + ' on #{this} to not match ' + _.inspect(descriptor) + , descriptor + , actualDescriptor + , true + ); + } else { + this.assert( + actualDescriptor + , 'expected #{this} to have an own property descriptor for ' + _.inspect(name) + , 'expected #{this} to not have an own property descriptor for ' + _.inspect(name) + ); + } + flag(this, 'object', actualDescriptor); + } + + Assertion.addMethod('ownPropertyDescriptor', assertOwnPropertyDescriptor); + Assertion.addMethod('haveOwnPropertyDescriptor', assertOwnPropertyDescriptor); + + /** + * ### .length + * + * Sets the `doLength` flag later used as a chain precursor to a value + * comparison for the `length` property. + * + * expect('foo').to.have.length.above(2); + * expect([ 1, 2, 3 ]).to.have.length.above(2); + * expect('foo').to.have.length.below(4); + * expect([ 1, 2, 3 ]).to.have.length.below(4); + * expect('foo').to.have.length.within(2,4); + * expect([ 1, 2, 3 ]).to.have.length.within(2,4); + * + * *Deprecation notice:* Using `length` as an assertion will be deprecated + * in version 2.4.0 and removed in 3.0.0. Code using the old style of + * asserting for `length` property value using `length(value)` should be + * switched to use `lengthOf(value)` instead. + * + * @name length + * @namespace BDD + * @api public + */ + + /** + * ### .lengthOf(value[, message]) + * + * Asserts that the target's `length` property has + * the expected value. + * + * expect([ 1, 2, 3]).to.have.lengthOf(3); + * expect('foobar').to.have.lengthOf(6); + * + * @name lengthOf + * @param {Number} length + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function assertLengthChain () { + flag(this, 'doLength', true); + } + + function assertLength (n, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + new Assertion(obj, msg).to.have.property('length'); + var len = obj.length; + + this.assert( + len == n + , 'expected #{this} to have a length of #{exp} but got #{act}' + , 'expected #{this} to not have a length of #{act}' + , n + , len + ); + } + + Assertion.addChainableMethod('length', assertLength, assertLengthChain); + Assertion.addMethod('lengthOf', assertLength); + + /** + * ### .match(regexp) + * + * Asserts that the target matches a regular expression. + * + * expect('foobar').to.match(/^foo/); + * + * @name match + * @alias matches + * @param {RegExp} RegularExpression + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + function assertMatch(re, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + this.assert( + re.exec(obj) + , 'expected #{this} to match ' + re + , 'expected #{this} not to match ' + re + ); + } + + Assertion.addMethod('match', assertMatch); + Assertion.addMethod('matches', assertMatch); + + /** + * ### .string(string) + * + * Asserts that the string target contains another string. + * + * expect('foobar').to.have.string('bar'); + * + * @name string + * @param {String} string + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + Assertion.addMethod('string', function (str, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + new Assertion(obj, msg).is.a('string'); + + this.assert( + ~obj.indexOf(str) + , 'expected #{this} to contain ' + _.inspect(str) + , 'expected #{this} to not contain ' + _.inspect(str) + ); + }); + + + /** + * ### .keys(key1, [key2], [...]) + * + * Asserts that the target contains any or all of the passed-in keys. + * Use in combination with `any`, `all`, `contains`, or `have` will affect + * what will pass. + * + * When used in conjunction with `any`, at least one key that is passed + * in must exist in the target object. This is regardless whether or not + * the `have` or `contain` qualifiers are used. Note, either `any` or `all` + * should be used in the assertion. If neither are used, the assertion is + * defaulted to `all`. + * + * When both `all` and `contain` are used, the target object must have at + * least all of the passed-in keys but may have more keys not listed. + * + * When both `all` and `have` are used, the target object must both contain + * all of the passed-in keys AND the number of keys in the target object must + * match the number of keys passed in (in other words, a target object must + * have all and only all of the passed-in keys). + * + * expect({ foo: 1, bar: 2 }).to.have.any.keys('foo', 'baz'); + * expect({ foo: 1, bar: 2 }).to.have.any.keys('foo'); + * expect({ foo: 1, bar: 2 }).to.contain.any.keys('bar', 'baz'); + * expect({ foo: 1, bar: 2 }).to.contain.any.keys(['foo']); + * expect({ foo: 1, bar: 2 }).to.contain.any.keys({'foo': 6}); + * expect({ foo: 1, bar: 2 }).to.have.all.keys(['bar', 'foo']); + * expect({ foo: 1, bar: 2 }).to.have.all.keys({'bar': 6, 'foo': 7}); + * expect({ foo: 1, bar: 2, baz: 3 }).to.contain.all.keys(['bar', 'foo']); + * expect({ foo: 1, bar: 2, baz: 3 }).to.contain.all.keys({'bar': 6}); + * + * + * @name keys + * @alias key + * @param {...String|Array|Object} keys + * @namespace BDD + * @api public + */ + + function assertKeys (keys) { + var obj = flag(this, 'object') + , str + , ok = true + , mixedArgsMsg = 'keys must be given single argument of Array|Object|String, or multiple String arguments'; + + switch (_.type(keys)) { + case "array": + if (arguments.length > 1) throw (new Error(mixedArgsMsg)); + break; + case "object": + if (arguments.length > 1) throw (new Error(mixedArgsMsg)); + keys = Object.keys(keys); + break; + default: + keys = Array.prototype.slice.call(arguments); + } + + if (!keys.length) throw new Error('keys required'); + + var actual = Object.keys(obj) + , expected = keys + , len = keys.length + , any = flag(this, 'any') + , all = flag(this, 'all'); + + if (!any && !all) { + all = true; + } + + // Has any + if (any) { + var intersection = expected.filter(function(key) { + return ~actual.indexOf(key); + }); + ok = intersection.length > 0; + } + + // Has all + if (all) { + ok = keys.every(function(key){ + return ~actual.indexOf(key); + }); + if (!flag(this, 'negate') && !flag(this, 'contains')) { + ok = ok && keys.length == actual.length; + } + } + + // Key string + if (len > 1) { + keys = keys.map(function(key){ + return _.inspect(key); + }); + var last = keys.pop(); + if (all) { + str = keys.join(', ') + ', and ' + last; + } + if (any) { + str = keys.join(', ') + ', or ' + last; + } + } else { + str = _.inspect(keys[0]); + } + + // Form + str = (len > 1 ? 'keys ' : 'key ') + str; + + // Have / include + str = (flag(this, 'contains') ? 'contain ' : 'have ') + str; + + // Assertion + this.assert( + ok + , 'expected #{this} to ' + str + , 'expected #{this} to not ' + str + , expected.slice(0).sort() + , actual.sort() + , true + ); + } + + Assertion.addMethod('keys', assertKeys); + Assertion.addMethod('key', assertKeys); + + /** + * ### .throw(constructor) + * + * Asserts that the function target will throw a specific error, or specific type of error + * (as determined using `instanceof`), optionally with a RegExp or string inclusion test + * for the error's message. + * + * var err = new ReferenceError('This is a bad function.'); + * var fn = function () { throw err; } + * expect(fn).to.throw(ReferenceError); + * expect(fn).to.throw(Error); + * expect(fn).to.throw(/bad function/); + * expect(fn).to.not.throw('good function'); + * expect(fn).to.throw(ReferenceError, /bad function/); + * expect(fn).to.throw(err); + * + * Please note that when a throw expectation is negated, it will check each + * parameter independently, starting with error constructor type. The appropriate way + * to check for the existence of a type of error but for a message that does not match + * is to use `and`. + * + * expect(fn).to.throw(ReferenceError) + * .and.not.throw(/good function/); + * + * @name throw + * @alias throws + * @alias Throw + * @param {ErrorConstructor} constructor + * @param {String|RegExp} expected error message + * @param {String} message _optional_ + * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types + * @returns error for chaining (null if no error) + * @namespace BDD + * @api public + */ + + function assertThrows (constructor, errMsg, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + new Assertion(obj, msg).is.a('function'); + + var thrown = false + , desiredError = null + , name = null + , thrownError = null; + + if (arguments.length === 0) { + errMsg = null; + constructor = null; + } else if (constructor && (constructor instanceof RegExp || 'string' === typeof constructor)) { + errMsg = constructor; + constructor = null; + } else if (constructor && constructor instanceof Error) { + desiredError = constructor; + constructor = null; + errMsg = null; + } else if (typeof constructor === 'function') { + name = constructor.prototype.name; + if (!name || (name === 'Error' && constructor !== Error)) { + name = constructor.name || (new constructor()).name; + } + } else { + constructor = null; + } + + try { + obj(); + } catch (err) { + // first, check desired error + if (desiredError) { + this.assert( + err === desiredError + , 'expected #{this} to throw #{exp} but #{act} was thrown' + , 'expected #{this} to not throw #{exp}' + , (desiredError instanceof Error ? desiredError.toString() : desiredError) + , (err instanceof Error ? err.toString() : err) + ); + + flag(this, 'object', err); + return this; + } + + // next, check constructor + if (constructor) { + this.assert( + err instanceof constructor + , 'expected #{this} to throw #{exp} but #{act} was thrown' + , 'expected #{this} to not throw #{exp} but #{act} was thrown' + , name + , (err instanceof Error ? err.toString() : err) + ); + + if (!errMsg) { + flag(this, 'object', err); + return this; + } + } + + // next, check message + var message = 'error' === _.type(err) && "message" in err + ? err.message + : '' + err; + + if ((message != null) && errMsg && errMsg instanceof RegExp) { + this.assert( + errMsg.exec(message) + , 'expected #{this} to throw error matching #{exp} but got #{act}' + , 'expected #{this} to throw error not matching #{exp}' + , errMsg + , message + ); + + flag(this, 'object', err); + return this; + } else if ((message != null) && errMsg && 'string' === typeof errMsg) { + this.assert( + ~message.indexOf(errMsg) + , 'expected #{this} to throw error including #{exp} but got #{act}' + , 'expected #{this} to throw error not including #{act}' + , errMsg + , message + ); + + flag(this, 'object', err); + return this; + } else { + thrown = true; + thrownError = err; + } + } + + var actuallyGot = '' + , expectedThrown = name !== null + ? name + : desiredError + ? '#{exp}' //_.inspect(desiredError) + : 'an error'; + + if (thrown) { + actuallyGot = ' but #{act} was thrown' + } + + this.assert( + thrown === true + , 'expected #{this} to throw ' + expectedThrown + actuallyGot + , 'expected #{this} to not throw ' + expectedThrown + actuallyGot + , (desiredError instanceof Error ? desiredError.toString() : desiredError) + , (thrownError instanceof Error ? thrownError.toString() : thrownError) + ); + + flag(this, 'object', thrownError); + }; + + Assertion.addMethod('throw', assertThrows); + Assertion.addMethod('throws', assertThrows); + Assertion.addMethod('Throw', assertThrows); + + /** + * ### .respondTo(method) + * + * Asserts that the object or class target will respond to a method. + * + * Klass.prototype.bar = function(){}; + * expect(Klass).to.respondTo('bar'); + * expect(obj).to.respondTo('bar'); + * + * To check if a constructor will respond to a static function, + * set the `itself` flag. + * + * Klass.baz = function(){}; + * expect(Klass).itself.to.respondTo('baz'); + * + * @name respondTo + * @alias respondsTo + * @param {String} method + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function respondTo (method, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object') + , itself = flag(this, 'itself') + , context = ('function' === _.type(obj) && !itself) + ? obj.prototype[method] + : obj[method]; + + this.assert( + 'function' === typeof context + , 'expected #{this} to respond to ' + _.inspect(method) + , 'expected #{this} to not respond to ' + _.inspect(method) + ); + } + + Assertion.addMethod('respondTo', respondTo); + Assertion.addMethod('respondsTo', respondTo); + + /** + * ### .itself + * + * Sets the `itself` flag, later used by the `respondTo` assertion. + * + * function Foo() {} + * Foo.bar = function() {} + * Foo.prototype.baz = function() {} + * + * expect(Foo).itself.to.respondTo('bar'); + * expect(Foo).itself.not.to.respondTo('baz'); + * + * @name itself + * @namespace BDD + * @api public + */ + + Assertion.addProperty('itself', function () { + flag(this, 'itself', true); + }); + + /** + * ### .satisfy(method) + * + * Asserts that the target passes a given truth test. + * + * expect(1).to.satisfy(function(num) { return num > 0; }); + * + * @name satisfy + * @alias satisfies + * @param {Function} matcher + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function satisfy (matcher, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + var result = matcher(obj); + this.assert( + result + , 'expected #{this} to satisfy ' + _.objDisplay(matcher) + , 'expected #{this} to not satisfy' + _.objDisplay(matcher) + , this.negate ? false : true + , result + ); + } + + Assertion.addMethod('satisfy', satisfy); + Assertion.addMethod('satisfies', satisfy); + + /** + * ### .closeTo(expected, delta) + * + * Asserts that the target is equal `expected`, to within a +/- `delta` range. + * + * expect(1.5).to.be.closeTo(1, 0.5); + * + * @name closeTo + * @alias approximately + * @param {Number} expected + * @param {Number} delta + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function closeTo(expected, delta, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + + new Assertion(obj, msg).is.a('number'); + if (_.type(expected) !== 'number' || _.type(delta) !== 'number') { + throw new Error('the arguments to closeTo or approximately must be numbers'); + } + + this.assert( + Math.abs(obj - expected) <= delta + , 'expected #{this} to be close to ' + expected + ' +/- ' + delta + , 'expected #{this} not to be close to ' + expected + ' +/- ' + delta + ); + } + + Assertion.addMethod('closeTo', closeTo); + Assertion.addMethod('approximately', closeTo); + + function isSubsetOf(subset, superset, cmp) { + return subset.every(function(elem) { + if (!cmp) return superset.indexOf(elem) !== -1; + + return superset.some(function(elem2) { + return cmp(elem, elem2); + }); + }) + } + + /** + * ### .members(set) + * + * Asserts that the target is a superset of `set`, + * or that the target and `set` have the same strictly-equal (===) members. + * Alternately, if the `deep` flag is set, set members are compared for deep + * equality. + * + * expect([1, 2, 3]).to.include.members([3, 2]); + * expect([1, 2, 3]).to.not.include.members([3, 2, 8]); + * + * expect([4, 2]).to.have.members([2, 4]); + * expect([5, 2]).to.not.have.members([5, 2, 1]); + * + * expect([{ id: 1 }]).to.deep.include.members([{ id: 1 }]); + * + * @name members + * @param {Array} set + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + Assertion.addMethod('members', function (subset, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + + new Assertion(obj).to.be.an('array'); + new Assertion(subset).to.be.an('array'); + + var cmp = flag(this, 'deep') ? _.eql : undefined; + + if (flag(this, 'contains')) { + return this.assert( + isSubsetOf(subset, obj, cmp) + , 'expected #{this} to be a superset of #{act}' + , 'expected #{this} to not be a superset of #{act}' + , obj + , subset + ); + } + + this.assert( + isSubsetOf(obj, subset, cmp) && isSubsetOf(subset, obj, cmp) + , 'expected #{this} to have the same members as #{act}' + , 'expected #{this} to not have the same members as #{act}' + , obj + , subset + ); + }); + + /** + * ### .oneOf(list) + * + * Assert that a value appears somewhere in the top level of array `list`. + * + * expect('a').to.be.oneOf(['a', 'b', 'c']); + * expect(9).to.not.be.oneOf(['z']); + * expect([3]).to.not.be.oneOf([1, 2, [3]]); + * + * var three = [3]; + * // for object-types, contents are not compared + * expect(three).to.not.be.oneOf([1, 2, [3]]); + * // comparing references works + * expect(three).to.be.oneOf([1, 2, three]); + * + * @name oneOf + * @param {Array<*>} list + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function oneOf (list, msg) { + if (msg) flag(this, 'message', msg); + var expected = flag(this, 'object'); + new Assertion(list).to.be.an('array'); + + this.assert( + list.indexOf(expected) > -1 + , 'expected #{this} to be one of #{exp}' + , 'expected #{this} to not be one of #{exp}' + , list + , expected + ); + } + + Assertion.addMethod('oneOf', oneOf); + + + /** + * ### .change(function) + * + * Asserts that a function changes an object property + * + * var obj = { val: 10 }; + * var fn = function() { obj.val += 3 }; + * var noChangeFn = function() { return 'foo' + 'bar'; } + * expect(fn).to.change(obj, 'val'); + * expect(noChangeFn).to.not.change(obj, 'val') + * + * @name change + * @alias changes + * @alias Change + * @param {String} object + * @param {String} property name + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function assertChanges (object, prop, msg) { + if (msg) flag(this, 'message', msg); + var fn = flag(this, 'object'); + new Assertion(object, msg).to.have.property(prop); + new Assertion(fn).is.a('function'); + + var initial = object[prop]; + fn(); + + this.assert( + initial !== object[prop] + , 'expected .' + prop + ' to change' + , 'expected .' + prop + ' to not change' + ); + } + + Assertion.addChainableMethod('change', assertChanges); + Assertion.addChainableMethod('changes', assertChanges); + + /** + * ### .increase(function) + * + * Asserts that a function increases an object property + * + * var obj = { val: 10 }; + * var fn = function() { obj.val = 15 }; + * expect(fn).to.increase(obj, 'val'); + * + * @name increase + * @alias increases + * @alias Increase + * @param {String} object + * @param {String} property name + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function assertIncreases (object, prop, msg) { + if (msg) flag(this, 'message', msg); + var fn = flag(this, 'object'); + new Assertion(object, msg).to.have.property(prop); + new Assertion(fn).is.a('function'); + + var initial = object[prop]; + fn(); + + this.assert( + object[prop] - initial > 0 + , 'expected .' + prop + ' to increase' + , 'expected .' + prop + ' to not increase' + ); + } + + Assertion.addChainableMethod('increase', assertIncreases); + Assertion.addChainableMethod('increases', assertIncreases); + + /** + * ### .decrease(function) + * + * Asserts that a function decreases an object property + * + * var obj = { val: 10 }; + * var fn = function() { obj.val = 5 }; + * expect(fn).to.decrease(obj, 'val'); + * + * @name decrease + * @alias decreases + * @alias Decrease + * @param {String} object + * @param {String} property name + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function assertDecreases (object, prop, msg) { + if (msg) flag(this, 'message', msg); + var fn = flag(this, 'object'); + new Assertion(object, msg).to.have.property(prop); + new Assertion(fn).is.a('function'); + + var initial = object[prop]; + fn(); + + this.assert( + object[prop] - initial < 0 + , 'expected .' + prop + ' to decrease' + , 'expected .' + prop + ' to not decrease' + ); + } + + Assertion.addChainableMethod('decrease', assertDecreases); + Assertion.addChainableMethod('decreases', assertDecreases); + + /** + * ### .extensible + * + * Asserts that the target is extensible (can have new properties added to + * it). + * + * var nonExtensibleObject = Object.preventExtensions({}); + * var sealedObject = Object.seal({}); + * var frozenObject = Object.freeze({}); + * + * expect({}).to.be.extensible; + * expect(nonExtensibleObject).to.not.be.extensible; + * expect(sealedObject).to.not.be.extensible; + * expect(frozenObject).to.not.be.extensible; + * + * @name extensible + * @namespace BDD + * @api public + */ + + Assertion.addProperty('extensible', function() { + var obj = flag(this, 'object'); + + // In ES5, if the argument to this method is not an object (a primitive), then it will cause a TypeError. + // In ES6, a non-object argument will be treated as if it was a non-extensible ordinary object, simply return false. + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isExtensible + // The following provides ES6 behavior when a TypeError is thrown under ES5. + + var isExtensible; + + try { + isExtensible = Object.isExtensible(obj); + } catch (err) { + if (err instanceof TypeError) isExtensible = false; + else throw err; + } + + this.assert( + isExtensible + , 'expected #{this} to be extensible' + , 'expected #{this} to not be extensible' + ); + }); + + /** + * ### .sealed + * + * Asserts that the target is sealed (cannot have new properties added to it + * and its existing properties cannot be removed). + * + * var sealedObject = Object.seal({}); + * var frozenObject = Object.freeze({}); + * + * expect(sealedObject).to.be.sealed; + * expect(frozenObject).to.be.sealed; + * expect({}).to.not.be.sealed; + * + * @name sealed + * @namespace BDD + * @api public + */ + + Assertion.addProperty('sealed', function() { + var obj = flag(this, 'object'); + + // In ES5, if the argument to this method is not an object (a primitive), then it will cause a TypeError. + // In ES6, a non-object argument will be treated as if it was a sealed ordinary object, simply return true. + // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isSealed + // The following provides ES6 behavior when a TypeError is thrown under ES5. + + var isSealed; + + try { + isSealed = Object.isSealed(obj); + } catch (err) { + if (err instanceof TypeError) isSealed = true; + else throw err; + } + + this.assert( + isSealed + , 'expected #{this} to be sealed' + , 'expected #{this} to not be sealed' + ); + }); + + /** + * ### .frozen + * + * Asserts that the target is frozen (cannot have new properties added to it + * and its existing properties cannot be modified). + * + * var frozenObject = Object.freeze({}); + * + * expect(frozenObject).to.be.frozen; + * expect({}).to.not.be.frozen; + * + * @name frozen + * @namespace BDD + * @api public + */ + + Assertion.addProperty('frozen', function() { + var obj = flag(this, 'object'); + + // In ES5, if the argument to this method is not an object (a primitive), then it will cause a TypeError. + // In ES6, a non-object argument will be treated as if it was a frozen ordinary object, simply return true. + // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isFrozen + // The following provides ES6 behavior when a TypeError is thrown under ES5. + + var isFrozen; + + try { + isFrozen = Object.isFrozen(obj); + } catch (err) { + if (err instanceof TypeError) isFrozen = true; + else throw err; + } + + this.assert( + isFrozen + , 'expected #{this} to be frozen' + , 'expected #{this} to not be frozen' + ); + }); +}; + +},{}],9:[function(require,module,exports){ +/*! + * chai + * Copyright(c) 2011-2014 Jake Luer + * MIT Licensed + */ + + +module.exports = function (chai, util) { + + /*! + * Chai dependencies. + */ + + var Assertion = chai.Assertion + , flag = util.flag; + + /*! + * Module export. + */ + + /** + * ### assert(expression, message) + * + * Write your own test expressions. + * + * assert('foo' !== 'bar', 'foo is not bar'); + * assert(Array.isArray([]), 'empty arrays are arrays'); + * + * @param {Mixed} expression to test for truthiness + * @param {String} message to display on error + * @name assert + * @namespace Assert + * @api public + */ + + var assert = chai.assert = function (express, errmsg) { + var test = new Assertion(null, null, chai.assert); + test.assert( + express + , errmsg + , '[ negation message unavailable ]' + ); + }; + + /** + * ### .fail(actual, expected, [message], [operator]) + * + * Throw a failure. Node.js `assert` module-compatible. + * + * @name fail + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @param {String} operator + * @namespace Assert + * @api public + */ + + assert.fail = function (actual, expected, message, operator) { + message = message || 'assert.fail()'; + throw new chai.AssertionError(message, { + actual: actual + , expected: expected + , operator: operator + }, assert.fail); + }; + + /** + * ### .isOk(object, [message]) + * + * Asserts that `object` is truthy. + * + * assert.isOk('everything', 'everything is ok'); + * assert.isOk(false, 'this will fail'); + * + * @name isOk + * @alias ok + * @param {Mixed} object to test + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isOk = function (val, msg) { + new Assertion(val, msg).is.ok; + }; + + /** + * ### .isNotOk(object, [message]) + * + * Asserts that `object` is falsy. + * + * assert.isNotOk('everything', 'this will fail'); + * assert.isNotOk(false, 'this will pass'); + * + * @name isNotOk + * @alias notOk + * @param {Mixed} object to test + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isNotOk = function (val, msg) { + new Assertion(val, msg).is.not.ok; + }; + + /** + * ### .equal(actual, expected, [message]) + * + * Asserts non-strict equality (`==`) of `actual` and `expected`. + * + * assert.equal(3, '3', '== coerces values to strings'); + * + * @name equal + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.equal = function (act, exp, msg) { + var test = new Assertion(act, msg, assert.equal); + + test.assert( + exp == flag(test, 'object') + , 'expected #{this} to equal #{exp}' + , 'expected #{this} to not equal #{act}' + , exp + , act + ); + }; + + /** + * ### .notEqual(actual, expected, [message]) + * + * Asserts non-strict inequality (`!=`) of `actual` and `expected`. + * + * assert.notEqual(3, 4, 'these numbers are not equal'); + * + * @name notEqual + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.notEqual = function (act, exp, msg) { + var test = new Assertion(act, msg, assert.notEqual); + + test.assert( + exp != flag(test, 'object') + , 'expected #{this} to not equal #{exp}' + , 'expected #{this} to equal #{act}' + , exp + , act + ); + }; + + /** + * ### .strictEqual(actual, expected, [message]) + * + * Asserts strict equality (`===`) of `actual` and `expected`. + * + * assert.strictEqual(true, true, 'these booleans are strictly equal'); + * + * @name strictEqual + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.strictEqual = function (act, exp, msg) { + new Assertion(act, msg).to.equal(exp); + }; + + /** + * ### .notStrictEqual(actual, expected, [message]) + * + * Asserts strict inequality (`!==`) of `actual` and `expected`. + * + * assert.notStrictEqual(3, '3', 'no coercion for strict equality'); + * + * @name notStrictEqual + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.notStrictEqual = function (act, exp, msg) { + new Assertion(act, msg).to.not.equal(exp); + }; + + /** + * ### .deepEqual(actual, expected, [message]) + * + * Asserts that `actual` is deeply equal to `expected`. + * + * assert.deepEqual({ tea: 'green' }, { tea: 'green' }); + * + * @name deepEqual + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.deepEqual = function (act, exp, msg) { + new Assertion(act, msg).to.eql(exp); + }; + + /** + * ### .notDeepEqual(actual, expected, [message]) + * + * Assert that `actual` is not deeply equal to `expected`. + * + * assert.notDeepEqual({ tea: 'green' }, { tea: 'jasmine' }); + * + * @name notDeepEqual + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.notDeepEqual = function (act, exp, msg) { + new Assertion(act, msg).to.not.eql(exp); + }; + + /** + * ### .isAbove(valueToCheck, valueToBeAbove, [message]) + * + * Asserts `valueToCheck` is strictly greater than (>) `valueToBeAbove` + * + * assert.isAbove(5, 2, '5 is strictly greater than 2'); + * + * @name isAbove + * @param {Mixed} valueToCheck + * @param {Mixed} valueToBeAbove + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isAbove = function (val, abv, msg) { + new Assertion(val, msg).to.be.above(abv); + }; + + /** + * ### .isAtLeast(valueToCheck, valueToBeAtLeast, [message]) + * + * Asserts `valueToCheck` is greater than or equal to (>=) `valueToBeAtLeast` + * + * assert.isAtLeast(5, 2, '5 is greater or equal to 2'); + * assert.isAtLeast(3, 3, '3 is greater or equal to 3'); + * + * @name isAtLeast + * @param {Mixed} valueToCheck + * @param {Mixed} valueToBeAtLeast + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isAtLeast = function (val, atlst, msg) { + new Assertion(val, msg).to.be.least(atlst); + }; + + /** + * ### .isBelow(valueToCheck, valueToBeBelow, [message]) + * + * Asserts `valueToCheck` is strictly less than (<) `valueToBeBelow` + * + * assert.isBelow(3, 6, '3 is strictly less than 6'); + * + * @name isBelow + * @param {Mixed} valueToCheck + * @param {Mixed} valueToBeBelow + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isBelow = function (val, blw, msg) { + new Assertion(val, msg).to.be.below(blw); + }; + + /** + * ### .isAtMost(valueToCheck, valueToBeAtMost, [message]) + * + * Asserts `valueToCheck` is less than or equal to (<=) `valueToBeAtMost` + * + * assert.isAtMost(3, 6, '3 is less than or equal to 6'); + * assert.isAtMost(4, 4, '4 is less than or equal to 4'); + * + * @name isAtMost + * @param {Mixed} valueToCheck + * @param {Mixed} valueToBeAtMost + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isAtMost = function (val, atmst, msg) { + new Assertion(val, msg).to.be.most(atmst); + }; + + /** + * ### .isTrue(value, [message]) + * + * Asserts that `value` is true. + * + * var teaServed = true; + * assert.isTrue(teaServed, 'the tea has been served'); + * + * @name isTrue + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isTrue = function (val, msg) { + new Assertion(val, msg).is['true']; + }; + + /** + * ### .isNotTrue(value, [message]) + * + * Asserts that `value` is not true. + * + * var tea = 'tasty chai'; + * assert.isNotTrue(tea, 'great, time for tea!'); + * + * @name isNotTrue + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isNotTrue = function (val, msg) { + new Assertion(val, msg).to.not.equal(true); + }; + + /** + * ### .isFalse(value, [message]) + * + * Asserts that `value` is false. + * + * var teaServed = false; + * assert.isFalse(teaServed, 'no tea yet? hmm...'); + * + * @name isFalse + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isFalse = function (val, msg) { + new Assertion(val, msg).is['false']; + }; + + /** + * ### .isNotFalse(value, [message]) + * + * Asserts that `value` is not false. + * + * var tea = 'tasty chai'; + * assert.isNotFalse(tea, 'great, time for tea!'); + * + * @name isNotFalse + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isNotFalse = function (val, msg) { + new Assertion(val, msg).to.not.equal(false); + }; + + /** + * ### .isNull(value, [message]) + * + * Asserts that `value` is null. + * + * assert.isNull(err, 'there was no error'); + * + * @name isNull + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isNull = function (val, msg) { + new Assertion(val, msg).to.equal(null); + }; + + /** + * ### .isNotNull(value, [message]) + * + * Asserts that `value` is not null. + * + * var tea = 'tasty chai'; + * assert.isNotNull(tea, 'great, time for tea!'); + * + * @name isNotNull + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isNotNull = function (val, msg) { + new Assertion(val, msg).to.not.equal(null); + }; + + /** + * ### .isNaN + * Asserts that value is NaN + * + * assert.isNaN('foo', 'foo is NaN'); + * + * @name isNaN + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isNaN = function (val, msg) { + new Assertion(val, msg).to.be.NaN; + }; + + /** + * ### .isNotNaN + * Asserts that value is not NaN + * + * assert.isNotNaN(4, '4 is not NaN'); + * + * @name isNotNaN + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + assert.isNotNaN = function (val, msg) { + new Assertion(val, msg).not.to.be.NaN; + }; + + /** + * ### .isUndefined(value, [message]) + * + * Asserts that `value` is `undefined`. + * + * var tea; + * assert.isUndefined(tea, 'no tea defined'); + * + * @name isUndefined + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isUndefined = function (val, msg) { + new Assertion(val, msg).to.equal(undefined); + }; + + /** + * ### .isDefined(value, [message]) + * + * Asserts that `value` is not `undefined`. + * + * var tea = 'cup of chai'; + * assert.isDefined(tea, 'tea has been defined'); + * + * @name isDefined + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isDefined = function (val, msg) { + new Assertion(val, msg).to.not.equal(undefined); + }; + + /** + * ### .isFunction(value, [message]) + * + * Asserts that `value` is a function. + * + * function serveTea() { return 'cup of tea'; }; + * assert.isFunction(serveTea, 'great, we can have tea now'); + * + * @name isFunction + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isFunction = function (val, msg) { + new Assertion(val, msg).to.be.a('function'); + }; + + /** + * ### .isNotFunction(value, [message]) + * + * Asserts that `value` is _not_ a function. + * + * var serveTea = [ 'heat', 'pour', 'sip' ]; + * assert.isNotFunction(serveTea, 'great, we have listed the steps'); + * + * @name isNotFunction + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isNotFunction = function (val, msg) { + new Assertion(val, msg).to.not.be.a('function'); + }; + + /** + * ### .isObject(value, [message]) + * + * Asserts that `value` is an object of type 'Object' (as revealed by `Object.prototype.toString`). + * _The assertion does not match subclassed objects._ + * + * var selection = { name: 'Chai', serve: 'with spices' }; + * assert.isObject(selection, 'tea selection is an object'); + * + * @name isObject + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isObject = function (val, msg) { + new Assertion(val, msg).to.be.a('object'); + }; + + /** + * ### .isNotObject(value, [message]) + * + * Asserts that `value` is _not_ an object of type 'Object' (as revealed by `Object.prototype.toString`). + * + * var selection = 'chai' + * assert.isNotObject(selection, 'tea selection is not an object'); + * assert.isNotObject(null, 'null is not an object'); + * + * @name isNotObject + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isNotObject = function (val, msg) { + new Assertion(val, msg).to.not.be.a('object'); + }; + + /** + * ### .isArray(value, [message]) + * + * Asserts that `value` is an array. + * + * var menu = [ 'green', 'chai', 'oolong' ]; + * assert.isArray(menu, 'what kind of tea do we want?'); + * + * @name isArray + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isArray = function (val, msg) { + new Assertion(val, msg).to.be.an('array'); + }; + + /** + * ### .isNotArray(value, [message]) + * + * Asserts that `value` is _not_ an array. + * + * var menu = 'green|chai|oolong'; + * assert.isNotArray(menu, 'what kind of tea do we want?'); + * + * @name isNotArray + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isNotArray = function (val, msg) { + new Assertion(val, msg).to.not.be.an('array'); + }; + + /** + * ### .isString(value, [message]) + * + * Asserts that `value` is a string. + * + * var teaOrder = 'chai'; + * assert.isString(teaOrder, 'order placed'); + * + * @name isString + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isString = function (val, msg) { + new Assertion(val, msg).to.be.a('string'); + }; + + /** + * ### .isNotString(value, [message]) + * + * Asserts that `value` is _not_ a string. + * + * var teaOrder = 4; + * assert.isNotString(teaOrder, 'order placed'); + * + * @name isNotString + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isNotString = function (val, msg) { + new Assertion(val, msg).to.not.be.a('string'); + }; + + /** + * ### .isNumber(value, [message]) + * + * Asserts that `value` is a number. + * + * var cups = 2; + * assert.isNumber(cups, 'how many cups'); + * + * @name isNumber + * @param {Number} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isNumber = function (val, msg) { + new Assertion(val, msg).to.be.a('number'); + }; + + /** + * ### .isNotNumber(value, [message]) + * + * Asserts that `value` is _not_ a number. + * + * var cups = '2 cups please'; + * assert.isNotNumber(cups, 'how many cups'); + * + * @name isNotNumber + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isNotNumber = function (val, msg) { + new Assertion(val, msg).to.not.be.a('number'); + }; + + /** + * ### .isBoolean(value, [message]) + * + * Asserts that `value` is a boolean. + * + * var teaReady = true + * , teaServed = false; + * + * assert.isBoolean(teaReady, 'is the tea ready'); + * assert.isBoolean(teaServed, 'has tea been served'); + * + * @name isBoolean + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isBoolean = function (val, msg) { + new Assertion(val, msg).to.be.a('boolean'); + }; + + /** + * ### .isNotBoolean(value, [message]) + * + * Asserts that `value` is _not_ a boolean. + * + * var teaReady = 'yep' + * , teaServed = 'nope'; + * + * assert.isNotBoolean(teaReady, 'is the tea ready'); + * assert.isNotBoolean(teaServed, 'has tea been served'); + * + * @name isNotBoolean + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isNotBoolean = function (val, msg) { + new Assertion(val, msg).to.not.be.a('boolean'); + }; + + /** + * ### .typeOf(value, name, [message]) + * + * Asserts that `value`'s type is `name`, as determined by + * `Object.prototype.toString`. + * + * assert.typeOf({ tea: 'chai' }, 'object', 'we have an object'); + * assert.typeOf(['chai', 'jasmine'], 'array', 'we have an array'); + * assert.typeOf('tea', 'string', 'we have a string'); + * assert.typeOf(/tea/, 'regexp', 'we have a regular expression'); + * assert.typeOf(null, 'null', 'we have a null'); + * assert.typeOf(undefined, 'undefined', 'we have an undefined'); + * + * @name typeOf + * @param {Mixed} value + * @param {String} name + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.typeOf = function (val, type, msg) { + new Assertion(val, msg).to.be.a(type); + }; + + /** + * ### .notTypeOf(value, name, [message]) + * + * Asserts that `value`'s type is _not_ `name`, as determined by + * `Object.prototype.toString`. + * + * assert.notTypeOf('tea', 'number', 'strings are not numbers'); + * + * @name notTypeOf + * @param {Mixed} value + * @param {String} typeof name + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.notTypeOf = function (val, type, msg) { + new Assertion(val, msg).to.not.be.a(type); + }; + + /** + * ### .instanceOf(object, constructor, [message]) + * + * Asserts that `value` is an instance of `constructor`. + * + * var Tea = function (name) { this.name = name; } + * , chai = new Tea('chai'); + * + * assert.instanceOf(chai, Tea, 'chai is an instance of tea'); + * + * @name instanceOf + * @param {Object} object + * @param {Constructor} constructor + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.instanceOf = function (val, type, msg) { + new Assertion(val, msg).to.be.instanceOf(type); + }; + + /** + * ### .notInstanceOf(object, constructor, [message]) + * + * Asserts `value` is not an instance of `constructor`. + * + * var Tea = function (name) { this.name = name; } + * , chai = new String('chai'); + * + * assert.notInstanceOf(chai, Tea, 'chai is not an instance of tea'); + * + * @name notInstanceOf + * @param {Object} object + * @param {Constructor} constructor + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.notInstanceOf = function (val, type, msg) { + new Assertion(val, msg).to.not.be.instanceOf(type); + }; + + /** + * ### .include(haystack, needle, [message]) + * + * Asserts that `haystack` includes `needle`. Works + * for strings and arrays. + * + * assert.include('foobar', 'bar', 'foobar contains string "bar"'); + * assert.include([ 1, 2, 3 ], 3, 'array contains value'); + * + * @name include + * @param {Array|String} haystack + * @param {Mixed} needle + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.include = function (exp, inc, msg) { + new Assertion(exp, msg, assert.include).include(inc); + }; + + /** + * ### .notInclude(haystack, needle, [message]) + * + * Asserts that `haystack` does not include `needle`. Works + * for strings and arrays. + * + * assert.notInclude('foobar', 'baz', 'string not include substring'); + * assert.notInclude([ 1, 2, 3 ], 4, 'array not include contain value'); + * + * @name notInclude + * @param {Array|String} haystack + * @param {Mixed} needle + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.notInclude = function (exp, inc, msg) { + new Assertion(exp, msg, assert.notInclude).not.include(inc); + }; + + /** + * ### .match(value, regexp, [message]) + * + * Asserts that `value` matches the regular expression `regexp`. + * + * assert.match('foobar', /^foo/, 'regexp matches'); + * + * @name match + * @param {Mixed} value + * @param {RegExp} regexp + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.match = function (exp, re, msg) { + new Assertion(exp, msg).to.match(re); + }; + + /** + * ### .notMatch(value, regexp, [message]) + * + * Asserts that `value` does not match the regular expression `regexp`. + * + * assert.notMatch('foobar', /^foo/, 'regexp does not match'); + * + * @name notMatch + * @param {Mixed} value + * @param {RegExp} regexp + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.notMatch = function (exp, re, msg) { + new Assertion(exp, msg).to.not.match(re); + }; + + /** + * ### .property(object, property, [message]) + * + * Asserts that `object` has a property named by `property`. + * + * assert.property({ tea: { green: 'matcha' }}, 'tea'); + * + * @name property + * @param {Object} object + * @param {String} property + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.property = function (obj, prop, msg) { + new Assertion(obj, msg).to.have.property(prop); + }; + + /** + * ### .notProperty(object, property, [message]) + * + * Asserts that `object` does _not_ have a property named by `property`. + * + * assert.notProperty({ tea: { green: 'matcha' }}, 'coffee'); + * + * @name notProperty + * @param {Object} object + * @param {String} property + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.notProperty = function (obj, prop, msg) { + new Assertion(obj, msg).to.not.have.property(prop); + }; + + /** + * ### .deepProperty(object, property, [message]) + * + * Asserts that `object` has a property named by `property`, which can be a + * string using dot- and bracket-notation for deep reference. + * + * assert.deepProperty({ tea: { green: 'matcha' }}, 'tea.green'); + * + * @name deepProperty + * @param {Object} object + * @param {String} property + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.deepProperty = function (obj, prop, msg) { + new Assertion(obj, msg).to.have.deep.property(prop); + }; + + /** + * ### .notDeepProperty(object, property, [message]) + * + * Asserts that `object` does _not_ have a property named by `property`, which + * can be a string using dot- and bracket-notation for deep reference. + * + * assert.notDeepProperty({ tea: { green: 'matcha' }}, 'tea.oolong'); + * + * @name notDeepProperty + * @param {Object} object + * @param {String} property + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.notDeepProperty = function (obj, prop, msg) { + new Assertion(obj, msg).to.not.have.deep.property(prop); + }; + + /** + * ### .propertyVal(object, property, value, [message]) + * + * Asserts that `object` has a property named by `property` with value given + * by `value`. + * + * assert.propertyVal({ tea: 'is good' }, 'tea', 'is good'); + * + * @name propertyVal + * @param {Object} object + * @param {String} property + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.propertyVal = function (obj, prop, val, msg) { + new Assertion(obj, msg).to.have.property(prop, val); + }; + + /** + * ### .propertyNotVal(object, property, value, [message]) + * + * Asserts that `object` has a property named by `property`, but with a value + * different from that given by `value`. + * + * assert.propertyNotVal({ tea: 'is good' }, 'tea', 'is bad'); + * + * @name propertyNotVal + * @param {Object} object + * @param {String} property + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.propertyNotVal = function (obj, prop, val, msg) { + new Assertion(obj, msg).to.not.have.property(prop, val); + }; + + /** + * ### .deepPropertyVal(object, property, value, [message]) + * + * Asserts that `object` has a property named by `property` with value given + * by `value`. `property` can use dot- and bracket-notation for deep + * reference. + * + * assert.deepPropertyVal({ tea: { green: 'matcha' }}, 'tea.green', 'matcha'); + * + * @name deepPropertyVal + * @param {Object} object + * @param {String} property + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.deepPropertyVal = function (obj, prop, val, msg) { + new Assertion(obj, msg).to.have.deep.property(prop, val); + }; + + /** + * ### .deepPropertyNotVal(object, property, value, [message]) + * + * Asserts that `object` has a property named by `property`, but with a value + * different from that given by `value`. `property` can use dot- and + * bracket-notation for deep reference. + * + * assert.deepPropertyNotVal({ tea: { green: 'matcha' }}, 'tea.green', 'konacha'); + * + * @name deepPropertyNotVal + * @param {Object} object + * @param {String} property + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.deepPropertyNotVal = function (obj, prop, val, msg) { + new Assertion(obj, msg).to.not.have.deep.property(prop, val); + }; + + /** + * ### .lengthOf(object, length, [message]) + * + * Asserts that `object` has a `length` property with the expected value. + * + * assert.lengthOf([1,2,3], 3, 'array has length of 3'); + * assert.lengthOf('foobar', 6, 'string has length of 6'); + * + * @name lengthOf + * @param {Mixed} object + * @param {Number} length + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.lengthOf = function (exp, len, msg) { + new Assertion(exp, msg).to.have.length(len); + }; + + /** + * ### .throws(function, [constructor/string/regexp], [string/regexp], [message]) + * + * Asserts that `function` will throw an error that is an instance of + * `constructor`, or alternately that it will throw an error with message + * matching `regexp`. + * + * assert.throws(fn, 'function throws a reference error'); + * assert.throws(fn, /function throws a reference error/); + * assert.throws(fn, ReferenceError); + * assert.throws(fn, ReferenceError, 'function throws a reference error'); + * assert.throws(fn, ReferenceError, /function throws a reference error/); + * + * @name throws + * @alias throw + * @alias Throw + * @param {Function} function + * @param {ErrorConstructor} constructor + * @param {RegExp} regexp + * @param {String} message + * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types + * @namespace Assert + * @api public + */ + + assert.throws = function (fn, errt, errs, msg) { + if ('string' === typeof errt || errt instanceof RegExp) { + errs = errt; + errt = null; + } + + var assertErr = new Assertion(fn, msg).to.throw(errt, errs); + return flag(assertErr, 'object'); + }; + + /** + * ### .doesNotThrow(function, [constructor/regexp], [message]) + * + * Asserts that `function` will _not_ throw an error that is an instance of + * `constructor`, or alternately that it will not throw an error with message + * matching `regexp`. + * + * assert.doesNotThrow(fn, Error, 'function does not throw'); + * + * @name doesNotThrow + * @param {Function} function + * @param {ErrorConstructor} constructor + * @param {RegExp} regexp + * @param {String} message + * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types + * @namespace Assert + * @api public + */ + + assert.doesNotThrow = function (fn, type, msg) { + if ('string' === typeof type) { + msg = type; + type = null; + } + + new Assertion(fn, msg).to.not.Throw(type); + }; + + /** + * ### .operator(val1, operator, val2, [message]) + * + * Compares two values using `operator`. + * + * assert.operator(1, '<', 2, 'everything is ok'); + * assert.operator(1, '>', 2, 'this will fail'); + * + * @name operator + * @param {Mixed} val1 + * @param {String} operator + * @param {Mixed} val2 + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.operator = function (val, operator, val2, msg) { + var ok; + switch(operator) { + case '==': + ok = val == val2; + break; + case '===': + ok = val === val2; + break; + case '>': + ok = val > val2; + break; + case '>=': + ok = val >= val2; + break; + case '<': + ok = val < val2; + break; + case '<=': + ok = val <= val2; + break; + case '!=': + ok = val != val2; + break; + case '!==': + ok = val !== val2; + break; + default: + throw new Error('Invalid operator "' + operator + '"'); + } + var test = new Assertion(ok, msg); + test.assert( + true === flag(test, 'object') + , 'expected ' + util.inspect(val) + ' to be ' + operator + ' ' + util.inspect(val2) + , 'expected ' + util.inspect(val) + ' to not be ' + operator + ' ' + util.inspect(val2) ); + }; + + /** + * ### .closeTo(actual, expected, delta, [message]) + * + * Asserts that the target is equal `expected`, to within a +/- `delta` range. + * + * assert.closeTo(1.5, 1, 0.5, 'numbers are close'); + * + * @name closeTo + * @param {Number} actual + * @param {Number} expected + * @param {Number} delta + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.closeTo = function (act, exp, delta, msg) { + new Assertion(act, msg).to.be.closeTo(exp, delta); + }; + + /** + * ### .approximately(actual, expected, delta, [message]) + * + * Asserts that the target is equal `expected`, to within a +/- `delta` range. + * + * assert.approximately(1.5, 1, 0.5, 'numbers are close'); + * + * @name approximately + * @param {Number} actual + * @param {Number} expected + * @param {Number} delta + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.approximately = function (act, exp, delta, msg) { + new Assertion(act, msg).to.be.approximately(exp, delta); + }; + + /** + * ### .sameMembers(set1, set2, [message]) + * + * Asserts that `set1` and `set2` have the same members. + * Order is not taken into account. + * + * assert.sameMembers([ 1, 2, 3 ], [ 2, 1, 3 ], 'same members'); + * + * @name sameMembers + * @param {Array} set1 + * @param {Array} set2 + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.sameMembers = function (set1, set2, msg) { + new Assertion(set1, msg).to.have.same.members(set2); + } + + /** + * ### .sameDeepMembers(set1, set2, [message]) + * + * Asserts that `set1` and `set2` have the same members - using a deep equality checking. + * Order is not taken into account. + * + * assert.sameDeepMembers([ {b: 3}, {a: 2}, {c: 5} ], [ {c: 5}, {b: 3}, {a: 2} ], 'same deep members'); + * + * @name sameDeepMembers + * @param {Array} set1 + * @param {Array} set2 + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.sameDeepMembers = function (set1, set2, msg) { + new Assertion(set1, msg).to.have.same.deep.members(set2); + } + + /** + * ### .includeMembers(superset, subset, [message]) + * + * Asserts that `subset` is included in `superset`. + * Order is not taken into account. + * + * assert.includeMembers([ 1, 2, 3 ], [ 2, 1 ], 'include members'); + * + * @name includeMembers + * @param {Array} superset + * @param {Array} subset + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.includeMembers = function (superset, subset, msg) { + new Assertion(superset, msg).to.include.members(subset); + } + + /** + * ### .includeDeepMembers(superset, subset, [message]) + * + * Asserts that `subset` is included in `superset` - using deep equality checking. + * Order is not taken into account. + * Duplicates are ignored. + * + * assert.includeDeepMembers([ {a: 1}, {b: 2}, {c: 3} ], [ {b: 2}, {a: 1}, {b: 2} ], 'include deep members'); + * + * @name includeDeepMembers + * @param {Array} superset + * @param {Array} subset + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.includeDeepMembers = function (superset, subset, msg) { + new Assertion(superset, msg).to.include.deep.members(subset); + } + + /** + * ### .oneOf(inList, list, [message]) + * + * Asserts that non-object, non-array value `inList` appears in the flat array `list`. + * + * assert.oneOf(1, [ 2, 1 ], 'Not found in list'); + * + * @name oneOf + * @param {*} inList + * @param {Array<*>} list + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.oneOf = function (inList, list, msg) { + new Assertion(inList, msg).to.be.oneOf(list); + } + + /** + * ### .changes(function, object, property) + * + * Asserts that a function changes the value of a property + * + * var obj = { val: 10 }; + * var fn = function() { obj.val = 22 }; + * assert.changes(fn, obj, 'val'); + * + * @name changes + * @param {Function} modifier function + * @param {Object} object + * @param {String} property name + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.changes = function (fn, obj, prop) { + new Assertion(fn).to.change(obj, prop); + } + + /** + * ### .doesNotChange(function, object, property) + * + * Asserts that a function does not changes the value of a property + * + * var obj = { val: 10 }; + * var fn = function() { console.log('foo'); }; + * assert.doesNotChange(fn, obj, 'val'); + * + * @name doesNotChange + * @param {Function} modifier function + * @param {Object} object + * @param {String} property name + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.doesNotChange = function (fn, obj, prop) { + new Assertion(fn).to.not.change(obj, prop); + } + + /** + * ### .increases(function, object, property) + * + * Asserts that a function increases an object property + * + * var obj = { val: 10 }; + * var fn = function() { obj.val = 13 }; + * assert.increases(fn, obj, 'val'); + * + * @name increases + * @param {Function} modifier function + * @param {Object} object + * @param {String} property name + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.increases = function (fn, obj, prop) { + new Assertion(fn).to.increase(obj, prop); + } + + /** + * ### .doesNotIncrease(function, object, property) + * + * Asserts that a function does not increase object property + * + * var obj = { val: 10 }; + * var fn = function() { obj.val = 8 }; + * assert.doesNotIncrease(fn, obj, 'val'); + * + * @name doesNotIncrease + * @param {Function} modifier function + * @param {Object} object + * @param {String} property name + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.doesNotIncrease = function (fn, obj, prop) { + new Assertion(fn).to.not.increase(obj, prop); + } + + /** + * ### .decreases(function, object, property) + * + * Asserts that a function decreases an object property + * + * var obj = { val: 10 }; + * var fn = function() { obj.val = 5 }; + * assert.decreases(fn, obj, 'val'); + * + * @name decreases + * @param {Function} modifier function + * @param {Object} object + * @param {String} property name + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.decreases = function (fn, obj, prop) { + new Assertion(fn).to.decrease(obj, prop); + } + + /** + * ### .doesNotDecrease(function, object, property) + * + * Asserts that a function does not decreases an object property + * + * var obj = { val: 10 }; + * var fn = function() { obj.val = 15 }; + * assert.doesNotDecrease(fn, obj, 'val'); + * + * @name doesNotDecrease + * @param {Function} modifier function + * @param {Object} object + * @param {String} property name + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.doesNotDecrease = function (fn, obj, prop) { + new Assertion(fn).to.not.decrease(obj, prop); + } + + /*! + * ### .ifError(object) + * + * Asserts if value is not a false value, and throws if it is a true value. + * This is added to allow for chai to be a drop-in replacement for Node's + * assert class. + * + * var err = new Error('I am a custom error'); + * assert.ifError(err); // Rethrows err! + * + * @name ifError + * @param {Object} object + * @namespace Assert + * @api public + */ + + assert.ifError = function (val) { + if (val) { + throw(val); + } + }; + + /** + * ### .isExtensible(object) + * + * Asserts that `object` is extensible (can have new properties added to it). + * + * assert.isExtensible({}); + * + * @name isExtensible + * @alias extensible + * @param {Object} object + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.isExtensible = function (obj, msg) { + new Assertion(obj, msg).to.be.extensible; + }; + + /** + * ### .isNotExtensible(object) + * + * Asserts that `object` is _not_ extensible. + * + * var nonExtensibleObject = Object.preventExtensions({}); + * var sealedObject = Object.seal({}); + * var frozenObject = Object.freese({}); + * + * assert.isNotExtensible(nonExtensibleObject); + * assert.isNotExtensible(sealedObject); + * assert.isNotExtensible(frozenObject); + * + * @name isNotExtensible + * @alias notExtensible + * @param {Object} object + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.isNotExtensible = function (obj, msg) { + new Assertion(obj, msg).to.not.be.extensible; + }; + + /** + * ### .isSealed(object) + * + * Asserts that `object` is sealed (cannot have new properties added to it + * and its existing properties cannot be removed). + * + * var sealedObject = Object.seal({}); + * var frozenObject = Object.seal({}); + * + * assert.isSealed(sealedObject); + * assert.isSealed(frozenObject); + * + * @name isSealed + * @alias sealed + * @param {Object} object + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.isSealed = function (obj, msg) { + new Assertion(obj, msg).to.be.sealed; + }; + + /** + * ### .isNotSealed(object) + * + * Asserts that `object` is _not_ sealed. + * + * assert.isNotSealed({}); + * + * @name isNotSealed + * @alias notSealed + * @param {Object} object + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.isNotSealed = function (obj, msg) { + new Assertion(obj, msg).to.not.be.sealed; + }; + + /** + * ### .isFrozen(object) + * + * Asserts that `object` is frozen (cannot have new properties added to it + * and its existing properties cannot be modified). + * + * var frozenObject = Object.freeze({}); + * assert.frozen(frozenObject); + * + * @name isFrozen + * @alias frozen + * @param {Object} object + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.isFrozen = function (obj, msg) { + new Assertion(obj, msg).to.be.frozen; + }; + + /** + * ### .isNotFrozen(object) + * + * Asserts that `object` is _not_ frozen. + * + * assert.isNotFrozen({}); + * + * @name isNotFrozen + * @alias notFrozen + * @param {Object} object + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.isNotFrozen = function (obj, msg) { + new Assertion(obj, msg).to.not.be.frozen; + }; + + /*! + * Aliases. + */ + + (function alias(name, as){ + assert[as] = assert[name]; + return alias; + }) + ('isOk', 'ok') + ('isNotOk', 'notOk') + ('throws', 'throw') + ('throws', 'Throw') + ('isExtensible', 'extensible') + ('isNotExtensible', 'notExtensible') + ('isSealed', 'sealed') + ('isNotSealed', 'notSealed') + ('isFrozen', 'frozen') + ('isNotFrozen', 'notFrozen'); +}; + +},{}],10:[function(require,module,exports){ +/*! + * chai + * Copyright(c) 2011-2014 Jake Luer + * MIT Licensed + */ + +module.exports = function (chai, util) { + chai.expect = function (val, message) { + return new chai.Assertion(val, message); + }; + + /** + * ### .fail(actual, expected, [message], [operator]) + * + * Throw a failure. + * + * @name fail + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @param {String} operator + * @namespace Expect + * @api public + */ + + chai.expect.fail = function (actual, expected, message, operator) { + message = message || 'expect.fail()'; + throw new chai.AssertionError(message, { + actual: actual + , expected: expected + , operator: operator + }, chai.expect.fail); + }; +}; + +},{}],11:[function(require,module,exports){ +/*! + * chai + * Copyright(c) 2011-2014 Jake Luer + * MIT Licensed + */ + +module.exports = function (chai, util) { + var Assertion = chai.Assertion; + + function loadShould () { + // explicitly define this method as function as to have it's name to include as `ssfi` + function shouldGetter() { + if (this instanceof String || this instanceof Number || this instanceof Boolean ) { + return new Assertion(this.valueOf(), null, shouldGetter); + } + return new Assertion(this, null, shouldGetter); + } + function shouldSetter(value) { + // See https://github.com/chaijs/chai/issues/86: this makes + // `whatever.should = someValue` actually set `someValue`, which is + // especially useful for `global.should = require('chai').should()`. + // + // Note that we have to use [[DefineProperty]] instead of [[Put]] + // since otherwise we would trigger this very setter! + Object.defineProperty(this, 'should', { + value: value, + enumerable: true, + configurable: true, + writable: true + }); + } + // modify Object.prototype to have `should` + Object.defineProperty(Object.prototype, 'should', { + set: shouldSetter + , get: shouldGetter + , configurable: true + }); + + var should = {}; + + /** + * ### .fail(actual, expected, [message], [operator]) + * + * Throw a failure. + * + * @name fail + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @param {String} operator + * @namespace Should + * @api public + */ + + should.fail = function (actual, expected, message, operator) { + message = message || 'should.fail()'; + throw new chai.AssertionError(message, { + actual: actual + , expected: expected + , operator: operator + }, should.fail); + }; + + /** + * ### .equal(actual, expected, [message]) + * + * Asserts non-strict equality (`==`) of `actual` and `expected`. + * + * should.equal(3, '3', '== coerces values to strings'); + * + * @name equal + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @namespace Should + * @api public + */ + + should.equal = function (val1, val2, msg) { + new Assertion(val1, msg).to.equal(val2); + }; + + /** + * ### .throw(function, [constructor/string/regexp], [string/regexp], [message]) + * + * Asserts that `function` will throw an error that is an instance of + * `constructor`, or alternately that it will throw an error with message + * matching `regexp`. + * + * should.throw(fn, 'function throws a reference error'); + * should.throw(fn, /function throws a reference error/); + * should.throw(fn, ReferenceError); + * should.throw(fn, ReferenceError, 'function throws a reference error'); + * should.throw(fn, ReferenceError, /function throws a reference error/); + * + * @name throw + * @alias Throw + * @param {Function} function + * @param {ErrorConstructor} constructor + * @param {RegExp} regexp + * @param {String} message + * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types + * @namespace Should + * @api public + */ + + should.Throw = function (fn, errt, errs, msg) { + new Assertion(fn, msg).to.Throw(errt, errs); + }; + + /** + * ### .exist + * + * Asserts that the target is neither `null` nor `undefined`. + * + * var foo = 'hi'; + * + * should.exist(foo, 'foo exists'); + * + * @name exist + * @namespace Should + * @api public + */ + + should.exist = function (val, msg) { + new Assertion(val, msg).to.exist; + } + + // negation + should.not = {} + + /** + * ### .not.equal(actual, expected, [message]) + * + * Asserts non-strict inequality (`!=`) of `actual` and `expected`. + * + * should.not.equal(3, 4, 'these numbers are not equal'); + * + * @name not.equal + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @namespace Should + * @api public + */ + + should.not.equal = function (val1, val2, msg) { + new Assertion(val1, msg).to.not.equal(val2); + }; + + /** + * ### .throw(function, [constructor/regexp], [message]) + * + * Asserts that `function` will _not_ throw an error that is an instance of + * `constructor`, or alternately that it will not throw an error with message + * matching `regexp`. + * + * should.not.throw(fn, Error, 'function does not throw'); + * + * @name not.throw + * @alias not.Throw + * @param {Function} function + * @param {ErrorConstructor} constructor + * @param {RegExp} regexp + * @param {String} message + * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types + * @namespace Should + * @api public + */ + + should.not.Throw = function (fn, errt, errs, msg) { + new Assertion(fn, msg).to.not.Throw(errt, errs); + }; + + /** + * ### .not.exist + * + * Asserts that the target is neither `null` nor `undefined`. + * + * var bar = null; + * + * should.not.exist(bar, 'bar does not exist'); + * + * @name not.exist + * @namespace Should + * @api public + */ + + should.not.exist = function (val, msg) { + new Assertion(val, msg).to.not.exist; + } + + should['throw'] = should['Throw']; + should.not['throw'] = should.not['Throw']; + + return should; + }; + + chai.should = loadShould; + chai.Should = loadShould; +}; + +},{}],12:[function(require,module,exports){ +/*! + * Chai - addChainingMethod utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/*! + * Module dependencies + */ + +var transferFlags = require('./transferFlags'); +var flag = require('./flag'); +var config = require('../config'); + +/*! + * Module variables + */ + +// Check whether `__proto__` is supported +var hasProtoSupport = '__proto__' in Object; + +// Without `__proto__` support, this module will need to add properties to a function. +// However, some Function.prototype methods cannot be overwritten, +// and there seems no easy cross-platform way to detect them (@see chaijs/chai/issues/69). +var excludeNames = /^(?:length|name|arguments|caller)$/; + +// Cache `Function` properties +var call = Function.prototype.call, + apply = Function.prototype.apply; + +/** + * ### addChainableMethod (ctx, name, method, chainingBehavior) + * + * Adds a method to an object, such that the method can also be chained. + * + * utils.addChainableMethod(chai.Assertion.prototype, 'foo', function (str) { + * var obj = utils.flag(this, 'object'); + * new chai.Assertion(obj).to.be.equal(str); + * }); + * + * Can also be accessed directly from `chai.Assertion`. + * + * chai.Assertion.addChainableMethod('foo', fn, chainingBehavior); + * + * The result can then be used as both a method assertion, executing both `method` and + * `chainingBehavior`, or as a language chain, which only executes `chainingBehavior`. + * + * expect(fooStr).to.be.foo('bar'); + * expect(fooStr).to.be.foo.equal('foo'); + * + * @param {Object} ctx object to which the method is added + * @param {String} name of method to add + * @param {Function} method function to be used for `name`, when called + * @param {Function} chainingBehavior function to be called every time the property is accessed + * @namespace Utils + * @name addChainableMethod + * @api public + */ + +module.exports = function (ctx, name, method, chainingBehavior) { + if (typeof chainingBehavior !== 'function') { + chainingBehavior = function () { }; + } + + var chainableBehavior = { + method: method + , chainingBehavior: chainingBehavior + }; + + // save the methods so we can overwrite them later, if we need to. + if (!ctx.__methods) { + ctx.__methods = {}; + } + ctx.__methods[name] = chainableBehavior; + + Object.defineProperty(ctx, name, + { get: function () { + chainableBehavior.chainingBehavior.call(this); + + var assert = function assert() { + var old_ssfi = flag(this, 'ssfi'); + if (old_ssfi && config.includeStack === false) + flag(this, 'ssfi', assert); + var result = chainableBehavior.method.apply(this, arguments); + return result === undefined ? this : result; + }; + + // Use `__proto__` if available + if (hasProtoSupport) { + // Inherit all properties from the object by replacing the `Function` prototype + var prototype = assert.__proto__ = Object.create(this); + // Restore the `call` and `apply` methods from `Function` + prototype.call = call; + prototype.apply = apply; + } + // Otherwise, redefine all properties (slow!) + else { + var asserterNames = Object.getOwnPropertyNames(ctx); + asserterNames.forEach(function (asserterName) { + if (!excludeNames.test(asserterName)) { + var pd = Object.getOwnPropertyDescriptor(ctx, asserterName); + Object.defineProperty(assert, asserterName, pd); + } + }); + } + + transferFlags(this, assert); + return assert; + } + , configurable: true + }); +}; + +},{"../config":7,"./flag":16,"./transferFlags":32}],13:[function(require,module,exports){ +/*! + * Chai - addMethod utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +var config = require('../config'); + +/** + * ### .addMethod (ctx, name, method) + * + * Adds a method to the prototype of an object. + * + * utils.addMethod(chai.Assertion.prototype, 'foo', function (str) { + * var obj = utils.flag(this, 'object'); + * new chai.Assertion(obj).to.be.equal(str); + * }); + * + * Can also be accessed directly from `chai.Assertion`. + * + * chai.Assertion.addMethod('foo', fn); + * + * Then can be used as any other assertion. + * + * expect(fooStr).to.be.foo('bar'); + * + * @param {Object} ctx object to which the method is added + * @param {String} name of method to add + * @param {Function} method function to be used for name + * @namespace Utils + * @name addMethod + * @api public + */ +var flag = require('./flag'); + +module.exports = function (ctx, name, method) { + ctx[name] = function () { + var old_ssfi = flag(this, 'ssfi'); + if (old_ssfi && config.includeStack === false) + flag(this, 'ssfi', ctx[name]); + var result = method.apply(this, arguments); + return result === undefined ? this : result; + }; +}; + +},{"../config":7,"./flag":16}],14:[function(require,module,exports){ +/*! + * Chai - addProperty utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +var config = require('../config'); +var flag = require('./flag'); + +/** + * ### addProperty (ctx, name, getter) + * + * Adds a property to the prototype of an object. + * + * utils.addProperty(chai.Assertion.prototype, 'foo', function () { + * var obj = utils.flag(this, 'object'); + * new chai.Assertion(obj).to.be.instanceof(Foo); + * }); + * + * Can also be accessed directly from `chai.Assertion`. + * + * chai.Assertion.addProperty('foo', fn); + * + * Then can be used as any other assertion. + * + * expect(myFoo).to.be.foo; + * + * @param {Object} ctx object to which the property is added + * @param {String} name of property to add + * @param {Function} getter function to be used for name + * @namespace Utils + * @name addProperty + * @api public + */ + +module.exports = function (ctx, name, getter) { + Object.defineProperty(ctx, name, + { get: function addProperty() { + var old_ssfi = flag(this, 'ssfi'); + if (old_ssfi && config.includeStack === false) + flag(this, 'ssfi', addProperty); + + var result = getter.call(this); + return result === undefined ? this : result; + } + , configurable: true + }); +}; + +},{"../config":7,"./flag":16}],15:[function(require,module,exports){ +/*! + * Chai - expectTypes utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/** + * ### expectTypes(obj, types) + * + * Ensures that the object being tested against is of a valid type. + * + * utils.expectTypes(this, ['array', 'object', 'string']); + * + * @param {Mixed} obj constructed Assertion + * @param {Array} type A list of allowed types for this assertion + * @namespace Utils + * @name expectTypes + * @api public + */ + +var AssertionError = require('assertion-error'); +var flag = require('./flag'); +var type = require('type-detect'); + +module.exports = function (obj, types) { + var obj = flag(obj, 'object'); + types = types.map(function (t) { return t.toLowerCase(); }); + types.sort(); + + // Transforms ['lorem', 'ipsum'] into 'a lirum, or an ipsum' + var str = types.map(function (t, index) { + var art = ~[ 'a', 'e', 'i', 'o', 'u' ].indexOf(t.charAt(0)) ? 'an' : 'a'; + var or = types.length > 1 && index === types.length - 1 ? 'or ' : ''; + return or + art + ' ' + t; + }).join(', '); + + if (!types.some(function (expected) { return type(obj) === expected; })) { + throw new AssertionError( + 'object tested must be ' + str + ', but ' + type(obj) + ' given' + ); + } +}; + +},{"./flag":16,"assertion-error":1,"type-detect":39}],16:[function(require,module,exports){ +/*! + * Chai - flag utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/** + * ### flag(object, key, [value]) + * + * Get or set a flag value on an object. If a + * value is provided it will be set, else it will + * return the currently set value or `undefined` if + * the value is not set. + * + * utils.flag(this, 'foo', 'bar'); // setter + * utils.flag(this, 'foo'); // getter, returns `bar` + * + * @param {Object} object constructed Assertion + * @param {String} key + * @param {Mixed} value (optional) + * @namespace Utils + * @name flag + * @api private + */ + +module.exports = function (obj, key, value) { + var flags = obj.__flags || (obj.__flags = Object.create(null)); + if (arguments.length === 3) { + flags[key] = value; + } else { + return flags[key]; + } +}; + +},{}],17:[function(require,module,exports){ +/*! + * Chai - getActual utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/** + * # getActual(object, [actual]) + * + * Returns the `actual` value for an Assertion + * + * @param {Object} object (constructed Assertion) + * @param {Arguments} chai.Assertion.prototype.assert arguments + * @namespace Utils + * @name getActual + */ + +module.exports = function (obj, args) { + return args.length > 4 ? args[4] : obj._obj; +}; + +},{}],18:[function(require,module,exports){ +/*! + * Chai - getEnumerableProperties utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/** + * ### .getEnumerableProperties(object) + * + * This allows the retrieval of enumerable property names of an object, + * inherited or not. + * + * @param {Object} object + * @returns {Array} + * @namespace Utils + * @name getEnumerableProperties + * @api public + */ + +module.exports = function getEnumerableProperties(object) { + var result = []; + for (var name in object) { + result.push(name); + } + return result; +}; + +},{}],19:[function(require,module,exports){ +/*! + * Chai - message composition utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/*! + * Module dependancies + */ + +var flag = require('./flag') + , getActual = require('./getActual') + , inspect = require('./inspect') + , objDisplay = require('./objDisplay'); + +/** + * ### .getMessage(object, message, negateMessage) + * + * Construct the error message based on flags + * and template tags. Template tags will return + * a stringified inspection of the object referenced. + * + * Message template tags: + * - `#{this}` current asserted object + * - `#{act}` actual value + * - `#{exp}` expected value + * + * @param {Object} object (constructed Assertion) + * @param {Arguments} chai.Assertion.prototype.assert arguments + * @namespace Utils + * @name getMessage + * @api public + */ + +module.exports = function (obj, args) { + var negate = flag(obj, 'negate') + , val = flag(obj, 'object') + , expected = args[3] + , actual = getActual(obj, args) + , msg = negate ? args[2] : args[1] + , flagMsg = flag(obj, 'message'); + + if(typeof msg === "function") msg = msg(); + msg = msg || ''; + msg = msg + .replace(/#\{this\}/g, function () { return objDisplay(val); }) + .replace(/#\{act\}/g, function () { return objDisplay(actual); }) + .replace(/#\{exp\}/g, function () { return objDisplay(expected); }); + + return flagMsg ? flagMsg + ': ' + msg : msg; +}; + +},{"./flag":16,"./getActual":17,"./inspect":26,"./objDisplay":27}],20:[function(require,module,exports){ +/*! + * Chai - getName utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/** + * # getName(func) + * + * Gets the name of a function, in a cross-browser way. + * + * @param {Function} a function (usually a constructor) + * @namespace Utils + * @name getName + */ + +module.exports = function (func) { + if (func.name) return func.name; + + var match = /^\s?function ([^(]*)\(/.exec(func); + return match && match[1] ? match[1] : ""; +}; + +},{}],21:[function(require,module,exports){ +/*! + * Chai - getPathInfo utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +var hasProperty = require('./hasProperty'); + +/** + * ### .getPathInfo(path, object) + * + * This allows the retrieval of property info in an + * object given a string path. + * + * The path info consists of an object with the + * following properties: + * + * * parent - The parent object of the property referenced by `path` + * * name - The name of the final property, a number if it was an array indexer + * * value - The value of the property, if it exists, otherwise `undefined` + * * exists - Whether the property exists or not + * + * @param {String} path + * @param {Object} object + * @returns {Object} info + * @namespace Utils + * @name getPathInfo + * @api public + */ + +module.exports = function getPathInfo(path, obj) { + var parsed = parsePath(path), + last = parsed[parsed.length - 1]; + + var info = { + parent: parsed.length > 1 ? _getPathValue(parsed, obj, parsed.length - 1) : obj, + name: last.p || last.i, + value: _getPathValue(parsed, obj) + }; + info.exists = hasProperty(info.name, info.parent); + + return info; +}; + + +/*! + * ## parsePath(path) + * + * Helper function used to parse string object + * paths. Use in conjunction with `_getPathValue`. + * + * var parsed = parsePath('myobject.property.subprop'); + * + * ### Paths: + * + * * Can be as near infinitely deep and nested + * * Arrays are also valid using the formal `myobject.document[3].property`. + * * Literal dots and brackets (not delimiter) must be backslash-escaped. + * + * @param {String} path + * @returns {Object} parsed + * @api private + */ + +function parsePath (path) { + var str = path.replace(/([^\\])\[/g, '$1.[') + , parts = str.match(/(\\\.|[^.]+?)+/g); + return parts.map(function (value) { + var re = /^\[(\d+)\]$/ + , mArr = re.exec(value); + if (mArr) return { i: parseFloat(mArr[1]) }; + else return { p: value.replace(/\\([.\[\]])/g, '$1') }; + }); +} + + +/*! + * ## _getPathValue(parsed, obj) + * + * Helper companion function for `.parsePath` that returns + * the value located at the parsed address. + * + * var value = getPathValue(parsed, obj); + * + * @param {Object} parsed definition from `parsePath`. + * @param {Object} object to search against + * @param {Number} object to search against + * @returns {Object|Undefined} value + * @api private + */ + +function _getPathValue (parsed, obj, index) { + var tmp = obj + , res; + + index = (index === undefined ? parsed.length : index); + + for (var i = 0, l = index; i < l; i++) { + var part = parsed[i]; + if (tmp) { + if ('undefined' !== typeof part.p) + tmp = tmp[part.p]; + else if ('undefined' !== typeof part.i) + tmp = tmp[part.i]; + if (i == (l - 1)) res = tmp; + } else { + res = undefined; + } + } + return res; +} + +},{"./hasProperty":24}],22:[function(require,module,exports){ +/*! + * Chai - getPathValue utility + * Copyright(c) 2012-2014 Jake Luer + * @see https://github.com/logicalparadox/filtr + * MIT Licensed + */ + +var getPathInfo = require('./getPathInfo'); + +/** + * ### .getPathValue(path, object) + * + * This allows the retrieval of values in an + * object given a string path. + * + * var obj = { + * prop1: { + * arr: ['a', 'b', 'c'] + * , str: 'Hello' + * } + * , prop2: { + * arr: [ { nested: 'Universe' } ] + * , str: 'Hello again!' + * } + * } + * + * The following would be the results. + * + * getPathValue('prop1.str', obj); // Hello + * getPathValue('prop1.att[2]', obj); // b + * getPathValue('prop2.arr[0].nested', obj); // Universe + * + * @param {String} path + * @param {Object} object + * @returns {Object} value or `undefined` + * @namespace Utils + * @name getPathValue + * @api public + */ +module.exports = function(path, obj) { + var info = getPathInfo(path, obj); + return info.value; +}; + +},{"./getPathInfo":21}],23:[function(require,module,exports){ +/*! + * Chai - getProperties utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/** + * ### .getProperties(object) + * + * This allows the retrieval of property names of an object, enumerable or not, + * inherited or not. + * + * @param {Object} object + * @returns {Array} + * @namespace Utils + * @name getProperties + * @api public + */ + +module.exports = function getProperties(object) { + var result = Object.getOwnPropertyNames(object); + + function addProperty(property) { + if (result.indexOf(property) === -1) { + result.push(property); + } + } + + var proto = Object.getPrototypeOf(object); + while (proto !== null) { + Object.getOwnPropertyNames(proto).forEach(addProperty); + proto = Object.getPrototypeOf(proto); + } + + return result; +}; + +},{}],24:[function(require,module,exports){ +/*! + * Chai - hasProperty utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +var type = require('type-detect'); + +/** + * ### .hasProperty(object, name) + * + * This allows checking whether an object has + * named property or numeric array index. + * + * Basically does the same thing as the `in` + * operator but works properly with natives + * and null/undefined values. + * + * var obj = { + * arr: ['a', 'b', 'c'] + * , str: 'Hello' + * } + * + * The following would be the results. + * + * hasProperty('str', obj); // true + * hasProperty('constructor', obj); // true + * hasProperty('bar', obj); // false + * + * hasProperty('length', obj.str); // true + * hasProperty(1, obj.str); // true + * hasProperty(5, obj.str); // false + * + * hasProperty('length', obj.arr); // true + * hasProperty(2, obj.arr); // true + * hasProperty(3, obj.arr); // false + * + * @param {Objuect} object + * @param {String|Number} name + * @returns {Boolean} whether it exists + * @namespace Utils + * @name getPathInfo + * @api public + */ + +var literals = { + 'number': Number + , 'string': String +}; + +module.exports = function hasProperty(name, obj) { + var ot = type(obj); + + // Bad Object, obviously no props at all + if(ot === 'null' || ot === 'undefined') + return false; + + // The `in` operator does not work with certain literals + // box these before the check + if(literals[ot] && typeof obj !== 'object') + obj = new literals[ot](obj); + + return name in obj; +}; + +},{"type-detect":39}],25:[function(require,module,exports){ +/*! + * chai + * Copyright(c) 2011 Jake Luer + * MIT Licensed + */ + +/*! + * Main exports + */ + +var exports = module.exports = {}; + +/*! + * test utility + */ + +exports.test = require('./test'); + +/*! + * type utility + */ + +exports.type = require('type-detect'); + +/*! + * expectTypes utility + */ +exports.expectTypes = require('./expectTypes'); + +/*! + * message utility + */ + +exports.getMessage = require('./getMessage'); + +/*! + * actual utility + */ + +exports.getActual = require('./getActual'); + +/*! + * Inspect util + */ + +exports.inspect = require('./inspect'); + +/*! + * Object Display util + */ + +exports.objDisplay = require('./objDisplay'); + +/*! + * Flag utility + */ + +exports.flag = require('./flag'); + +/*! + * Flag transferring utility + */ + +exports.transferFlags = require('./transferFlags'); + +/*! + * Deep equal utility + */ + +exports.eql = require('deep-eql'); + +/*! + * Deep path value + */ + +exports.getPathValue = require('./getPathValue'); + +/*! + * Deep path info + */ + +exports.getPathInfo = require('./getPathInfo'); + +/*! + * Check if a property exists + */ + +exports.hasProperty = require('./hasProperty'); + +/*! + * Function name + */ + +exports.getName = require('./getName'); + +/*! + * add Property + */ + +exports.addProperty = require('./addProperty'); + +/*! + * add Method + */ + +exports.addMethod = require('./addMethod'); + +/*! + * overwrite Property + */ + +exports.overwriteProperty = require('./overwriteProperty'); + +/*! + * overwrite Method + */ + +exports.overwriteMethod = require('./overwriteMethod'); + +/*! + * Add a chainable method + */ + +exports.addChainableMethod = require('./addChainableMethod'); + +/*! + * Overwrite chainable method + */ + +exports.overwriteChainableMethod = require('./overwriteChainableMethod'); + +},{"./addChainableMethod":12,"./addMethod":13,"./addProperty":14,"./expectTypes":15,"./flag":16,"./getActual":17,"./getMessage":19,"./getName":20,"./getPathInfo":21,"./getPathValue":22,"./hasProperty":24,"./inspect":26,"./objDisplay":27,"./overwriteChainableMethod":28,"./overwriteMethod":29,"./overwriteProperty":30,"./test":31,"./transferFlags":32,"deep-eql":33,"type-detect":39}],26:[function(require,module,exports){ +// This is (almost) directly from Node.js utils +// https://github.com/joyent/node/blob/f8c335d0caf47f16d31413f89aa28eda3878e3aa/lib/util.js + +var getName = require('./getName'); +var getProperties = require('./getProperties'); +var getEnumerableProperties = require('./getEnumerableProperties'); + +module.exports = inspect; + +/** + * Echos the value of a value. Trys to print the value out + * in the best way possible given the different types. + * + * @param {Object} obj The object to print out. + * @param {Boolean} showHidden Flag that shows hidden (not enumerable) + * properties of objects. + * @param {Number} depth Depth in which to descend in object. Default is 2. + * @param {Boolean} colors Flag to turn on ANSI escape codes to color the + * output. Default is false (no coloring). + * @namespace Utils + * @name inspect + */ +function inspect(obj, showHidden, depth, colors) { + var ctx = { + showHidden: showHidden, + seen: [], + stylize: function (str) { return str; } + }; + return formatValue(ctx, obj, (typeof depth === 'undefined' ? 2 : depth)); +} + +// Returns true if object is a DOM element. +var isDOMElement = function (object) { + if (typeof HTMLElement === 'object') { + return object instanceof HTMLElement; + } else { + return object && + typeof object === 'object' && + object.nodeType === 1 && + typeof object.nodeName === 'string'; + } +}; + +function formatValue(ctx, value, recurseTimes) { + // Provide a hook for user-specified inspect functions. + // Check that value is an object with an inspect function on it + if (value && typeof value.inspect === 'function' && + // Filter out the util module, it's inspect function is special + value.inspect !== exports.inspect && + // Also filter out any prototype objects using the circular check. + !(value.constructor && value.constructor.prototype === value)) { + var ret = value.inspect(recurseTimes); + if (typeof ret !== 'string') { + ret = formatValue(ctx, ret, recurseTimes); + } + return ret; + } + + // Primitive types cannot have properties + var primitive = formatPrimitive(ctx, value); + if (primitive) { + return primitive; + } + + // If this is a DOM element, try to get the outer HTML. + if (isDOMElement(value)) { + if ('outerHTML' in value) { + return value.outerHTML; + // This value does not have an outerHTML attribute, + // it could still be an XML element + } else { + // Attempt to serialize it + try { + if (document.xmlVersion) { + var xmlSerializer = new XMLSerializer(); + return xmlSerializer.serializeToString(value); + } else { + // Firefox 11- do not support outerHTML + // It does, however, support innerHTML + // Use the following to render the element + var ns = "http://www.w3.org/1999/xhtml"; + var container = document.createElementNS(ns, '_'); + + container.appendChild(value.cloneNode(false)); + html = container.innerHTML + .replace('><', '>' + value.innerHTML + '<'); + container.innerHTML = ''; + return html; + } + } catch (err) { + // This could be a non-native DOM implementation, + // continue with the normal flow: + // printing the element as if it is an object. + } + } + } + + // Look up the keys of the object. + var visibleKeys = getEnumerableProperties(value); + var keys = ctx.showHidden ? getProperties(value) : visibleKeys; + + // Some type of object without properties can be shortcutted. + // In IE, errors have a single `stack` property, or if they are vanilla `Error`, + // a `stack` plus `description` property; ignore those for consistency. + if (keys.length === 0 || (isError(value) && ( + (keys.length === 1 && keys[0] === 'stack') || + (keys.length === 2 && keys[0] === 'description' && keys[1] === 'stack') + ))) { + if (typeof value === 'function') { + var name = getName(value); + var nameSuffix = name ? ': ' + name : ''; + return ctx.stylize('[Function' + nameSuffix + ']', 'special'); + } + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } + if (isDate(value)) { + return ctx.stylize(Date.prototype.toUTCString.call(value), 'date'); + } + if (isError(value)) { + return formatError(value); + } + } + + var base = '', array = false, braces = ['{', '}']; + + // Make Array say that they are Array + if (isArray(value)) { + array = true; + braces = ['[', ']']; + } + + // Make functions say that they are functions + if (typeof value === 'function') { + var name = getName(value); + var nameSuffix = name ? ': ' + name : ''; + base = ' [Function' + nameSuffix + ']'; + } + + // Make RegExps say that they are RegExps + if (isRegExp(value)) { + base = ' ' + RegExp.prototype.toString.call(value); + } + + // Make dates with properties first say the date + if (isDate(value)) { + base = ' ' + Date.prototype.toUTCString.call(value); + } + + // Make error with message first say the error + if (isError(value)) { + return formatError(value); + } + + if (keys.length === 0 && (!array || value.length == 0)) { + return braces[0] + base + braces[1]; + } + + if (recurseTimes < 0) { + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } else { + return ctx.stylize('[Object]', 'special'); + } + } + + ctx.seen.push(value); + + var output; + if (array) { + output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); + } else { + output = keys.map(function(key) { + return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); + }); + } + + ctx.seen.pop(); + + return reduceToSingleString(output, base, braces); +} + + +function formatPrimitive(ctx, value) { + switch (typeof value) { + case 'undefined': + return ctx.stylize('undefined', 'undefined'); + + case 'string': + var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') + .replace(/'/g, "\\'") + .replace(/\\"/g, '"') + '\''; + return ctx.stylize(simple, 'string'); + + case 'number': + if (value === 0 && (1/value) === -Infinity) { + return ctx.stylize('-0', 'number'); + } + return ctx.stylize('' + value, 'number'); + + case 'boolean': + return ctx.stylize('' + value, 'boolean'); + } + // For some reason typeof null is "object", so special case here. + if (value === null) { + return ctx.stylize('null', 'null'); + } +} + + +function formatError(value) { + return '[' + Error.prototype.toString.call(value) + ']'; +} + + +function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { + var output = []; + for (var i = 0, l = value.length; i < l; ++i) { + if (Object.prototype.hasOwnProperty.call(value, String(i))) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + String(i), true)); + } else { + output.push(''); + } + } + keys.forEach(function(key) { + if (!key.match(/^\d+$/)) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + key, true)); + } + }); + return output; +} + + +function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { + var name, str; + if (value.__lookupGetter__) { + if (value.__lookupGetter__(key)) { + if (value.__lookupSetter__(key)) { + str = ctx.stylize('[Getter/Setter]', 'special'); + } else { + str = ctx.stylize('[Getter]', 'special'); + } + } else { + if (value.__lookupSetter__(key)) { + str = ctx.stylize('[Setter]', 'special'); + } + } + } + if (visibleKeys.indexOf(key) < 0) { + name = '[' + key + ']'; + } + if (!str) { + if (ctx.seen.indexOf(value[key]) < 0) { + if (recurseTimes === null) { + str = formatValue(ctx, value[key], null); + } else { + str = formatValue(ctx, value[key], recurseTimes - 1); + } + if (str.indexOf('\n') > -1) { + if (array) { + str = str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n').substr(2); + } else { + str = '\n' + str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n'); + } + } + } else { + str = ctx.stylize('[Circular]', 'special'); + } + } + if (typeof name === 'undefined') { + if (array && key.match(/^\d+$/)) { + return str; + } + name = JSON.stringify('' + key); + if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { + name = name.substr(1, name.length - 2); + name = ctx.stylize(name, 'name'); + } else { + name = name.replace(/'/g, "\\'") + .replace(/\\"/g, '"') + .replace(/(^"|"$)/g, "'"); + name = ctx.stylize(name, 'string'); + } + } + + return name + ': ' + str; +} + + +function reduceToSingleString(output, base, braces) { + var numLinesEst = 0; + var length = output.reduce(function(prev, cur) { + numLinesEst++; + if (cur.indexOf('\n') >= 0) numLinesEst++; + return prev + cur.length + 1; + }, 0); + + if (length > 60) { + return braces[0] + + (base === '' ? '' : base + '\n ') + + ' ' + + output.join(',\n ') + + ' ' + + braces[1]; + } + + return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; +} + +function isArray(ar) { + return Array.isArray(ar) || + (typeof ar === 'object' && objectToString(ar) === '[object Array]'); +} + +function isRegExp(re) { + return typeof re === 'object' && objectToString(re) === '[object RegExp]'; +} + +function isDate(d) { + return typeof d === 'object' && objectToString(d) === '[object Date]'; +} + +function isError(e) { + return typeof e === 'object' && objectToString(e) === '[object Error]'; +} + +function objectToString(o) { + return Object.prototype.toString.call(o); +} + +},{"./getEnumerableProperties":18,"./getName":20,"./getProperties":23}],27:[function(require,module,exports){ +/*! + * Chai - flag utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/*! + * Module dependancies + */ + +var inspect = require('./inspect'); +var config = require('../config'); + +/** + * ### .objDisplay (object) + * + * Determines if an object or an array matches + * criteria to be inspected in-line for error + * messages or should be truncated. + * + * @param {Mixed} javascript object to inspect + * @name objDisplay + * @namespace Utils + * @api public + */ + +module.exports = function (obj) { + var str = inspect(obj) + , type = Object.prototype.toString.call(obj); + + if (config.truncateThreshold && str.length >= config.truncateThreshold) { + if (type === '[object Function]') { + return !obj.name || obj.name === '' + ? '[Function]' + : '[Function: ' + obj.name + ']'; + } else if (type === '[object Array]') { + return '[ Array(' + obj.length + ') ]'; + } else if (type === '[object Object]') { + var keys = Object.keys(obj) + , kstr = keys.length > 2 + ? keys.splice(0, 2).join(', ') + ', ...' + : keys.join(', '); + return '{ Object (' + kstr + ') }'; + } else { + return str; + } + } else { + return str; + } +}; + +},{"../config":7,"./inspect":26}],28:[function(require,module,exports){ +/*! + * Chai - overwriteChainableMethod utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/** + * ### overwriteChainableMethod (ctx, name, method, chainingBehavior) + * + * Overwites an already existing chainable method + * and provides access to the previous function or + * property. Must return functions to be used for + * name. + * + * utils.overwriteChainableMethod(chai.Assertion.prototype, 'length', + * function (_super) { + * } + * , function (_super) { + * } + * ); + * + * Can also be accessed directly from `chai.Assertion`. + * + * chai.Assertion.overwriteChainableMethod('foo', fn, fn); + * + * Then can be used as any other assertion. + * + * expect(myFoo).to.have.length(3); + * expect(myFoo).to.have.length.above(3); + * + * @param {Object} ctx object whose method / property is to be overwritten + * @param {String} name of method / property to overwrite + * @param {Function} method function that returns a function to be used for name + * @param {Function} chainingBehavior function that returns a function to be used for property + * @namespace Utils + * @name overwriteChainableMethod + * @api public + */ + +module.exports = function (ctx, name, method, chainingBehavior) { + var chainableBehavior = ctx.__methods[name]; + + var _chainingBehavior = chainableBehavior.chainingBehavior; + chainableBehavior.chainingBehavior = function () { + var result = chainingBehavior(_chainingBehavior).call(this); + return result === undefined ? this : result; + }; + + var _method = chainableBehavior.method; + chainableBehavior.method = function () { + var result = method(_method).apply(this, arguments); + return result === undefined ? this : result; + }; +}; + +},{}],29:[function(require,module,exports){ +/*! + * Chai - overwriteMethod utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/** + * ### overwriteMethod (ctx, name, fn) + * + * Overwites an already existing method and provides + * access to previous function. Must return function + * to be used for name. + * + * utils.overwriteMethod(chai.Assertion.prototype, 'equal', function (_super) { + * return function (str) { + * var obj = utils.flag(this, 'object'); + * if (obj instanceof Foo) { + * new chai.Assertion(obj.value).to.equal(str); + * } else { + * _super.apply(this, arguments); + * } + * } + * }); + * + * Can also be accessed directly from `chai.Assertion`. + * + * chai.Assertion.overwriteMethod('foo', fn); + * + * Then can be used as any other assertion. + * + * expect(myFoo).to.equal('bar'); + * + * @param {Object} ctx object whose method is to be overwritten + * @param {String} name of method to overwrite + * @param {Function} method function that returns a function to be used for name + * @namespace Utils + * @name overwriteMethod + * @api public + */ + +module.exports = function (ctx, name, method) { + var _method = ctx[name] + , _super = function () { return this; }; + + if (_method && 'function' === typeof _method) + _super = _method; + + ctx[name] = function () { + var result = method(_super).apply(this, arguments); + return result === undefined ? this : result; + } +}; + +},{}],30:[function(require,module,exports){ +/*! + * Chai - overwriteProperty utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/** + * ### overwriteProperty (ctx, name, fn) + * + * Overwites an already existing property getter and provides + * access to previous value. Must return function to use as getter. + * + * utils.overwriteProperty(chai.Assertion.prototype, 'ok', function (_super) { + * return function () { + * var obj = utils.flag(this, 'object'); + * if (obj instanceof Foo) { + * new chai.Assertion(obj.name).to.equal('bar'); + * } else { + * _super.call(this); + * } + * } + * }); + * + * + * Can also be accessed directly from `chai.Assertion`. + * + * chai.Assertion.overwriteProperty('foo', fn); + * + * Then can be used as any other assertion. + * + * expect(myFoo).to.be.ok; + * + * @param {Object} ctx object whose property is to be overwritten + * @param {String} name of property to overwrite + * @param {Function} getter function that returns a getter function to be used for name + * @namespace Utils + * @name overwriteProperty + * @api public + */ + +module.exports = function (ctx, name, getter) { + var _get = Object.getOwnPropertyDescriptor(ctx, name) + , _super = function () {}; + + if (_get && 'function' === typeof _get.get) + _super = _get.get + + Object.defineProperty(ctx, name, + { get: function () { + var result = getter(_super).call(this); + return result === undefined ? this : result; + } + , configurable: true + }); +}; + +},{}],31:[function(require,module,exports){ +/*! + * Chai - test utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/*! + * Module dependancies + */ + +var flag = require('./flag'); + +/** + * # test(object, expression) + * + * Test and object for expression. + * + * @param {Object} object (constructed Assertion) + * @param {Arguments} chai.Assertion.prototype.assert arguments + * @namespace Utils + * @name test + */ + +module.exports = function (obj, args) { + var negate = flag(obj, 'negate') + , expr = args[0]; + return negate ? !expr : expr; +}; + +},{"./flag":16}],32:[function(require,module,exports){ +/*! + * Chai - transferFlags utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/** + * ### transferFlags(assertion, object, includeAll = true) + * + * Transfer all the flags for `assertion` to `object`. If + * `includeAll` is set to `false`, then the base Chai + * assertion flags (namely `object`, `ssfi`, and `message`) + * will not be transferred. + * + * + * var newAssertion = new Assertion(); + * utils.transferFlags(assertion, newAssertion); + * + * var anotherAsseriton = new Assertion(myObj); + * utils.transferFlags(assertion, anotherAssertion, false); + * + * @param {Assertion} assertion the assertion to transfer the flags from + * @param {Object} object the object to transfer the flags to; usually a new assertion + * @param {Boolean} includeAll + * @namespace Utils + * @name transferFlags + * @api private + */ + +module.exports = function (assertion, object, includeAll) { + var flags = assertion.__flags || (assertion.__flags = Object.create(null)); + + if (!object.__flags) { + object.__flags = Object.create(null); + } + + includeAll = arguments.length === 3 ? includeAll : true; + + for (var flag in flags) { + if (includeAll || + (flag !== 'object' && flag !== 'ssfi' && flag != 'message')) { + object.__flags[flag] = flags[flag]; + } + } +}; + +},{}],33:[function(require,module,exports){ +module.exports = require('./lib/eql'); + +},{"./lib/eql":34}],34:[function(require,module,exports){ +/*! + * deep-eql + * Copyright(c) 2013 Jake Luer + * MIT Licensed + */ + +/*! + * Module dependencies + */ + +var type = require('type-detect'); + +/*! + * Buffer.isBuffer browser shim + */ + +var Buffer; +try { Buffer = require('buffer').Buffer; } +catch(ex) { + Buffer = {}; + Buffer.isBuffer = function() { return false; } +} + +/*! + * Primary Export + */ + +module.exports = deepEqual; + +/** + * Assert super-strict (egal) equality between + * two objects of any type. + * + * @param {Mixed} a + * @param {Mixed} b + * @param {Array} memoised (optional) + * @return {Boolean} equal match + */ + +function deepEqual(a, b, m) { + if (sameValue(a, b)) { + return true; + } else if ('date' === type(a)) { + return dateEqual(a, b); + } else if ('regexp' === type(a)) { + return regexpEqual(a, b); + } else if (Buffer.isBuffer(a)) { + return bufferEqual(a, b); + } else if ('arguments' === type(a)) { + return argumentsEqual(a, b, m); + } else if (!typeEqual(a, b)) { + return false; + } else if (('object' !== type(a) && 'object' !== type(b)) + && ('array' !== type(a) && 'array' !== type(b))) { + return sameValue(a, b); + } else { + return objectEqual(a, b, m); + } +} + +/*! + * Strict (egal) equality test. Ensures that NaN always + * equals NaN and `-0` does not equal `+0`. + * + * @param {Mixed} a + * @param {Mixed} b + * @return {Boolean} equal match + */ + +function sameValue(a, b) { + if (a === b) return a !== 0 || 1 / a === 1 / b; + return a !== a && b !== b; +} + +/*! + * Compare the types of two given objects and + * return if they are equal. Note that an Array + * has a type of `array` (not `object`) and arguments + * have a type of `arguments` (not `array`/`object`). + * + * @param {Mixed} a + * @param {Mixed} b + * @return {Boolean} result + */ + +function typeEqual(a, b) { + return type(a) === type(b); +} + +/*! + * Compare two Date objects by asserting that + * the time values are equal using `saveValue`. + * + * @param {Date} a + * @param {Date} b + * @return {Boolean} result + */ + +function dateEqual(a, b) { + if ('date' !== type(b)) return false; + return sameValue(a.getTime(), b.getTime()); +} + +/*! + * Compare two regular expressions by converting them + * to string and checking for `sameValue`. + * + * @param {RegExp} a + * @param {RegExp} b + * @return {Boolean} result + */ + +function regexpEqual(a, b) { + if ('regexp' !== type(b)) return false; + return sameValue(a.toString(), b.toString()); +} + +/*! + * Assert deep equality of two `arguments` objects. + * Unfortunately, these must be sliced to arrays + * prior to test to ensure no bad behavior. + * + * @param {Arguments} a + * @param {Arguments} b + * @param {Array} memoize (optional) + * @return {Boolean} result + */ + +function argumentsEqual(a, b, m) { + if ('arguments' !== type(b)) return false; + a = [].slice.call(a); + b = [].slice.call(b); + return deepEqual(a, b, m); +} + +/*! + * Get enumerable properties of a given object. + * + * @param {Object} a + * @return {Array} property names + */ + +function enumerable(a) { + var res = []; + for (var key in a) res.push(key); + return res; +} + +/*! + * Simple equality for flat iterable objects + * such as Arrays or Node.js buffers. + * + * @param {Iterable} a + * @param {Iterable} b + * @return {Boolean} result + */ + +function iterableEqual(a, b) { + if (a.length !== b.length) return false; + + var i = 0; + var match = true; + + for (; i < a.length; i++) { + if (a[i] !== b[i]) { + match = false; + break; + } + } + + return match; +} + +/*! + * Extension to `iterableEqual` specifically + * for Node.js Buffers. + * + * @param {Buffer} a + * @param {Mixed} b + * @return {Boolean} result + */ + +function bufferEqual(a, b) { + if (!Buffer.isBuffer(b)) return false; + return iterableEqual(a, b); +} + +/*! + * Block for `objectEqual` ensuring non-existing + * values don't get in. + * + * @param {Mixed} object + * @return {Boolean} result + */ + +function isValue(a) { + return a !== null && a !== undefined; +} + +/*! + * Recursively check the equality of two objects. + * Once basic sameness has been established it will + * defer to `deepEqual` for each enumerable key + * in the object. + * + * @param {Mixed} a + * @param {Mixed} b + * @return {Boolean} result + */ + +function objectEqual(a, b, m) { + if (!isValue(a) || !isValue(b)) { + return false; + } + + if (a.prototype !== b.prototype) { + return false; + } + + var i; + if (m) { + for (i = 0; i < m.length; i++) { + if ((m[i][0] === a && m[i][1] === b) + || (m[i][0] === b && m[i][1] === a)) { + return true; + } + } + } else { + m = []; + } + + try { + var ka = enumerable(a); + var kb = enumerable(b); + } catch (ex) { + return false; + } + + ka.sort(); + kb.sort(); + + if (!iterableEqual(ka, kb)) { + return false; + } + + m.push([ a, b ]); + + var key; + for (i = ka.length - 1; i >= 0; i--) { + key = ka[i]; + if (!deepEqual(a[key], b[key], m)) { + return false; + } + } + + return true; +} + +},{"buffer":3,"type-detect":35}],35:[function(require,module,exports){ +module.exports = require('./lib/type'); + +},{"./lib/type":36}],36:[function(require,module,exports){ +/*! + * type-detect + * Copyright(c) 2013 jake luer + * MIT Licensed + */ + +/*! + * Primary Exports + */ + +var exports = module.exports = getType; + +/*! + * Detectable javascript natives + */ + +var natives = { + '[object Array]': 'array' + , '[object RegExp]': 'regexp' + , '[object Function]': 'function' + , '[object Arguments]': 'arguments' + , '[object Date]': 'date' +}; + +/** + * ### typeOf (obj) + * + * Use several different techniques to determine + * the type of object being tested. + * + * + * @param {Mixed} object + * @return {String} object type + * @api public + */ + +function getType (obj) { + var str = Object.prototype.toString.call(obj); + if (natives[str]) return natives[str]; + if (obj === null) return 'null'; + if (obj === undefined) return 'undefined'; + if (obj === Object(obj)) return 'object'; + return typeof obj; +} + +exports.Library = Library; + +/** + * ### Library + * + * Create a repository for custom type detection. + * + * ```js + * var lib = new type.Library; + * ``` + * + */ + +function Library () { + this.tests = {}; +} + +/** + * #### .of (obj) + * + * Expose replacement `typeof` detection to the library. + * + * ```js + * if ('string' === lib.of('hello world')) { + * // ... + * } + * ``` + * + * @param {Mixed} object to test + * @return {String} type + */ + +Library.prototype.of = getType; + +/** + * #### .define (type, test) + * + * Add a test to for the `.test()` assertion. + * + * Can be defined as a regular expression: + * + * ```js + * lib.define('int', /^[0-9]+$/); + * ``` + * + * ... or as a function: + * + * ```js + * lib.define('bln', function (obj) { + * if ('boolean' === lib.of(obj)) return true; + * var blns = [ 'yes', 'no', 'true', 'false', 1, 0 ]; + * if ('string' === lib.of(obj)) obj = obj.toLowerCase(); + * return !! ~blns.indexOf(obj); + * }); + * ``` + * + * @param {String} type + * @param {RegExp|Function} test + * @api public + */ + +Library.prototype.define = function (type, test) { + if (arguments.length === 1) return this.tests[type]; + this.tests[type] = test; + return this; +}; + +/** + * #### .test (obj, test) + * + * Assert that an object is of type. Will first + * check natives, and if that does not pass it will + * use the user defined custom tests. + * + * ```js + * assert(lib.test('1', 'int')); + * assert(lib.test('yes', 'bln')); + * ``` + * + * @param {Mixed} object + * @param {String} type + * @return {Boolean} result + * @api public + */ + +Library.prototype.test = function (obj, type) { + if (type === getType(obj)) return true; + var test = this.tests[type]; + + if (test && 'regexp' === getType(test)) { + return test.test(obj); + } else if (test && 'function' === getType(test)) { + return test(obj); + } else { + throw new ReferenceError('Type test "' + type + '" not defined or invalid.'); + } +}; + +},{}],37:[function(require,module,exports){ +exports.read = function (buffer, offset, isLE, mLen, nBytes) { + var e, m + var eLen = nBytes * 8 - mLen - 1 + var eMax = (1 << eLen) - 1 + var eBias = eMax >> 1 + var nBits = -7 + var i = isLE ? (nBytes - 1) : 0 + var d = isLE ? -1 : 1 + var s = buffer[offset + i] + + i += d + + e = s & ((1 << (-nBits)) - 1) + s >>= (-nBits) + nBits += eLen + for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {} + + m = e & ((1 << (-nBits)) - 1) + e >>= (-nBits) + nBits += mLen + for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {} + + if (e === 0) { + e = 1 - eBias + } else if (e === eMax) { + return m ? NaN : ((s ? -1 : 1) * Infinity) + } else { + m = m + Math.pow(2, mLen) + e = e - eBias + } + return (s ? -1 : 1) * m * Math.pow(2, e - mLen) +} + +exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { + var e, m, c + var eLen = nBytes * 8 - mLen - 1 + var eMax = (1 << eLen) - 1 + var eBias = eMax >> 1 + var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) + var i = isLE ? 0 : (nBytes - 1) + var d = isLE ? 1 : -1 + var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 + + value = Math.abs(value) + + if (isNaN(value) || value === Infinity) { + m = isNaN(value) ? 1 : 0 + e = eMax + } else { + e = Math.floor(Math.log(value) / Math.LN2) + if (value * (c = Math.pow(2, -e)) < 1) { + e-- + c *= 2 + } + if (e + eBias >= 1) { + value += rt / c + } else { + value += rt * Math.pow(2, 1 - eBias) + } + if (value * c >= 2) { + e++ + c /= 2 + } + + if (e + eBias >= eMax) { + m = 0 + e = eMax + } else if (e + eBias >= 1) { + m = (value * c - 1) * Math.pow(2, mLen) + e = e + eBias + } else { + m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) + e = 0 + } + } + + for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} + + e = (e << mLen) | m + eLen += mLen + for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} + + buffer[offset + i - d] |= s * 128 +} + +},{}],38:[function(require,module,exports){ +var toString = {}.toString; + +module.exports = Array.isArray || function (arr) { + return toString.call(arr) == '[object Array]'; +}; + +},{}],39:[function(require,module,exports){ +arguments[4][35][0].apply(exports,arguments) +},{"./lib/type":40,"dup":35}],40:[function(require,module,exports){ +/*! + * type-detect + * Copyright(c) 2013 jake luer + * MIT Licensed + */ + +/*! + * Primary Exports + */ + +var exports = module.exports = getType; + +/** + * ### typeOf (obj) + * + * Use several different techniques to determine + * the type of object being tested. + * + * + * @param {Mixed} object + * @return {String} object type + * @api public + */ +var objectTypeRegexp = /^\[object (.*)\]$/; + +function getType(obj) { + var type = Object.prototype.toString.call(obj).match(objectTypeRegexp)[1].toLowerCase(); + // Let "new String('')" return 'object' + if (typeof Promise === 'function' && obj instanceof Promise) return 'promise'; + // PhantomJS has type "DOMWindow" for null + if (obj === null) return 'null'; + // PhantomJS has type "DOMWindow" for undefined + if (obj === undefined) return 'undefined'; + return type; +} + +exports.Library = Library; + +/** + * ### Library + * + * Create a repository for custom type detection. + * + * ```js + * var lib = new type.Library; + * ``` + * + */ + +function Library() { + if (!(this instanceof Library)) return new Library(); + this.tests = {}; +} + +/** + * #### .of (obj) + * + * Expose replacement `typeof` detection to the library. + * + * ```js + * if ('string' === lib.of('hello world')) { + * // ... + * } + * ``` + * + * @param {Mixed} object to test + * @return {String} type + */ + +Library.prototype.of = getType; + +/** + * #### .define (type, test) + * + * Add a test to for the `.test()` assertion. + * + * Can be defined as a regular expression: + * + * ```js + * lib.define('int', /^[0-9]+$/); + * ``` + * + * ... or as a function: + * + * ```js + * lib.define('bln', function (obj) { + * if ('boolean' === lib.of(obj)) return true; + * var blns = [ 'yes', 'no', 'true', 'false', 1, 0 ]; + * if ('string' === lib.of(obj)) obj = obj.toLowerCase(); + * return !! ~blns.indexOf(obj); + * }); + * ``` + * + * @param {String} type + * @param {RegExp|Function} test + * @api public + */ + +Library.prototype.define = function(type, test) { + if (arguments.length === 1) return this.tests[type]; + this.tests[type] = test; + return this; +}; + +/** + * #### .test (obj, test) + * + * Assert that an object is of type. Will first + * check natives, and if that does not pass it will + * use the user defined custom tests. + * + * ```js + * assert(lib.test('1', 'int')); + * assert(lib.test('yes', 'bln')); + * ``` + * + * @param {Mixed} object + * @param {String} type + * @return {Boolean} result + * @api public + */ + +Library.prototype.test = function(obj, type) { + if (type === getType(obj)) return true; + var test = this.tests[type]; + + if (test && 'regexp' === getType(test)) { + return test.test(obj); + } else if (test && 'function' === getType(test)) { + return test(obj); + } else { + throw new ReferenceError('Type test "' + type + '" not defined or invalid.'); + } +}; + +},{}],41:[function(require,module,exports){ +// Underscore.js 1.8.3 +// http://underscorejs.org +// (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors +// Underscore may be freely distributed under the MIT license. + +(function() { + + // Baseline setup + // -------------- + + // Establish the root object, `window` in the browser, or `exports` on the server. + var root = this; + + // Save the previous value of the `_` variable. + var previousUnderscore = root._; + + // Save bytes in the minified (but not gzipped) version: + var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; + + // Create quick reference variables for speed access to core prototypes. + var + push = ArrayProto.push, + slice = ArrayProto.slice, + toString = ObjProto.toString, + hasOwnProperty = ObjProto.hasOwnProperty; + + // All **ECMAScript 5** native function implementations that we hope to use + // are declared here. + var + nativeIsArray = Array.isArray, + nativeKeys = Object.keys, + nativeBind = FuncProto.bind, + nativeCreate = Object.create; + + // Naked function reference for surrogate-prototype-swapping. + var Ctor = function(){}; + + // Create a safe reference to the Underscore object for use below. + var _ = function(obj) { + if (obj instanceof _) return obj; + if (!(this instanceof _)) return new _(obj); + this._wrapped = obj; + }; + + // Export the Underscore object for **Node.js**, with + // backwards-compatibility for the old `require()` API. If we're in + // the browser, add `_` as a global object. + if (typeof exports !== 'undefined') { + if (typeof module !== 'undefined' && module.exports) { + exports = module.exports = _; + } + exports._ = _; + } else { + root._ = _; + } + + // Current version. + _.VERSION = '1.8.3'; + + // Internal function that returns an efficient (for current engines) version + // of the passed-in callback, to be repeatedly applied in other Underscore + // functions. + var optimizeCb = function(func, context, argCount) { + if (context === void 0) return func; + switch (argCount == null ? 3 : argCount) { + case 1: return function(value) { + return func.call(context, value); + }; + case 2: return function(value, other) { + return func.call(context, value, other); + }; + case 3: return function(value, index, collection) { + return func.call(context, value, index, collection); + }; + case 4: return function(accumulator, value, index, collection) { + return func.call(context, accumulator, value, index, collection); + }; + } + return function() { + return func.apply(context, arguments); + }; + }; + + // A mostly-internal function to generate callbacks that can be applied + // to each element in a collection, returning the desired result — either + // identity, an arbitrary callback, a property matcher, or a property accessor. + var cb = function(value, context, argCount) { + if (value == null) return _.identity; + if (_.isFunction(value)) return optimizeCb(value, context, argCount); + if (_.isObject(value)) return _.matcher(value); + return _.property(value); + }; + _.iteratee = function(value, context) { + return cb(value, context, Infinity); + }; + + // An internal function for creating assigner functions. + var createAssigner = function(keysFunc, undefinedOnly) { + return function(obj) { + var length = arguments.length; + if (length < 2 || obj == null) return obj; + for (var index = 1; index < length; index++) { + var source = arguments[index], + keys = keysFunc(source), + l = keys.length; + for (var i = 0; i < l; i++) { + var key = keys[i]; + if (!undefinedOnly || obj[key] === void 0) obj[key] = source[key]; + } + } + return obj; + }; + }; + + // An internal function for creating a new object that inherits from another. + var baseCreate = function(prototype) { + if (!_.isObject(prototype)) return {}; + if (nativeCreate) return nativeCreate(prototype); + Ctor.prototype = prototype; + var result = new Ctor; + Ctor.prototype = null; + return result; + }; + + var property = function(key) { + return function(obj) { + return obj == null ? void 0 : obj[key]; + }; + }; + + // Helper for collection methods to determine whether a collection + // should be iterated as an array or as an object + // Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength + // Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094 + var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1; + var getLength = property('length'); + var isArrayLike = function(collection) { + var length = getLength(collection); + return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX; + }; + + // Collection Functions + // -------------------- + + // The cornerstone, an `each` implementation, aka `forEach`. + // Handles raw objects in addition to array-likes. Treats all + // sparse array-likes as if they were dense. + _.each = _.forEach = function(obj, iteratee, context) { + iteratee = optimizeCb(iteratee, context); + var i, length; + if (isArrayLike(obj)) { + for (i = 0, length = obj.length; i < length; i++) { + iteratee(obj[i], i, obj); + } + } else { + var keys = _.keys(obj); + for (i = 0, length = keys.length; i < length; i++) { + iteratee(obj[keys[i]], keys[i], obj); + } + } + return obj; + }; + + // Return the results of applying the iteratee to each element. + _.map = _.collect = function(obj, iteratee, context) { + iteratee = cb(iteratee, context); + var keys = !isArrayLike(obj) && _.keys(obj), + length = (keys || obj).length, + results = Array(length); + for (var index = 0; index < length; index++) { + var currentKey = keys ? keys[index] : index; + results[index] = iteratee(obj[currentKey], currentKey, obj); + } + return results; + }; + + // Create a reducing function iterating left or right. + function createReduce(dir) { + // Optimized iterator function as using arguments.length + // in the main function will deoptimize the, see #1991. + function iterator(obj, iteratee, memo, keys, index, length) { + for (; index >= 0 && index < length; index += dir) { + var currentKey = keys ? keys[index] : index; + memo = iteratee(memo, obj[currentKey], currentKey, obj); + } + return memo; + } + + return function(obj, iteratee, memo, context) { + iteratee = optimizeCb(iteratee, context, 4); + var keys = !isArrayLike(obj) && _.keys(obj), + length = (keys || obj).length, + index = dir > 0 ? 0 : length - 1; + // Determine the initial value if none is provided. + if (arguments.length < 3) { + memo = obj[keys ? keys[index] : index]; + index += dir; + } + return iterator(obj, iteratee, memo, keys, index, length); + }; + } + + // **Reduce** builds up a single result from a list of values, aka `inject`, + // or `foldl`. + _.reduce = _.foldl = _.inject = createReduce(1); + + // The right-associative version of reduce, also known as `foldr`. + _.reduceRight = _.foldr = createReduce(-1); + + // Return the first value which passes a truth test. Aliased as `detect`. + _.find = _.detect = function(obj, predicate, context) { + var key; + if (isArrayLike(obj)) { + key = _.findIndex(obj, predicate, context); + } else { + key = _.findKey(obj, predicate, context); + } + if (key !== void 0 && key !== -1) return obj[key]; + }; + + // Return all the elements that pass a truth test. + // Aliased as `select`. + _.filter = _.select = function(obj, predicate, context) { + var results = []; + predicate = cb(predicate, context); + _.each(obj, function(value, index, list) { + if (predicate(value, index, list)) results.push(value); + }); + return results; + }; + + // Return all the elements for which a truth test fails. + _.reject = function(obj, predicate, context) { + return _.filter(obj, _.negate(cb(predicate)), context); + }; + + // Determine whether all of the elements match a truth test. + // Aliased as `all`. + _.every = _.all = function(obj, predicate, context) { + predicate = cb(predicate, context); + var keys = !isArrayLike(obj) && _.keys(obj), + length = (keys || obj).length; + for (var index = 0; index < length; index++) { + var currentKey = keys ? keys[index] : index; + if (!predicate(obj[currentKey], currentKey, obj)) return false; + } + return true; + }; + + // Determine if at least one element in the object matches a truth test. + // Aliased as `any`. + _.some = _.any = function(obj, predicate, context) { + predicate = cb(predicate, context); + var keys = !isArrayLike(obj) && _.keys(obj), + length = (keys || obj).length; + for (var index = 0; index < length; index++) { + var currentKey = keys ? keys[index] : index; + if (predicate(obj[currentKey], currentKey, obj)) return true; + } + return false; + }; + + // Determine if the array or object contains a given item (using `===`). + // Aliased as `includes` and `include`. + _.contains = _.includes = _.include = function(obj, item, fromIndex, guard) { + if (!isArrayLike(obj)) obj = _.values(obj); + if (typeof fromIndex != 'number' || guard) fromIndex = 0; + return _.indexOf(obj, item, fromIndex) >= 0; + }; + + // Invoke a method (with arguments) on every item in a collection. + _.invoke = function(obj, method) { + var args = slice.call(arguments, 2); + var isFunc = _.isFunction(method); + return _.map(obj, function(value) { + var func = isFunc ? method : value[method]; + return func == null ? func : func.apply(value, args); + }); + }; + + // Convenience version of a common use case of `map`: fetching a property. + _.pluck = function(obj, key) { + return _.map(obj, _.property(key)); + }; + + // Convenience version of a common use case of `filter`: selecting only objects + // containing specific `key:value` pairs. + _.where = function(obj, attrs) { + return _.filter(obj, _.matcher(attrs)); + }; + + // Convenience version of a common use case of `find`: getting the first object + // containing specific `key:value` pairs. + _.findWhere = function(obj, attrs) { + return _.find(obj, _.matcher(attrs)); + }; + + // Return the maximum element (or element-based computation). + _.max = function(obj, iteratee, context) { + var result = -Infinity, lastComputed = -Infinity, + value, computed; + if (iteratee == null && obj != null) { + obj = isArrayLike(obj) ? obj : _.values(obj); + for (var i = 0, length = obj.length; i < length; i++) { + value = obj[i]; + if (value > result) { + result = value; + } + } + } else { + iteratee = cb(iteratee, context); + _.each(obj, function(value, index, list) { + computed = iteratee(value, index, list); + if (computed > lastComputed || computed === -Infinity && result === -Infinity) { + result = value; + lastComputed = computed; + } + }); + } + return result; + }; + + // Return the minimum element (or element-based computation). + _.min = function(obj, iteratee, context) { + var result = Infinity, lastComputed = Infinity, + value, computed; + if (iteratee == null && obj != null) { + obj = isArrayLike(obj) ? obj : _.values(obj); + for (var i = 0, length = obj.length; i < length; i++) { + value = obj[i]; + if (value < result) { + result = value; + } + } + } else { + iteratee = cb(iteratee, context); + _.each(obj, function(value, index, list) { + computed = iteratee(value, index, list); + if (computed < lastComputed || computed === Infinity && result === Infinity) { + result = value; + lastComputed = computed; + } + }); + } + return result; + }; + + // Shuffle a collection, using the modern version of the + // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle). + _.shuffle = function(obj) { + var set = isArrayLike(obj) ? obj : _.values(obj); + var length = set.length; + var shuffled = Array(length); + for (var index = 0, rand; index < length; index++) { + rand = _.random(0, index); + if (rand !== index) shuffled[index] = shuffled[rand]; + shuffled[rand] = set[index]; + } + return shuffled; + }; + + // Sample **n** random values from a collection. + // If **n** is not specified, returns a single random element. + // The internal `guard` argument allows it to work with `map`. + _.sample = function(obj, n, guard) { + if (n == null || guard) { + if (!isArrayLike(obj)) obj = _.values(obj); + return obj[_.random(obj.length - 1)]; + } + return _.shuffle(obj).slice(0, Math.max(0, n)); + }; + + // Sort the object's values by a criterion produced by an iteratee. + _.sortBy = function(obj, iteratee, context) { + iteratee = cb(iteratee, context); + return _.pluck(_.map(obj, function(value, index, list) { + return { + value: value, + index: index, + criteria: iteratee(value, index, list) + }; + }).sort(function(left, right) { + var a = left.criteria; + var b = right.criteria; + if (a !== b) { + if (a > b || a === void 0) return 1; + if (a < b || b === void 0) return -1; + } + return left.index - right.index; + }), 'value'); + }; + + // An internal function used for aggregate "group by" operations. + var group = function(behavior) { + return function(obj, iteratee, context) { + var result = {}; + iteratee = cb(iteratee, context); + _.each(obj, function(value, index) { + var key = iteratee(value, index, obj); + behavior(result, value, key); + }); + return result; + }; + }; + + // Groups the object's values by a criterion. Pass either a string attribute + // to group by, or a function that returns the criterion. + _.groupBy = group(function(result, value, key) { + if (_.has(result, key)) result[key].push(value); else result[key] = [value]; + }); + + // Indexes the object's values by a criterion, similar to `groupBy`, but for + // when you know that your index values will be unique. + _.indexBy = group(function(result, value, key) { + result[key] = value; + }); + + // Counts instances of an object that group by a certain criterion. Pass + // either a string attribute to count by, or a function that returns the + // criterion. + _.countBy = group(function(result, value, key) { + if (_.has(result, key)) result[key]++; else result[key] = 1; + }); + + // Safely create a real, live array from anything iterable. + _.toArray = function(obj) { + if (!obj) return []; + if (_.isArray(obj)) return slice.call(obj); + if (isArrayLike(obj)) return _.map(obj, _.identity); + return _.values(obj); + }; + + // Return the number of elements in an object. + _.size = function(obj) { + if (obj == null) return 0; + return isArrayLike(obj) ? obj.length : _.keys(obj).length; + }; + + // Split a collection into two arrays: one whose elements all satisfy the given + // predicate, and one whose elements all do not satisfy the predicate. + _.partition = function(obj, predicate, context) { + predicate = cb(predicate, context); + var pass = [], fail = []; + _.each(obj, function(value, key, obj) { + (predicate(value, key, obj) ? pass : fail).push(value); + }); + return [pass, fail]; + }; + + // Array Functions + // --------------- + + // Get the first element of an array. Passing **n** will return the first N + // values in the array. Aliased as `head` and `take`. The **guard** check + // allows it to work with `_.map`. + _.first = _.head = _.take = function(array, n, guard) { + if (array == null) return void 0; + if (n == null || guard) return array[0]; + return _.initial(array, array.length - n); + }; + + // Returns everything but the last entry of the array. Especially useful on + // the arguments object. Passing **n** will return all the values in + // the array, excluding the last N. + _.initial = function(array, n, guard) { + return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n))); + }; + + // Get the last element of an array. Passing **n** will return the last N + // values in the array. + _.last = function(array, n, guard) { + if (array == null) return void 0; + if (n == null || guard) return array[array.length - 1]; + return _.rest(array, Math.max(0, array.length - n)); + }; + + // Returns everything but the first entry of the array. Aliased as `tail` and `drop`. + // Especially useful on the arguments object. Passing an **n** will return + // the rest N values in the array. + _.rest = _.tail = _.drop = function(array, n, guard) { + return slice.call(array, n == null || guard ? 1 : n); + }; + + // Trim out all falsy values from an array. + _.compact = function(array) { + return _.filter(array, _.identity); + }; + + // Internal implementation of a recursive `flatten` function. + var flatten = function(input, shallow, strict, startIndex) { + var output = [], idx = 0; + for (var i = startIndex || 0, length = getLength(input); i < length; i++) { + var value = input[i]; + if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) { + //flatten current level of array or arguments object + if (!shallow) value = flatten(value, shallow, strict); + var j = 0, len = value.length; + output.length += len; + while (j < len) { + output[idx++] = value[j++]; + } + } else if (!strict) { + output[idx++] = value; + } + } + return output; + }; + + // Flatten out an array, either recursively (by default), or just one level. + _.flatten = function(array, shallow) { + return flatten(array, shallow, false); + }; + + // Return a version of the array that does not contain the specified value(s). + _.without = function(array) { + return _.difference(array, slice.call(arguments, 1)); + }; + + // Produce a duplicate-free version of the array. If the array has already + // been sorted, you have the option of using a faster algorithm. + // Aliased as `unique`. + _.uniq = _.unique = function(array, isSorted, iteratee, context) { + if (!_.isBoolean(isSorted)) { + context = iteratee; + iteratee = isSorted; + isSorted = false; + } + if (iteratee != null) iteratee = cb(iteratee, context); + var result = []; + var seen = []; + for (var i = 0, length = getLength(array); i < length; i++) { + var value = array[i], + computed = iteratee ? iteratee(value, i, array) : value; + if (isSorted) { + if (!i || seen !== computed) result.push(value); + seen = computed; + } else if (iteratee) { + if (!_.contains(seen, computed)) { + seen.push(computed); + result.push(value); + } + } else if (!_.contains(result, value)) { + result.push(value); + } + } + return result; + }; + + // Produce an array that contains the union: each distinct element from all of + // the passed-in arrays. + _.union = function() { + return _.uniq(flatten(arguments, true, true)); + }; + + // Produce an array that contains every item shared between all the + // passed-in arrays. + _.intersection = function(array) { + var result = []; + var argsLength = arguments.length; + for (var i = 0, length = getLength(array); i < length; i++) { + var item = array[i]; + if (_.contains(result, item)) continue; + for (var j = 1; j < argsLength; j++) { + if (!_.contains(arguments[j], item)) break; + } + if (j === argsLength) result.push(item); + } + return result; + }; + + // Take the difference between one array and a number of other arrays. + // Only the elements present in just the first array will remain. + _.difference = function(array) { + var rest = flatten(arguments, true, true, 1); + return _.filter(array, function(value){ + return !_.contains(rest, value); + }); + }; + + // Zip together multiple lists into a single array -- elements that share + // an index go together. + _.zip = function() { + return _.unzip(arguments); + }; + + // Complement of _.zip. Unzip accepts an array of arrays and groups + // each array's elements on shared indices + _.unzip = function(array) { + var length = array && _.max(array, getLength).length || 0; + var result = Array(length); + + for (var index = 0; index < length; index++) { + result[index] = _.pluck(array, index); + } + return result; + }; + + // Converts lists into objects. Pass either a single array of `[key, value]` + // pairs, or two parallel arrays of the same length -- one of keys, and one of + // the corresponding values. + _.object = function(list, values) { + var result = {}; + for (var i = 0, length = getLength(list); i < length; i++) { + if (values) { + result[list[i]] = values[i]; + } else { + result[list[i][0]] = list[i][1]; + } + } + return result; + }; + + // Generator function to create the findIndex and findLastIndex functions + function createPredicateIndexFinder(dir) { + return function(array, predicate, context) { + predicate = cb(predicate, context); + var length = getLength(array); + var index = dir > 0 ? 0 : length - 1; + for (; index >= 0 && index < length; index += dir) { + if (predicate(array[index], index, array)) return index; + } + return -1; + }; + } + + // Returns the first index on an array-like that passes a predicate test + _.findIndex = createPredicateIndexFinder(1); + _.findLastIndex = createPredicateIndexFinder(-1); + + // Use a comparator function to figure out the smallest index at which + // an object should be inserted so as to maintain order. Uses binary search. + _.sortedIndex = function(array, obj, iteratee, context) { + iteratee = cb(iteratee, context, 1); + var value = iteratee(obj); + var low = 0, high = getLength(array); + while (low < high) { + var mid = Math.floor((low + high) / 2); + if (iteratee(array[mid]) < value) low = mid + 1; else high = mid; + } + return low; + }; + + // Generator function to create the indexOf and lastIndexOf functions + function createIndexFinder(dir, predicateFind, sortedIndex) { + return function(array, item, idx) { + var i = 0, length = getLength(array); + if (typeof idx == 'number') { + if (dir > 0) { + i = idx >= 0 ? idx : Math.max(idx + length, i); + } else { + length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1; + } + } else if (sortedIndex && idx && length) { + idx = sortedIndex(array, item); + return array[idx] === item ? idx : -1; + } + if (item !== item) { + idx = predicateFind(slice.call(array, i, length), _.isNaN); + return idx >= 0 ? idx + i : -1; + } + for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) { + if (array[idx] === item) return idx; + } + return -1; + }; + } + + // Return the position of the first occurrence of an item in an array, + // or -1 if the item is not included in the array. + // If the array is large and already in sort order, pass `true` + // for **isSorted** to use binary search. + _.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex); + _.lastIndexOf = createIndexFinder(-1, _.findLastIndex); + + // Generate an integer Array containing an arithmetic progression. A port of + // the native Python `range()` function. See + // [the Python documentation](http://docs.python.org/library/functions.html#range). + _.range = function(start, stop, step) { + if (stop == null) { + stop = start || 0; + start = 0; + } + step = step || 1; + + var length = Math.max(Math.ceil((stop - start) / step), 0); + var range = Array(length); + + for (var idx = 0; idx < length; idx++, start += step) { + range[idx] = start; + } + + return range; + }; + + // Function (ahem) Functions + // ------------------ + + // Determines whether to execute a function as a constructor + // or a normal function with the provided arguments + var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) { + if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args); + var self = baseCreate(sourceFunc.prototype); + var result = sourceFunc.apply(self, args); + if (_.isObject(result)) return result; + return self; + }; + + // Create a function bound to a given object (assigning `this`, and arguments, + // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if + // available. + _.bind = function(func, context) { + if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); + if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function'); + var args = slice.call(arguments, 2); + var bound = function() { + return executeBound(func, bound, context, this, args.concat(slice.call(arguments))); + }; + return bound; + }; + + // Partially apply a function by creating a version that has had some of its + // arguments pre-filled, without changing its dynamic `this` context. _ acts + // as a placeholder, allowing any combination of arguments to be pre-filled. + _.partial = function(func) { + var boundArgs = slice.call(arguments, 1); + var bound = function() { + var position = 0, length = boundArgs.length; + var args = Array(length); + for (var i = 0; i < length; i++) { + args[i] = boundArgs[i] === _ ? arguments[position++] : boundArgs[i]; + } + while (position < arguments.length) args.push(arguments[position++]); + return executeBound(func, bound, this, this, args); + }; + return bound; + }; + + // Bind a number of an object's methods to that object. Remaining arguments + // are the method names to be bound. Useful for ensuring that all callbacks + // defined on an object belong to it. + _.bindAll = function(obj) { + var i, length = arguments.length, key; + if (length <= 1) throw new Error('bindAll must be passed function names'); + for (i = 1; i < length; i++) { + key = arguments[i]; + obj[key] = _.bind(obj[key], obj); + } + return obj; + }; + + // Memoize an expensive function by storing its results. + _.memoize = function(func, hasher) { + var memoize = function(key) { + var cache = memoize.cache; + var address = '' + (hasher ? hasher.apply(this, arguments) : key); + if (!_.has(cache, address)) cache[address] = func.apply(this, arguments); + return cache[address]; + }; + memoize.cache = {}; + return memoize; + }; + + // Delays a function for the given number of milliseconds, and then calls + // it with the arguments supplied. + _.delay = function(func, wait) { + var args = slice.call(arguments, 2); + return setTimeout(function(){ + return func.apply(null, args); + }, wait); + }; + + // Defers a function, scheduling it to run after the current call stack has + // cleared. + _.defer = _.partial(_.delay, _, 1); + + // Returns a function, that, when invoked, will only be triggered at most once + // during a given window of time. Normally, the throttled function will run + // as much as it can, without ever going more than once per `wait` duration; + // but if you'd like to disable the execution on the leading edge, pass + // `{leading: false}`. To disable execution on the trailing edge, ditto. + _.throttle = function(func, wait, options) { + var context, args, result; + var timeout = null; + var previous = 0; + if (!options) options = {}; + var later = function() { + previous = options.leading === false ? 0 : _.now(); + timeout = null; + result = func.apply(context, args); + if (!timeout) context = args = null; + }; + return function() { + var now = _.now(); + if (!previous && options.leading === false) previous = now; + var remaining = wait - (now - previous); + context = this; + args = arguments; + if (remaining <= 0 || remaining > wait) { + if (timeout) { + clearTimeout(timeout); + timeout = null; + } + previous = now; + result = func.apply(context, args); + if (!timeout) context = args = null; + } else if (!timeout && options.trailing !== false) { + timeout = setTimeout(later, remaining); + } + return result; + }; + }; + + // Returns a function, that, as long as it continues to be invoked, will not + // be triggered. The function will be called after it stops being called for + // N milliseconds. If `immediate` is passed, trigger the function on the + // leading edge, instead of the trailing. + _.debounce = function(func, wait, immediate) { + var timeout, args, context, timestamp, result; + + var later = function() { + var last = _.now() - timestamp; + + if (last < wait && last >= 0) { + timeout = setTimeout(later, wait - last); + } else { + timeout = null; + if (!immediate) { + result = func.apply(context, args); + if (!timeout) context = args = null; + } + } + }; + + return function() { + context = this; + args = arguments; + timestamp = _.now(); + var callNow = immediate && !timeout; + if (!timeout) timeout = setTimeout(later, wait); + if (callNow) { + result = func.apply(context, args); + context = args = null; + } + + return result; + }; + }; + + // Returns the first function passed as an argument to the second, + // allowing you to adjust arguments, run code before and after, and + // conditionally execute the original function. + _.wrap = function(func, wrapper) { + return _.partial(wrapper, func); + }; + + // Returns a negated version of the passed-in predicate. + _.negate = function(predicate) { + return function() { + return !predicate.apply(this, arguments); + }; + }; + + // Returns a function that is the composition of a list of functions, each + // consuming the return value of the function that follows. + _.compose = function() { + var args = arguments; + var start = args.length - 1; + return function() { + var i = start; + var result = args[start].apply(this, arguments); + while (i--) result = args[i].call(this, result); + return result; + }; + }; + + // Returns a function that will only be executed on and after the Nth call. + _.after = function(times, func) { + return function() { + if (--times < 1) { + return func.apply(this, arguments); + } + }; + }; + + // Returns a function that will only be executed up to (but not including) the Nth call. + _.before = function(times, func) { + var memo; + return function() { + if (--times > 0) { + memo = func.apply(this, arguments); + } + if (times <= 1) func = null; + return memo; + }; + }; + + // Returns a function that will be executed at most one time, no matter how + // often you call it. Useful for lazy initialization. + _.once = _.partial(_.before, 2); + + // Object Functions + // ---------------- + + // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed. + var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString'); + var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString', + 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString']; + + function collectNonEnumProps(obj, keys) { + var nonEnumIdx = nonEnumerableProps.length; + var constructor = obj.constructor; + var proto = (_.isFunction(constructor) && constructor.prototype) || ObjProto; + + // Constructor is a special case. + var prop = 'constructor'; + if (_.has(obj, prop) && !_.contains(keys, prop)) keys.push(prop); + + while (nonEnumIdx--) { + prop = nonEnumerableProps[nonEnumIdx]; + if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) { + keys.push(prop); + } + } + } + + // Retrieve the names of an object's own properties. + // Delegates to **ECMAScript 5**'s native `Object.keys` + _.keys = function(obj) { + if (!_.isObject(obj)) return []; + if (nativeKeys) return nativeKeys(obj); + var keys = []; + for (var key in obj) if (_.has(obj, key)) keys.push(key); + // Ahem, IE < 9. + if (hasEnumBug) collectNonEnumProps(obj, keys); + return keys; + }; + + // Retrieve all the property names of an object. + _.allKeys = function(obj) { + if (!_.isObject(obj)) return []; + var keys = []; + for (var key in obj) keys.push(key); + // Ahem, IE < 9. + if (hasEnumBug) collectNonEnumProps(obj, keys); + return keys; + }; + + // Retrieve the values of an object's properties. + _.values = function(obj) { + var keys = _.keys(obj); + var length = keys.length; + var values = Array(length); + for (var i = 0; i < length; i++) { + values[i] = obj[keys[i]]; + } + return values; + }; + + // Returns the results of applying the iteratee to each element of the object + // In contrast to _.map it returns an object + _.mapObject = function(obj, iteratee, context) { + iteratee = cb(iteratee, context); + var keys = _.keys(obj), + length = keys.length, + results = {}, + currentKey; + for (var index = 0; index < length; index++) { + currentKey = keys[index]; + results[currentKey] = iteratee(obj[currentKey], currentKey, obj); + } + return results; + }; + + // Convert an object into a list of `[key, value]` pairs. + _.pairs = function(obj) { + var keys = _.keys(obj); + var length = keys.length; + var pairs = Array(length); + for (var i = 0; i < length; i++) { + pairs[i] = [keys[i], obj[keys[i]]]; + } + return pairs; + }; + + // Invert the keys and values of an object. The values must be serializable. + _.invert = function(obj) { + var result = {}; + var keys = _.keys(obj); + for (var i = 0, length = keys.length; i < length; i++) { + result[obj[keys[i]]] = keys[i]; + } + return result; + }; + + // Return a sorted list of the function names available on the object. + // Aliased as `methods` + _.functions = _.methods = function(obj) { + var names = []; + for (var key in obj) { + if (_.isFunction(obj[key])) names.push(key); + } + return names.sort(); + }; + + // Extend a given object with all the properties in passed-in object(s). + _.extend = createAssigner(_.allKeys); + + // Assigns a given object with all the own properties in the passed-in object(s) + // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) + _.extendOwn = _.assign = createAssigner(_.keys); + + // Returns the first key on an object that passes a predicate test + _.findKey = function(obj, predicate, context) { + predicate = cb(predicate, context); + var keys = _.keys(obj), key; + for (var i = 0, length = keys.length; i < length; i++) { + key = keys[i]; + if (predicate(obj[key], key, obj)) return key; + } + }; + + // Return a copy of the object only containing the whitelisted properties. + _.pick = function(object, oiteratee, context) { + var result = {}, obj = object, iteratee, keys; + if (obj == null) return result; + if (_.isFunction(oiteratee)) { + keys = _.allKeys(obj); + iteratee = optimizeCb(oiteratee, context); + } else { + keys = flatten(arguments, false, false, 1); + iteratee = function(value, key, obj) { return key in obj; }; + obj = Object(obj); + } + for (var i = 0, length = keys.length; i < length; i++) { + var key = keys[i]; + var value = obj[key]; + if (iteratee(value, key, obj)) result[key] = value; + } + return result; + }; + + // Return a copy of the object without the blacklisted properties. + _.omit = function(obj, iteratee, context) { + if (_.isFunction(iteratee)) { + iteratee = _.negate(iteratee); + } else { + var keys = _.map(flatten(arguments, false, false, 1), String); + iteratee = function(value, key) { + return !_.contains(keys, key); + }; + } + return _.pick(obj, iteratee, context); + }; + + // Fill in a given object with default properties. + _.defaults = createAssigner(_.allKeys, true); + + // Creates an object that inherits from the given prototype object. + // If additional properties are provided then they will be added to the + // created object. + _.create = function(prototype, props) { + var result = baseCreate(prototype); + if (props) _.extendOwn(result, props); + return result; + }; + + // Create a (shallow-cloned) duplicate of an object. + _.clone = function(obj) { + if (!_.isObject(obj)) return obj; + return _.isArray(obj) ? obj.slice() : _.extend({}, obj); + }; + + // Invokes interceptor with the obj, and then returns obj. + // The primary purpose of this method is to "tap into" a method chain, in + // order to perform operations on intermediate results within the chain. + _.tap = function(obj, interceptor) { + interceptor(obj); + return obj; + }; + + // Returns whether an object has a given set of `key:value` pairs. + _.isMatch = function(object, attrs) { + var keys = _.keys(attrs), length = keys.length; + if (object == null) return !length; + var obj = Object(object); + for (var i = 0; i < length; i++) { + var key = keys[i]; + if (attrs[key] !== obj[key] || !(key in obj)) return false; + } + return true; + }; + + + // Internal recursive comparison function for `isEqual`. + var eq = function(a, b, aStack, bStack) { + // Identical objects are equal. `0 === -0`, but they aren't identical. + // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal). + if (a === b) return a !== 0 || 1 / a === 1 / b; + // A strict comparison is necessary because `null == undefined`. + if (a == null || b == null) return a === b; + // Unwrap any wrapped objects. + if (a instanceof _) a = a._wrapped; + if (b instanceof _) b = b._wrapped; + // Compare `[[Class]]` names. + var className = toString.call(a); + if (className !== toString.call(b)) return false; + switch (className) { + // Strings, numbers, regular expressions, dates, and booleans are compared by value. + case '[object RegExp]': + // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i') + case '[object String]': + // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is + // equivalent to `new String("5")`. + return '' + a === '' + b; + case '[object Number]': + // `NaN`s are equivalent, but non-reflexive. + // Object(NaN) is equivalent to NaN + if (+a !== +a) return +b !== +b; + // An `egal` comparison is performed for other numeric values. + return +a === 0 ? 1 / +a === 1 / b : +a === +b; + case '[object Date]': + case '[object Boolean]': + // Coerce dates and booleans to numeric primitive values. Dates are compared by their + // millisecond representations. Note that invalid dates with millisecond representations + // of `NaN` are not equivalent. + return +a === +b; + } + + var areArrays = className === '[object Array]'; + if (!areArrays) { + if (typeof a != 'object' || typeof b != 'object') return false; + + // Objects with different constructors are not equivalent, but `Object`s or `Array`s + // from different frames are. + var aCtor = a.constructor, bCtor = b.constructor; + if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor && + _.isFunction(bCtor) && bCtor instanceof bCtor) + && ('constructor' in a && 'constructor' in b)) { + return false; + } + } + // Assume equality for cyclic structures. The algorithm for detecting cyclic + // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. + + // Initializing stack of traversed objects. + // It's done here since we only need them for objects and arrays comparison. + aStack = aStack || []; + bStack = bStack || []; + var length = aStack.length; + while (length--) { + // Linear search. Performance is inversely proportional to the number of + // unique nested structures. + if (aStack[length] === a) return bStack[length] === b; + } + + // Add the first object to the stack of traversed objects. + aStack.push(a); + bStack.push(b); + + // Recursively compare objects and arrays. + if (areArrays) { + // Compare array lengths to determine if a deep comparison is necessary. + length = a.length; + if (length !== b.length) return false; + // Deep compare the contents, ignoring non-numeric properties. + while (length--) { + if (!eq(a[length], b[length], aStack, bStack)) return false; + } + } else { + // Deep compare objects. + var keys = _.keys(a), key; + length = keys.length; + // Ensure that both objects contain the same number of properties before comparing deep equality. + if (_.keys(b).length !== length) return false; + while (length--) { + // Deep compare each member + key = keys[length]; + if (!(_.has(b, key) && eq(a[key], b[key], aStack, bStack))) return false; + } + } + // Remove the first object from the stack of traversed objects. + aStack.pop(); + bStack.pop(); + return true; + }; + + // Perform a deep comparison to check if two objects are equal. + _.isEqual = function(a, b) { + return eq(a, b); + }; + + // Is a given array, string, or object empty? + // An "empty" object has no enumerable own-properties. + _.isEmpty = function(obj) { + if (obj == null) return true; + if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0; + return _.keys(obj).length === 0; + }; + + // Is a given value a DOM element? + _.isElement = function(obj) { + return !!(obj && obj.nodeType === 1); + }; + + // Is a given value an array? + // Delegates to ECMA5's native Array.isArray + _.isArray = nativeIsArray || function(obj) { + return toString.call(obj) === '[object Array]'; + }; + + // Is a given variable an object? + _.isObject = function(obj) { + var type = typeof obj; + return type === 'function' || type === 'object' && !!obj; + }; + + // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError. + _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function(name) { + _['is' + name] = function(obj) { + return toString.call(obj) === '[object ' + name + ']'; + }; + }); + + // Define a fallback version of the method in browsers (ahem, IE < 9), where + // there isn't any inspectable "Arguments" type. + if (!_.isArguments(arguments)) { + _.isArguments = function(obj) { + return _.has(obj, 'callee'); + }; + } + + // Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8, + // IE 11 (#1621), and in Safari 8 (#1929). + if (typeof /./ != 'function' && typeof Int8Array != 'object') { + _.isFunction = function(obj) { + return typeof obj == 'function' || false; + }; + } + + // Is a given object a finite number? + _.isFinite = function(obj) { + return isFinite(obj) && !isNaN(parseFloat(obj)); + }; + + // Is the given value `NaN`? (NaN is the only number which does not equal itself). + _.isNaN = function(obj) { + return _.isNumber(obj) && obj !== +obj; + }; + + // Is a given value a boolean? + _.isBoolean = function(obj) { + return obj === true || obj === false || toString.call(obj) === '[object Boolean]'; + }; + + // Is a given value equal to null? + _.isNull = function(obj) { + return obj === null; + }; + + // Is a given variable undefined? + _.isUndefined = function(obj) { + return obj === void 0; + }; + + // Shortcut function for checking if an object has a given property directly + // on itself (in other words, not on a prototype). + _.has = function(obj, key) { + return obj != null && hasOwnProperty.call(obj, key); + }; + + // Utility Functions + // ----------------- + + // Run Underscore.js in *noConflict* mode, returning the `_` variable to its + // previous owner. Returns a reference to the Underscore object. + _.noConflict = function() { + root._ = previousUnderscore; + return this; + }; + + // Keep the identity function around for default iteratees. + _.identity = function(value) { + return value; + }; + + // Predicate-generating functions. Often useful outside of Underscore. + _.constant = function(value) { + return function() { + return value; + }; + }; + + _.noop = function(){}; + + _.property = property; + + // Generates a function for a given object that returns a given property. + _.propertyOf = function(obj) { + return obj == null ? function(){} : function(key) { + return obj[key]; + }; + }; + + // Returns a predicate for checking whether an object has a given set of + // `key:value` pairs. + _.matcher = _.matches = function(attrs) { + attrs = _.extendOwn({}, attrs); + return function(obj) { + return _.isMatch(obj, attrs); + }; + }; + + // Run a function **n** times. + _.times = function(n, iteratee, context) { + var accum = Array(Math.max(0, n)); + iteratee = optimizeCb(iteratee, context, 1); + for (var i = 0; i < n; i++) accum[i] = iteratee(i); + return accum; + }; + + // Return a random integer between min and max (inclusive). + _.random = function(min, max) { + if (max == null) { + max = min; + min = 0; + } + return min + Math.floor(Math.random() * (max - min + 1)); + }; + + // A (possibly faster) way to get the current timestamp as an integer. + _.now = Date.now || function() { + return new Date().getTime(); + }; + + // List of HTML entities for escaping. + var escapeMap = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '`': '`' + }; + var unescapeMap = _.invert(escapeMap); + + // Functions for escaping and unescaping strings to/from HTML interpolation. + var createEscaper = function(map) { + var escaper = function(match) { + return map[match]; + }; + // Regexes for identifying a key that needs to be escaped + var source = '(?:' + _.keys(map).join('|') + ')'; + var testRegexp = RegExp(source); + var replaceRegexp = RegExp(source, 'g'); + return function(string) { + string = string == null ? '' : '' + string; + return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string; + }; + }; + _.escape = createEscaper(escapeMap); + _.unescape = createEscaper(unescapeMap); + + // If the value of the named `property` is a function then invoke it with the + // `object` as context; otherwise, return it. + _.result = function(object, property, fallback) { + var value = object == null ? void 0 : object[property]; + if (value === void 0) { + value = fallback; + } + return _.isFunction(value) ? value.call(object) : value; + }; + + // Generate a unique integer id (unique within the entire client session). + // Useful for temporary DOM ids. + var idCounter = 0; + _.uniqueId = function(prefix) { + var id = ++idCounter + ''; + return prefix ? prefix + id : id; + }; + + // By default, Underscore uses ERB-style template delimiters, change the + // following template settings to use alternative delimiters. + _.templateSettings = { + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g + }; + + // When customizing `templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /(.)^/; + + // Certain characters need to be escaped so that they can be put into a + // string literal. + var escapes = { + "'": "'", + '\\': '\\', + '\r': 'r', + '\n': 'n', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + var escaper = /\\|'|\r|\n|\u2028|\u2029/g; + + var escapeChar = function(match) { + return '\\' + escapes[match]; + }; + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + // NB: `oldSettings` only exists for backwards compatibility. + _.template = function(text, settings, oldSettings) { + if (!settings && oldSettings) settings = oldSettings; + settings = _.defaults({}, settings, _.templateSettings); + + // Combine delimiters into one regular expression via alternation. + var matcher = RegExp([ + (settings.escape || noMatch).source, + (settings.interpolate || noMatch).source, + (settings.evaluate || noMatch).source + ].join('|') + '|$', 'g'); + + // Compile the template source, escaping string literals appropriately. + var index = 0; + var source = "__p+='"; + text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { + source += text.slice(index, offset).replace(escaper, escapeChar); + index = offset + match.length; + + if (escape) { + source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; + } else if (interpolate) { + source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; + } else if (evaluate) { + source += "';\n" + evaluate + "\n__p+='"; + } + + // Adobe VMs need the match returned to produce the correct offest. + return match; + }); + source += "';\n"; + + // If a variable is not specified, place data values in local scope. + if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; + + source = "var __t,__p='',__j=Array.prototype.join," + + "print=function(){__p+=__j.call(arguments,'');};\n" + + source + 'return __p;\n'; + + try { + var render = new Function(settings.variable || 'obj', '_', source); + } catch (e) { + e.source = source; + throw e; + } + + var template = function(data) { + return render.call(this, data, _); + }; + + // Provide the compiled source as a convenience for precompilation. + var argument = settings.variable || 'obj'; + template.source = 'function(' + argument + '){\n' + source + '}'; + + return template; + }; + + // Add a "chain" function. Start chaining a wrapped Underscore object. + _.chain = function(obj) { + var instance = _(obj); + instance._chain = true; + return instance; + }; + + // OOP + // --------------- + // If Underscore is called as a function, it returns a wrapped object that + // can be used OO-style. This wrapper holds altered versions of all the + // underscore functions. Wrapped objects may be chained. + + // Helper function to continue chaining intermediate results. + var result = function(instance, obj) { + return instance._chain ? _(obj).chain() : obj; + }; + + // Add your own custom functions to the Underscore object. + _.mixin = function(obj) { + _.each(_.functions(obj), function(name) { + var func = _[name] = obj[name]; + _.prototype[name] = function() { + var args = [this._wrapped]; + push.apply(args, arguments); + return result(this, func.apply(_, args)); + }; + }); + }; + + // Add all of the Underscore functions to the wrapper object. + _.mixin(_); + + // Add all mutator Array functions to the wrapper. + _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { + var method = ArrayProto[name]; + _.prototype[name] = function() { + var obj = this._wrapped; + method.apply(obj, arguments); + if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0]; + return result(this, obj); + }; + }); + + // Add all accessor Array functions to the wrapper. + _.each(['concat', 'join', 'slice'], function(name) { + var method = ArrayProto[name]; + _.prototype[name] = function() { + return result(this, method.apply(this._wrapped, arguments)); + }; + }); + + // Extracts the result from a wrapped and chained object. + _.prototype.value = function() { + return this._wrapped; + }; + + // Provide unwrapping proxy for some methods used in engine operations + // such as arithmetic and JSON stringification. + _.prototype.valueOf = _.prototype.toJSON = _.prototype.value; + + _.prototype.toString = function() { + return '' + this._wrapped; + }; + + // AMD registration happens at the end for compatibility with AMD loaders + // that may not enforce next-turn semantics on modules. Even though general + // practice for AMD registration is to be anonymous, underscore registers + // as a named module because, like jQuery, it is a base library that is + // popular enough to be bundled in a third party lib, but not be part of + // an AMD load request. Those cases could generate an error when an + // anonymous define() is called outside of a loader request. + if (typeof define === 'function' && define.amd) { + define('underscore', [], function() { + return _; + }); + } +}.call(this)); + +},{}],42:[function(require,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +var xapiErrorLevels = Object.freeze({ + MAY_VIOLATION: 'MAY_VIOLATION', + MUST_VIOLATION: 'MUST_VIOLATION', + SHOULD_VIOLATION: 'SHOULD_VIOLATION' +}); + +var xapiValidationErrors = Object.freeze({ + ACTIVITIES_MUST_NOT_BE_NULL_MAP_OBJECTS: 'Activities must be non-null map objects', + ACTOR_MUST_BE_PROVIDED: 'Actor must be provided.', + AGENT_IFI_PROPERTIES_MUST_BE_SPECIFIED: 'Exactly one Inverse Functional Identifier property must be specified for an "agent".', + AGENT_MUST_BE_NON_NULL_MAP_OBJECT: '"agent" must be a non-null map object', + AGENT_MUST_NOT_HAVE_GROUP_CHARACTERISTICS: 'Invalid object with characteristics of a Group when an Agent was expected.', + ATTACHMENTS_MUST_BE_NOT_NULL_ARRAY: '"attachments" must be a non-null Array.', + ATTACHMENTS_MUST_NOT_BE_NULL_MAP_OBJECTS: '"attachment" instances must be non-null map objects.', + AUTHORITY_MUST_BE_NON_NULL_MAP_OBJECT: 'If present, the "authority" property must be a non-null map object.', + CONTEXT_ACTIVITIES_MUST_BE_ARRAY_OR_ACTIVITY_OBJ: 'Context Activities property values must be an array of Activity Objects or a single Activity Object.', + CONTEXT_ACTIVITIES_MUST_BE_NON_NULL_MAP_OBJECT: 'The Context Activities instances must be a non-null map object.', + CONTEXT_ACTIVITIES_MUST_NOT_BE_NULL: '"Context Activities" property values must not be null.', + CONTEXT_ACTIVITIES_SHOULD_BE_AN_ARRAY: 'Context Activities property values should prefer to be an array of Activities rather than a single Activity object.', + CONTEXT_MUST_BE_NON_NUL_MAP_OBJECT: 'If present, the "context" property must be a non-null map object.', + CORRECT_RESPONSES_PATTERN_MUST_BE_ARRAY: 'If present, the "correctResponsesPattern" value must be an Array of strings.', + CORRECT_RESPONSES_PATTERN_MUST_BE_STRINGS: '"correctResponsesPattern" items must be strings.', + DATE_MUST_BE_VALID: 'This propertys string value must be conformant to ISO 8601 for Date Times.', + DATE_SHOULD_INCLUDE_ZONE_INFORMATION: 'ISO 8601 date time strings used in the xAPI should include time zone information.', + DEFINITIONS_MUST_BE_OBJECTS: '"definitions", when present, must be map objects', + DISPLAY_SHOULD_BE_PROVIDED: '"display" property should be provided.', + DURATION_MUST_BE_VALID: 'If present, the "duration" property value must be an ISO 8601 duration', + EXTENSIONS_MUST_NOT_BE_NULL: 'If present, the extensions property must be a non-null map object.', + GROUP_AUTHORITY_AGENT_MEMBERS_MUST_BE_TWO: 'If used as a Group, the "authority" property must contain a "member" property that is an array containing exactly two Agent objects.', + GROUP_IFI_PROPERTIES_MUST_BE_SPECIFIED: 'Exactly one Inverse Functional Identifier property must be specified for a "group".', + GROUP_MEMBER_MUST_BE_ARRAY: 'If present, the member property of a Group must be an Array', + GROUP_MUST_BE_NON_NULL_MAP_OBJECT: '"group" must be a non-null map object', + ID_MUST_BE_UNIQUE: '"id" properties must be unique within each interaction component array', + ID_MUST_BE_VALID_UUID_REF: '"id" property value must be a valid UUID string for statement reference objects.', + ID_MUST_BE_VALID: 'Id was not a valid UUID', + ID_SHOULD_NOT_CONTAIN_WHITESPACES: '"id" properties on interaction components should not contain whitespace', + IDS_SHOULD_BE_GENERATED_BY_LRS: 'Ids should be generated by the Activity Provider, and must be generated by the LRS', + IFI_MUST_BE_MBOX_URI: '"mbox" property was required to be a mailto URI string but was not a string at all.', + IFI_MUST_BE_VALID_MBOX_FORMAT: '"mbox" property was required to be a mailto URI string but did not match the mailto format.', + INTERACTION_ACTIVITY_SHOULD_HAVE: 'Interaction Activity Definitions should have a type property of', + INTERACTION_COMPONENT_MUST_NOT_BE_NULL: 'This interaction component collection member must be a non-null map object', + INTERACTION_COMPONENT_SHOULD_BE_ARRAY: 'This interaction component collection property should be an array.', + INTERACTION_TYPE_MUST_BE_CMI: 'If present, the "interactionType" value must be a CMI interaction type option.', + INTERACTION_TYPE_MUST_BE_VALID: 'This interaction component collection property is not associated with the present interactionType of: ', + INVALID_JSON: 'Invalid JSON. The statement could not be parsed.', + LANGUAGE_MAP_KEY_INVALID: 'key, Language does not conform to RFC 5646', + LANGUAGE_MAP_KEY_MUST_BE_STRING: 'key: Language Map value should be a String, but was not', + LANGUAGE_MAPS_MUST_NOT_BE_NULL: 'Language Maps, when present, must be non-null map objects', + LANGUAGE_MUST_BE_STRING: 'The language property must be encoded as an RFC 5646 compliant string, but was not.', + LENGTH_MUST_BE_INTEGER: '"length" property must be provided with an integer value', + MAX_MUST_BE_GREATER_THAN_MIN: 'If both "max" and "min" are present, the max property value should be greater than min', + MEMBER_MUST_BE_PROVIDED_FOR_ANONYMOUS_GROUPS: '"member" property must be provided for Anonymous Groups.', + MUST_BE_BOOLEAN_PRESENT: 'property was required to be a Boolean but was absent.', + MUST_BE_BOOLEAN: 'property, if present, must be a Boolean.', + MUST_BE_IRI_STRING: 'property, if present, should be a IRI-like absolute URI per RFC 3987.', + MUST_BE_NUMBER_PRESENT: 'property was required to be a Number but was absent.', + MUST_BE_NUMBER: 'property, if present, must be a Number.', + MUST_BE_PRESENT: 'property was required to be a string but was absent.', + MUST_BE_STRING: 'property, if present, must be a string.', + MUST_BE_URI_PRESENT: 'property was required to be a URI string but was absent.', + MUST_BE_URI_STRING: 'property, if present, must be a URI string.', + OBJECT_MUST_BE_DEFINED: '"object" property must be provided.', + OBJECT_MUST_BE_NON_NULL_MAP_OBJECT: '"object" property must be a non-null map object.', + OBJECT_TYPE_MUST_BE_STATEMENT_REF: '"objectType" property value must be "StatementRef" for statement reference objects.', + OBJECT_TYPE_MUST_BE_VALID_OPTION: 'object\'s "objectType" did not match a valid option', + RAW_MUST_BE_GREATER_THAN_MIN: 'If both "raw" and "min" are present, the raw property value should be greater than min', + RAW_MUST_BE_LESS_THAN_MAX: 'If both "raw" and "max" are present, the raw property value should be less than max', + REGISTRATION_MUST_BE_UUID_STRING: 'If present, the registration property must be a UUID string.', + RESULT_MUST_BE_MAP_OBJECT: 'If present, the result must be a map object', + REVISION_MUST_BE_AGENT_OR_GROUP: 'The revision property must not be used if the Statement\'s Object is an Agent or Group.', + SCALED_MUST_BE_BETWEEN_0_1: 'If present, the scaled property value must be between 0 and 1', + SHA2_MUST_BE_PROVIDED_ON_ATTACHMENT_OBJECTS: '"sha2" property must be provided on attachment objects', + SHA2_MUST_CONTAIN_BASE_64_STRING: '"sha2" property must contain a string with base64 contents', + STATEMENT_ARGUMENT_IS_NOT_VALID: 'Statement argument provided was not a valid object or a valid JSON string.', + STATEMENT_ARGUMENT_MUST_BE_PROVIDED: 'No statement argument provided.', + STATEMENT_MUST_BE_PARSED_CORRECTLY: 'Null or non-object statement value parsed from provided statment JSON.', + STATEMENT_MUST_NOT_BE_NULL: 'Null statement argument provided.', + STATEMENT_REF_MUST_NOT_BE_NULL_MAP_OBJECTS: 'StatementRef instances must be non-null map objects', + SUB_STATEMENT_MUST_NOT_CONTAIN_SUB_STATEMENT: 'A SubStatement must not contain a SubStatement', + UNEXPECTED: 'Unexpected property not permitted', + VERB_MUST_BE_PROVIDED: 'Verb must be provided', + VERB_MUST_NOT_BE_NULL: 'Verb property value must a non-null map object.', + VERSION_MUST_COMPLY_SEMANTIC_VERSIONING: '"version" must be a non-null string that complies with Semantic Versioning 1.0.0' +}); + +exports.xapiErrorLevels = xapiErrorLevels; +exports.xapiValidationErrors = xapiValidationErrors; + +},{}],43:[function(require,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +var xapiGeneral = Object.freeze({ + FIRST_REPORT_VERSTION: '1.0.0', + GROUP_AUTHORITY_AGENT_MEMBERS: 2, + INTERACTION_DEFINITION_TYPE: 'http://adlnet.gov/expapi/activities/cmi.interaction', + MAX_SCALED_VALUE: 1, + MIN_SCALED_VALUE: 0, + NO_INDEX_FOUND: -1, + NUMER_OF_SPECIFIED_IFI_PROPERTIES: 1 +}); + +exports.xapiGeneral = xapiGeneral; + +},{}],44:[function(require,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +var interactionTypes = exports.interactionTypes = Object.freeze({ + CHOICE: 'choice', + FILL_IN: 'fill-in', + LIKERT: 'likert', + LONG_FILL_IN: 'long-fill-in', + MATCHING: 'matching', + NUMERIC: 'numeric', + OTHER: 'other', + PERFORMANCE: 'performance', + SEQUENCING: 'sequencing', + TRUE_FALSE: 'true-false' +}); + +var xapiValidationInteractionTypes = exports.xapiValidationInteractionTypes = Object.freeze([interactionTypes.CHOICE, interactionTypes.FILL_IN, interactionTypes.LIKERT, interactionTypes.LONG_FILL_IN, interactionTypes.MATCHING, interactionTypes.NUMERIC, interactionTypes.OTHER, interactionTypes.PERFORMANCE, interactionTypes.SEQUENCING, interactionTypes.TRUE_FALSE]); + +},{}],45:[function(require,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +var properties = Object.freeze({ + ACCOUNT: 'account', + ACTIVITY: 'activity', + ACTOR: 'actor', + AGENT: 'agent', + ATTACHMENT: 'attachment', + ATTACHMENTS: 'attachments', + AUTHORITY: 'authority', + CATEGORY: 'category', + CHOICE: 'choice', + CHOICES: 'choices', + COMPLETION: 'completion', + CONTENT_TYPE: 'contentType', + CONTEXT_ACTIVITIES: 'contextActivities', + CONTEXT: 'context', + CORRECT_RESPONSES_PATTERN: 'correctResponsesPattern', + DATE_TIME: 'dateTime', + DEFINITION: 'definition', + DESCRIPTION: 'description', + DISPLAY: 'display', + DURATION: 'duration', + EXTENSIONS: 'extensions', + FILE_URL: 'fileUrl', + GROUP: 'group', + GROUPING: 'grouping', + HOME_PAGE: 'homePage', + ID: 'id', + INSTRUCTOR: 'instructor', + INTERACTION_COMPONENTS: 'interactionComponents', + INTERACTION_TYPE: 'interactionType', + LANGUAGE_MAP: 'languageMap', + LANGUAGE: 'language', + LENGTH: 'length', + LIKERT: 'likert', + MATCHING: 'matching', + MAX: 'max', + MBOX_SHA_1_SUM: 'mbox_sha1sum', + MBOX: 'mbox', + MEMBER: 'member', + MIN: 'min', + MORE_INFO: 'moreInfo', + NAME: 'name', + OBJECT_TYPE: 'objectType', + OBJECT: 'object', + OPEN_ID: 'openID', + OTHER: 'other', + PARENT: 'parent', + PERFORMANCE: 'performance', + PLATFORM: 'platform', + RAW: 'raw', + REGISTRATION: 'registration', + RESPONSE: 'response', + RESULT: 'result', + REVISION: 'revision', + SCALE: 'scale', + SCALED: 'scaled', + SCORE: 'score', + SEQUENCING: 'sequencing', + SHA2: 'sha2', + SOURCE: 'source', + STATEMENT_REF: 'statementRef', + STATEMENT: 'statement', + STEPS: 'steps', + STORED: 'stored', + SUB_CONTEXT: 'subContext', + SUCCESS: 'success', + TARGET: 'target', + TEAM: 'team', + TIMESTAMP: 'timestamp', + TYPE: 'type', + USAGE_TYPE: 'usageType', + VERB: 'verb', + VERSION: 'version' +}); + +var objectTypes = Object.freeze({ + GROUP: 'Group', + AGENT: 'Agent', + ACTIVITY: 'Activity', + STATEMENT_REF: 'StatementRef', + SUB_STATEMENT: 'SubStatement' +}); + +var xapiValidationIfiPropertyNames = Object.freeze([properties.ACCOUNT, properties.MBOX_SHA_1_SUM, properties.MBOX, properties.OPEN_ID]); + +var xApiValidObjectTypes = Object.freeze([objectTypes.GROUP, objectTypes.AGENT, objectTypes.ACTIVITY, objectTypes.STATEMENT_REF, objectTypes.SUB_STATEMENT]); + +var xapiWhiteListProperties = Object.freeze({ + IFI: [properties.HOME_PAGE, properties.NAME], + URI: [properties.ID, properties.DISPLAY], + COMPONENT_ARRAY: [properties.ID, properties.DESCRIPTION], + ACTIVITY_DEFINITION: [properties.NAME, properties.DESCRIPTION, properties.TYPE, properties.MORE_INFO, properties.EXTENSIONS, properties.INTERACTION_TYPE, properties.CORRECT_RESPONSES_PATTERN, properties.CHOICES, properties.SCALE, properties.SOURCE, properties.TARGET, properties.STEPS], + ACTIVITY: [properties.OBJECT_TYPE, properties.ID, properties.DEFINITION], + STATEMENT_REF: [properties.ID, properties.OBJECT_TYPE], + SCORE: [properties.SCALED, properties.RAW, properties.MIN, properties.MAX], + RESULT: [properties.SCORE, properties.SUCCESS, properties.COMPLETION, properties.RESPONSE, properties.DURATION, properties.EXTENSIONS], + ATTACHMENT: [properties.USAGE_TYPE, properties.DISPLAY, properties.DESCRIPTION, properties.CONTENT_TYPE, properties.LENGTH, properties.SHA2, properties.FILE_URL], + AGENT: [properties.OBJECT_TYPE, properties.NAME, properties.ACCOUNT, properties.MBOX_SHA_1_SUM, properties.MBOX, properties.OPEN_ID], + GROUP: [properties.OBJECT_TYPE, properties.NAME, properties.MEMBER, properties.ACCOUNT, properties.MBOX_SHA_1_SUM, properties.MBOX, properties.OPEN_ID], + CONTEXT_ACTIVITIES: [properties.PARENT, properties.GROUPING, properties.CATEGORY, properties.OTHER], + STATEMENT: [properties.ID, properties.ACTOR, properties.VERB, properties.OBJECT, properties.RESULT, properties.CONTEXT, properties.TIMESTAMP, properties.STORED, properties.AUTHORITY, properties.VERSION, properties.ATTACHMENTS], + SUB_STATEMENT: [properties.ACTOR, properties.VERB, properties.OBJECT, properties.RESULT, properties.CONTEXT, properties.TIMESTAMP, properties.ATTACHMENTS, properties.OBJECT_TYPE], + EXTENSIONS: [properties.REGISTRATION, properties.INSTRUCTOR, properties.TEAM, properties.CONTEXT_ACTIVITIES, properties.REVISION, properties.PLATFORM, properties.LANGUAGE, properties.STATEMENT, properties.EXTENSIONS] +}); + +exports.properties = properties; +exports.objectTypes = objectTypes; +exports.xapiValidationIfiPropertyNames = xapiValidationIfiPropertyNames; +exports.xApiValidObjectTypes = xApiValidObjectTypes; +exports.xapiWhiteListProperties = xapiWhiteListProperties; + +},{}],46:[function(require,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +var xapiValidationRegex = Object.freeze({ + UUID: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i, + ISO_8601_DURATION: /^P((\d+([\.,]\d+)?Y)?(\d+([\.,]\d+)?M)?(\d+([\.,]\d+)?W)?(\d+([\.,]\d+)?D)?)?(T(\d+([\.,]\d+)?H)?(\d+([\.,]\d+)?M)?(\d+([\.,]\d+)?S)?)?$/, + ISO_8601_DATE_TIME: /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/, + MAILTO_URI: /^mailto:/, + CONTAINS_WHITESPACE: /\s/g, + SEMVER_1_P_0_P_0: /^((\d+)\.(\d+)\.(\d+))(?:-([\dA-Za-z\-]+))?$/, + BASE_64: /^(?:[A-Za-z0-9\+\/]{4})*(?:[A-Za-z0-9\+\/]{2}==|[A-Za-z0-9\+\/]{3}=|[A-Za-z0-9\+\/]{4})$/, + IRI: /^[a-z](?:[\-a-z0-9\+\.])*:(?:\/\/(?:(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:])*@)?(?:\[(?:(?:(?:[0-9a-f]{1,4}:){6}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|::(?:[0-9a-f]{1,4}:){5}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:[0-9a-f]{1,4}:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+[\-a-z0-9\._~!\$&'\(\)\*\+,;=:]+)\]|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}|(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=@])*)(?::[0-9]*)?(?:\/(?:(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@]))*)*|\/(?:(?:(?:(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@]))+)(?:\/(?:(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@]))*)*)?|(?:(?:(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@]))+)(?:\/(?:(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@]))*)*|(?!(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@])))(?:\?(?:(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@])|[\uE000-\uF8FF\uF0000-\uFFFFD|\u100000-\u10FFFD\/\?])*)?(?:\#(?:(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@])|[\/\?])*)?$/i, + BCP_47: /^(?:(en-GB-oed|i-(?:ami|bnn|default|enochian|hak|klingon|lux|mingo|navajo|pwn|tao|tay|tsu)|sgn-(?:BE-FR|BE-NL|CH-DE))|(art-lojban|cel-gaulish|no-(?:bok|nyn)|zh-(?:guoyu|hakka|min|min-nan|xiang)))$|^(x(?:-[0-9a-z]{1,8})+)$|^(?:((?:[a-z]{2,3}(?:(?:-[a-z]{3}){1,3})?)|[a-z]{4}|[a-z]{5,8})(?:-([a-z]{4}))?(?:-([a-z]{2}|[0-9]{3}))?((?:-(?:[a-z0-9]{5,8}|[0-9][a-z0-9]{3}))*)?((?:-[0-9a-wy-z](?:-[a-z0-9]{2,8}){1,})*)?(-x(?:-[0-9a-z]{1,8})+)?)$/i +}); + +var dateFormatRegexPositions = Object.freeze({ + YEAR: 1, + MONTH: 2, + DAY: 3, + HOUR: 4, + MINUTE: 5, + SECOND: 6, + MSECOND: 7, + ZONE: 8, + RELATIVE_TIME: 9, + TIME_ZONE_HOUR: 10, + TIME_ZONE_MINUTE: 11 +}); + +exports.xapiValidationRegex = xapiValidationRegex; +exports.dateFormatRegexPositions = dateFormatRegexPositions; + +},{}],47:[function(require,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +var IS_STRING = '[object String]', + IS_ARRAY = '[object Array]', + IS_BOOLEAN = '[object Boolean]', + IS_NUMBER = '[object Number]'; + +var toString = Object.prototype.toString; +var xapiValidationUtils; + +exports.xapiValidationUtils = xapiValidationUtils = { + isString: function isString(obj) { + return toString.call(obj) === IS_STRING; + }, + isObject: function isObject(obj) { + return obj === Object(obj); + }, + + + isArray: Array.isArray || function (obj) { + return toString.call(obj) === IS_ARRAY; + }, + + isBoolean: function isBoolean(obj) { + return obj === true || obj === false || toString.call(obj) === IS_BOOLEAN; + }, + isNumber: function isNumber(obj) { + return toString.call(obj) === IS_NUMBER; + }, + isDefined: function isDefined(obj) { + return obj !== null || obj !== undefined; + }, + isNonNullMapObject: function isNonNullMapObject(target) { + return this.isDefined(target) && this.isObject(target) && !this.isArray(target); + }, + isValidLanguageTag: function isValidLanguageTag(target, validLanguageRegex) { + // TODO - use more precise 5646 handling, rather than this simplified BCP 47 regex, which combines RFC 5646 and RFC 4647. + // return this.isDefined(target) && this.isString(target) && xapiValidationRegex.BCP_47.test(target); + return this.isDefined(target) && this.isString(target) && validLanguageRegex.test(target); + }, + addPropToTrace: function addPropToTrace(trace, addendum) { + return this.isDefined(addendum) ? trace + '.' + addendum : trace; + }, + addLookupToTrace: function addLookupToTrace(trace, key) { + return !this.isDefined(key) ? trace : this.isNumber(key) ? trace + '[' + key + ']' : trace + '["' + key + '"]'; + }, + localTraceToString: function localTraceToString(trace, addendum) { + return this.addPropToTrace(trace, addendum); + }, + isGroup: function isGroup(actorOrGroup, groupType) { + // return (actorOrGroup.member !== null && actorOrGroup.member !== undefined) || actorOrGroup.objectType === objectTypes.GROUP; + return actorOrGroup.member !== null && actorOrGroup.member !== undefined || actorOrGroup.objectType === groupType; + } +}; + +exports.xapiValidationUtils = xapiValidationUtils; + +},{}],48:[function(require,module,exports){ +'use strict'; + +var _properties = require('./constants/properties'); + +var _errors = require('./constants/errors'); + +var _interactionTypes = require('./constants/interaction-types'); + +var _regex = require('./constants/regex'); + +var _general = require('./constants/general'); + +var _utils = require('./utils/utils'); + +var xapiValidation; + +function makeV1Report(instance, errors) { + var version; + + instance = instance || null; + errors = errors || null; + version = _general.xapiGeneral.FIRST_REPORT_VERSTION; + return { instance: instance, errors: errors, version: version }; +} + +function makeV1SingleErrorReport(instance, error) { + return makeV1Report(instance, error === null || error === undefined ? [] : [error]); +} + +function validateAbsenceOfNonWhitelistedProperties(target, allowedProperties, trace, errors) { + var localErrors, localTrace, propertyName; + + localErrors = errors || []; + localTrace = trace || ''; + + for (propertyName in target) { + if (target.hasOwnProperty(propertyName) && allowedProperties.indexOf(propertyName) === _general.xapiGeneral.NO_INDEX_FOUND) { + localErrors.push({ + trace: _utils.xapiValidationUtils.addPropToTrace(localTrace, propertyName), + message: _errors.xapiValidationErrors.UNEXPECTED, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + } + + return localErrors; +} + +function validatePropertyIsString(parent, propertyName, trace, errors, isRequired, violationType) { + var localErrors, localTrace, propValue, localViolationType; + + localErrors = errors || []; + localTrace = trace || ''; + propValue = parent[propertyName], localViolationType = violationType || _errors.xapiErrorLevels.MUST_VIOLATION; + + if (propValue !== undefined) { + if (propValue === null || !_utils.xapiValidationUtils.isString(propValue)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, propertyName), + message: propertyName + ' ' + _errors.xapiValidationErrors.MUST_BE_STRING, + level: localViolationType + }); + } + } else if (isRequired) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, propertyName), + message: propertyName + ' ' + _errors.xapiValidationErrors.MUST_BE_PRESENT, + level: localViolationType + }); + } + + return localErrors; +} + +function validatePropertyIsUri(target, propertyName, trace, errors, isRequired) { + var localErrors, localTrace, propValue; + + localErrors = errors || []; + localTrace = trace || ''; + propValue = target[propertyName]; + + if (propValue !== undefined) { + if (propValue === null || !_utils.xapiValidationUtils.isString(propValue)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, propertyName), + message: propertyName + ' ' + _errors.xapiValidationErrors.MUST_BE_URI_STRING, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } else if (!_regex.xapiValidationRegex.IRI.test(propValue)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, propertyName), + message: propertyName + ' ' + _errors.xapiValidationErrors.MUST_BE_IRI_STRING, + level: _errors.xapiErrorLevels.SHOULD_VIOLATION + }); + } + } else if (isRequired) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, propertyName), + message: propertyName + ' ' + _errors.xapiValidationErrors.MUST_BE_URI_PRESENT, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + return localErrors; +} + +function validatePropertyIsUrl(target, propertyName, trace, errors, isRequired) { + // TODO - check whether a formal URL format definition is recommended/enforced for xAPI + return validatePropertyIsString(target, propertyName, trace, errors, isRequired); +} + +function validatePropertyIsBoolean(parent, propertyName, trace, errors, isRequired) { + var localErrors, localTrace, propValue; + + localErrors = errors || []; + localTrace = trace || ''; + propValue = parent[propertyName]; + + if (propValue !== undefined) { + if (propValue === null || !_utils.xapiValidationUtils.isBoolean(propValue)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, propertyName), + message: propertyName + ' ' + _errors.xapiValidationErrors.MUST_BE_BOOLEAN, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + } else if (isRequired) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, propertyName), + message: propertyName + ' ' + _errors.xapiValidationErrors.MUST_BE_BOOLEAN_PRESENT, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + return localErrors; +} + +function validatePropertyIsNumber(parent, propertyName, trace, errors, isRequired) { + var localErrors, localTrace, propValue; + + localErrors = errors || []; + localTrace = trace || ''; + propValue = parent[propertyName]; + + if (propValue !== undefined) { + if (propValue === null || !_utils.xapiValidationUtils.isNumber(propValue)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, propertyName), + message: propertyName + ' ' + _errors.xapiValidationErrors.MUST_BE_NUMBER, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + } else if (isRequired) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, propertyName), + message: propertyName + ' ' + _errors.xapiValidationErrors.MUST_BE_NUMBER_PRESENT, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + return localErrors; +} + +function validateIFIProperties(target, trace, errors) { + var localErrors, localTrace, accountTrace; + + localErrors = errors || []; + localTrace = trace || ''; + + if (target.mbox !== undefined && target.mbox !== null) { + if (!_utils.xapiValidationUtils.isString(target.mbox)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, _properties.properties.MBOX), + message: _errors.xapiValidationErrors.IFI_MUST_BE_MBOX_URI, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } else if (!_regex.xapiValidationRegex.MAILTO_URI.test(target.mbox)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, _properties.properties.MBOX), + message: _errors.xapiValidationErrors.IFI_MUST_BE_VALID_MBOX_FORMAT, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + } + + validatePropertyIsString(target, _properties.properties.MBOX_SHA_1_SUM, localTrace, localErrors, /*isRequired*/false); + validatePropertyIsUri(target, _properties.properties.OPEN_ID, localTrace, localErrors, /*isRequired*/false); + + if (target.account !== undefined && target.account !== null) { + accountTrace = _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.ACCOUNT); + validatePropertyIsUri(target.account, _properties.properties.HOME_PAGE, accountTrace, localErrors, /*isRequired*/true); + validatePropertyIsString(target.account, _properties.properties.NAME, accountTrace, localErrors, /*isRequired*/true); + validateAbsenceOfNonWhitelistedProperties(target.account, _properties.xapiWhiteListProperties.IFI, accountTrace, localErrors); + } + + return localErrors; +} + +function getIFIs(target) { + var ifis; + + if (target === null || target === undefined) { + return []; + } + + ifis = _properties.xapiValidationIfiPropertyNames.filter(function (name) { + if (target[name] !== undefined && target[name] !== null) { + return { key: name, value: target[name] }; + } + }); + + return ifis; +} + +function getIFICount(target) { + return getIFIs(target).length; +} + +function validateExtensions(extensions, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || [], localTrace = trace || _properties.properties.EXTENSIONS; + + if (extensions === undefined) { + return localErrors; + } + + if (!_utils.xapiValidationUtils.isNonNullMapObject(extensions)) { + localErrors.push({ + trace: localTrace, + message: _errors.xapiValidationErrors.EXTENSIONS_MUST_NOT_BE_NULL, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + // TODO - double-check what further enforceable constraints exist on extension object properties + return localErrors; +} + +function validateLanguageMap(languageMap, trace, errors) { + var localErrors, localTrace, propName, mappedValue; + + localErrors = errors || []; + localTrace = trace || _properties.properties.LANGUAGE_MAP; + + if (languageMap === undefined) { + return localErrors; + } + + if (!_utils.xapiValidationUtils.isNonNullMapObject(languageMap)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.addPropToTrace(localTrace), + message: _errors.xapiValidationErrors.LANGUAGE_MAPS_MUST_NOT_BE_NULL, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + for (propName in languageMap) { + + if (languageMap.hasOwnProperty(propName)) { + if (!_utils.xapiValidationUtils.isValidLanguageTag(propName, _regex.xapiValidationRegex.BCP_47)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.addPropToTrace(localTrace, propName), + message: propName + ' ' + _errors.xapiValidationErrors.LANGUAGE_MAP_KEY_INVALID, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + + mappedValue = languageMap[propName]; + + if (mappedValue === null || mappedValue === undefined || !_utils.xapiValidationUtils.isString(mappedValue)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.addLookupToTrace(localTrace, propName), + message: propName + ' ' + _errors.xapiValidationErrors.LANGUAGE_MAP_KEY_MUST_BE_STRING, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + } + } + + return localErrors; +} + +function validateVerb(verb, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || _properties.properties.VERB; + + if (verb === undefined) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.VERB_MUST_BE_PROVIDED, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + if (!_utils.xapiValidationUtils.isNonNullMapObject(verb)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.VERB_MUST_NOT_BE_NULL, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + validatePropertyIsUri(verb, _properties.properties.ID, localTrace, localErrors, /*isRequired*/true); + + if (verb.display === undefined) { + localErrors.push({ + trace: _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.DISPLAY), + message: _errors.xapiValidationErrors.DISPLAY_SHOULD_BE_PROVIDED, + level: _errors.xapiErrorLevels.SHOULD_VIOLATION + }); + } else { + validateLanguageMap(verb.display, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.DISPLAY), localErrors); + } + + validateAbsenceOfNonWhitelistedProperties(verb, _properties.xapiWhiteListProperties.URI, localTrace, localErrors); + + return localErrors; +} + +function validateInteractionComponentArray(components, interactionType, allowedInteractionTypes, trace, errors) { + var localErrors, localTrace, isAllowedComponentType, ids, perComponentTrace; + + localErrors = errors || []; + localTrace = trace || _properties.properties.INTERACTION_COMPONENTS; + isAllowedComponentType = allowedInteractionTypes.indexOf(interactionType) !== _general.xapiGeneral.NO_INDEX_FOUND; + ids = []; + + if (isAllowedComponentType && components !== undefined) { + if (components === null || !_utils.xapiValidationUtils.isArray(components)) { + localErrors.push({ + trace: localTrace, + message: _errors.xapiValidationErrors.INTERACTION_COMPONENT_SHOULD_BE_ARRAY, + level: _errors.xapiErrorLevels.SHOULD_VIOLATION + }); + } else { + components.forEach(function (interactionComponent, i) { + perComponentTrace = _utils.xapiValidationUtils.addLookupToTrace(localTrace, i); + + if (!_utils.xapiValidationUtils.isNonNullMapObject(interactionComponent)) { + localErrors.push({ + trace: perComponentTrace, + message: _errors.xapiValidationErrors.INTERACTION_COMPONENT_MUST_NOT_BE_NULL, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } else { + validatePropertyIsString(interactionComponent, _properties.properties.ID, perComponentTrace, localErrors, /*isRequired*/true, _errors.xapiErrorLevels.MUST_VIOLATION); + if (ids.indexOf(interactionComponent.id) !== _general.xapiGeneral.NO_INDEX_FOUND) { + localErrors.push({ + trace: _utils.xapiValidationUtils.addPropToTrace(perComponentTrace, _properties.properties.ID), + message: _errors.xapiValidationErrors.ID_MUST_BE_UNIQUE, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } else { + ids.push(interactionComponent.id); + } + + if (interactionComponent.id && _regex.xapiValidationRegex.CONTAINS_WHITESPACE.test(interactionComponent.id)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.addPropToTrace(perComponentTrace, _properties.properties.ID), + message: _errors.xapiValidationErrors.ID_SHOULD_NOT_CONTAIN_WHITESPACES, + level: _errors.xapiErrorLevels.SHOULD_VIOLATION + }); + } + + validateLanguageMap(interactionComponent.description, _utils.xapiValidationUtils.addPropToTrace(perComponentTrace, _properties.properties.DESCRIPTION), localErrors); + validateAbsenceOfNonWhitelistedProperties(interactionComponent, _properties.xapiWhiteListProperties.COMPONENT_ARRAY, perComponentTrace, localErrors); + } + }); + } + } else if (interactionType && components) { + localErrors.push({ + trace: localTrace, + message: _errors.xapiValidationErrors.INTERACTION_TYPE_MUST_BE_VALID + ' ' + interactionType, + level: _errors.xapiErrorLevels.SHOULD_VIOLATION + }); + } + + return localErrors; +} + +function validateActivityDefintion(definition, trace, errors) { + var localErrors, localTrace, correctResponsesPatternTrace; + + localErrors = errors || []; + localTrace = trace || _properties.properties.DEFINITION; + correctResponsesPatternTrace = _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.CORRECT_RESPONSES_PATTERN); + + if (!_utils.xapiValidationUtils.isNonNullMapObject(definition)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.addPropToTrace(localTrace), + message: _errors.xapiValidationErrors.DEFINITIONS_MUST_BE_OBJECTS, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + validateLanguageMap(definition.name, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.NAME), localErrors); + validateLanguageMap(definition.description, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.DESCRIPTION), localErrors); + + validatePropertyIsUri(definition, _properties.properties.TYPE, localTrace, localErrors, /*isRequired*/false); + validatePropertyIsUrl(definition, _properties.properties.MORE_INFO, localTrace, localErrors, /*isRequired*/false); + validateExtensions(definition.extensions, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.EXTENSIONS), localErrors); + + if (definition.interactionType !== undefined) { + if (definition.type !== _general.xapiGeneral.INTERACTION_DEFINITION_TYPE) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, _properties.properties.TYPE), + message: _errors.xapiValidationErrors.INTERACTION_ACTIVITY_SHOULD_HAVE + ' "' + _general.xapiGeneral.INTERACTION_DEFINITION_TYPE + '"', + level: _errors.xapiErrorLevels.SHOULD_VIOLATION + }); + } + + if (_interactionTypes.xapiValidationInteractionTypes.indexOf(definition.interactionType) === _general.xapiGeneral.NO_INDEX_FOUND) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, _properties.properties.INTERACTION_TYPE), + message: _errors.xapiValidationErrors.INTERACTION_TYPE_MUST_BE_CMI, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + } + + if (definition.correctResponsesPattern !== undefined) { + if (!_utils.xapiValidationUtils.isArray(definition.correctResponsesPattern)) { + localErrors.push({ + trace: correctResponsesPatternTrace, + message: _errors.xapiValidationErrors.CORRECT_RESPONSES_PATTERN_MUST_BE_ARRAY, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } else { + definition.correctResponsesPattern.forEach(function (response, i) { + if (response === null || response === undefined || !_utils.xapiValidationUtils.isString(response)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.addLookupToTrace(correctResponsesPatternTrace, i), + message: _errors.xapiValidationErrors.CORRECT_RESPONSES_PATTERN_MUST_BE_STRINGS, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + }); + } + } + + validateInteractionComponentArray(definition.choices, definition.interactionType, [_properties.properties.CHOICE, _properties.properties.SEQUENCING], _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.CHOICES), localErrors); + + validateInteractionComponentArray(definition.scale, definition.interactionType, [_properties.properties.LIKERT], _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.SCALE), localErrors); + + validateInteractionComponentArray(definition.source, definition.interactionType, [_properties.properties.MATCHING], _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.SOURCE), localErrors); + + validateInteractionComponentArray(definition.target, definition.interactionType, [_properties.properties.MATCHING], _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.TARGET), localErrors); + + validateInteractionComponentArray(definition.steps, definition.interactionType, [_properties.properties.PERFORMANCE], _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.STEPS), localErrors); + + validateAbsenceOfNonWhitelistedProperties(definition, _properties.xapiWhiteListProperties.ACTIVITY_DEFINITION, localTrace, localErrors); + return localErrors; +} + +function validateActivity(activity, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || _properties.properties.ACTIVITY; + + if (!_utils.xapiValidationUtils.isNonNullMapObject(activity)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.ACTIVITIES_MUST_NOT_BE_NULL, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + validatePropertyIsUri(activity, _properties.properties.ID, localTrace, localErrors, /*isRequired*/true); + + if (activity.definition !== undefined) { + validateActivityDefintion(activity.definition, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.DEFINITION), localErrors); + } + + validateAbsenceOfNonWhitelistedProperties(activity, _properties.xapiWhiteListProperties.ACTIVITY, localTrace, localErrors); + + return localErrors; +} + +function validateStatementRef(statementRef, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || _properties.properties.STATEMENT_REF; + + if (!_utils.xapiValidationUtils.isNonNullMapObject(statementRef)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.STATEMENT_REF_MUST_NOT_BE_NULL_MAP_OBJECTS, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + return localErrors; + } + + if (statementRef.objectType !== _properties.objectTypes.STATEMENT_REF) { + localErrors.push({ + trace: _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.OBJECT_TYPE), + message: _errors.xapiValidationErrors.OBJECT_TYPE_MUST_BE_STATEMENT_REF, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + + if (!statementRef.id || !_regex.xapiValidationRegex.UUID.test(statementRef.id)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.ID), + message: _errors.xapiValidationErrors.ID_MUST_BE_VALID_UUID_REF, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + + validateAbsenceOfNonWhitelistedProperties(statementRef, _properties.xapiWhiteListProperties.STATEMENT_REF, localTrace, localErrors); + + return localErrors; +} + +function validateScore(score, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || _properties.properties.SCORE; + + if (score === undefined) { + return localErrors; + } + + validatePropertyIsNumber(score, _properties.properties.SCALED, localTrace, localErrors, /*isRequired*/false); + + if (score.scaled !== undefined) { + if (score.scaled < _general.xapiGeneral.MIN_SCALED_VALUE || score.scaled > _general.xapiGeneral.MAX_SCALED_VALUE) { + localErrors.push({ + trace: _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.SCALED), + message: _errors.xapiValidationErrors.SCALED_MUST_BE_BETWEEN_0_1, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + } + + if (score.min !== undefined) { + validatePropertyIsNumber(score, _properties.properties.MIN, localTrace, localErrors, /*isRequired*/false); + + if (score.raw !== undefined && score.raw < score.min) { + localErrors.push({ + trace: _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.RAW), + message: _errors.xapiValidationErrors.RAW_MUST_BE_GREATER_THAN_MIN, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + + if (score.max !== undefined && score.max < score.min) { + localErrors.push({ + trace: _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.MAX), + message: _errors.xapiValidationErrors.MAX_MUST_BE_GREATER_THAN_MIN, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + } + + if (score.max !== undefined) { + validatePropertyIsNumber(score, _properties.properties.MAX, localTrace, localErrors, /*isRequired*/false); + + if (score.raw !== undefined && score.raw > score.max) { + localErrors.push({ + trace: _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.RAW), + message: _errors.xapiValidationErrors.RAW_MUST_BE_LESS_THAN_MAX, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + } + + validatePropertyIsNumber(score, _properties.properties.RAW, localTrace, localErrors, /*isRequired*/false); + validateAbsenceOfNonWhitelistedProperties(score, _properties.xapiWhiteListProperties.SCORE, localTrace, localErrors); + + return localErrors; +} + +function validateResult(result, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || _properties.properties.RESULT; + + if (result === undefined) { + return localErrors; + } + + if (!_utils.xapiValidationUtils.isNonNullMapObject(result)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.addPropToTrace(localTrace), + message: _errors.xapiValidationErrors.RESULT_MUST_BE_MAP_OBJECT, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + validateScore(result.score, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.SCORE), localErrors); + validatePropertyIsBoolean(result, _properties.properties.SUCCESS, localTrace, localErrors, /*isRequired*/false); + validatePropertyIsBoolean(result, _properties.properties.COMPLETION, localTrace, localErrors, /*isRequired*/false); + validatePropertyIsString(result, _properties.properties.RESPONSE, localTrace, localErrors, /*isRequired*/false); + validateExtensions(result.extensions, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.EXTENSIONS), localErrors); + + if (result.duration !== undefined && (result.duration === null || !_utils.xapiValidationUtils.isString(result.duration) || !_regex.xapiValidationRegex.ISO_8601_DURATION.test(result.duration))) { + localErrors.push({ + trace: _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.DURATION), + message: _errors.xapiValidationErrors.DURATION_MUST_BE_VALID, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + + validateAbsenceOfNonWhitelistedProperties(result, _properties.xapiWhiteListProperties.RESULT, localTrace, localErrors); + + return localErrors; +} + +function validatePropertyIsISO8601String(parent, propertyName, trace, errors) { + var localErrors, localTrace, matched, datetime; + + localErrors = errors || []; + localTrace = trace || _properties.properties.DATE_TIME; + datetime = parent[propertyName]; + + if (datetime === undefined) { + return localErrors; + } + + if (datetime === null || !_utils.xapiValidationUtils.isString(datetime)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, propertyName), + message: propertyName + ' ' + _errors.xapiValidationErrors.MUST_BE_STRING, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + matched = _regex.xapiValidationRegex.ISO_8601_DATE_TIME.exec(datetime); + + if (matched) { + if (!dateIncludesZoneInformation(matched)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, propertyName), + message: _errors.xapiValidationErrors.DATE_SHOULD_INCLUDE_ZONE_INFORMATION, + level: _errors.xapiErrorLevels.SHOULD_VIOLATION + }); + } + } else { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, propertyName), + message: _errors.xapiValidationErrors.DATE_MUST_BE_VALID, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + + return localErrors; +} + +function validateVersion(version, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || _properties.properties.VERSION; + + if (version === undefined) { + return localErrors; + } + + if (version === null || !_utils.xapiValidationUtils.isString(version) || !_regex.xapiValidationRegex.SEMVER_1_P_0_P_0.test(version)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.VERSION_MUST_COMPLY_SEMANTIC_VERSIONING, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + + return localErrors; +} + +function validateAttachmentObject(attachment, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || _properties.properties.ATTACHMENT; + + if (!_utils.xapiValidationUtils.isNonNullMapObject(attachment)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.ATTACHMENTS_MUST_NOT_BE_NULL_MAP_OBJECTS, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + if (attachment.display === undefined) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, _properties.properties.DISPLAY), + message: _errors.xapiValidationErrors.DISPLAY_SHOULD_BE_PROVIDED, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } else { + validateLanguageMap(attachment.display, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.DISPLAY), localErrors); + } + + validateLanguageMap(attachment.description, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.DESCRIPTION), localErrors); + validatePropertyIsUri(attachment, _properties.properties.USAGE_TYPE, localTrace, localErrors, /*isRequired*/true, _errors.xapiErrorLevels.MUST_VIOLATION); + validatePropertyIsUri(attachment, _properties.properties.FILE_URL, localTrace, localErrors, /*isRequired*/false, _errors.xapiErrorLevels.MUST_VIOLATION); + + // TODO - more complete validation for Internet Media Type via RFC 2046 + validatePropertyIsString(attachment, _properties.properties.CONTENT_TYPE, localTrace, localErrors, /*isRequired*/true, _errors.xapiErrorLevels.MUST_VIOLATION); + + if (attachment.length === undefined || attachment.length === null || !_utils.xapiValidationUtils.isNumber(attachment.length) || attachment.length % 1 !== 0) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, _properties.properties.LENGTH), + message: _errors.xapiValidationErrors.LENGTH_MUST_BE_INTEGER, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + + if (attachment.sha2 === undefined) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, _properties.properties.SHA2), + message: _errors.xapiValidationErrors.SHA2_MUST_BE_PROVIDED_ON_ATTACHMENT_OBJECTS, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } else if (attachment.sha2 === null || !_utils.xapiValidationUtils.isString(attachment.sha2) || !_regex.xapiValidationRegex.BASE_64.test(attachment.sha2)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, _properties.properties.SHA2), + message: _errors.xapiValidationErrors.SHA2_MUST_CONTAIN_BASE_64_STRING, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + + validateAbsenceOfNonWhitelistedProperties(attachment, _properties.xapiWhiteListProperties.ATTACHMENT, localTrace, localErrors); + return localErrors; +} + +function validateAttachments(attachments, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || _properties.properties.ATTACHMENTS; + + if (attachments === undefined) { + return localErrors; + } + + if (attachments === null || !_utils.xapiValidationUtils.isArray(attachments)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.ATTACHMENTS_MUST_BE_NOT_NULL_ARRAY, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + attachments.forEach(function (attachment, i) { + validateAttachmentObject(attachment, _utils.xapiValidationUtils.addLookupToTrace(localTrace, i), localErrors); + }); + + return localErrors; +} + +function validateAgent(agent, trace, errors) { + var localErrors, localTrace, ifiCount; + + localErrors = errors || []; + localTrace = trace || _properties.properties.AGENT; + + if (!_utils.xapiValidationUtils.isNonNullMapObject(agent)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.AGENT_MUST_BE_NON_NULL_MAP_OBJECT, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + return localErrors; + } + + ifiCount = getIFICount(agent); + + if (ifiCount !== _general.xapiGeneral.NUMER_OF_SPECIFIED_IFI_PROPERTIES) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.AGENT_IFI_PROPERTIES_MUST_BE_SPECIFIED, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + + if (agent.objectType === _properties.objectTypes.GROUP) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.AGENT_MUST_NOT_HAVE_GROUP_CHARACTERISTICS, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + + validateIFIProperties(agent, localTrace, localErrors); + validatePropertyIsString(agent, _properties.properties.NAME, localTrace, localErrors, /*isRequired*/false); + + validateAbsenceOfNonWhitelistedProperties(agent, _properties.xapiWhiteListProperties.AGENT, localTrace, localErrors); + + return localErrors; +} + +function validateGroup(group, trace, errors) { + var localErrors, localTrace, memberTrace, ifiCount; + + localErrors = errors || []; + localTrace = trace || _properties.properties.GROUP; + memberTrace = _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.MEMBER); + + if (!_utils.xapiValidationUtils.isNonNullMapObject(group)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.GROUP_MUST_BE_NON_NULL_MAP_OBJECT, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + ifiCount = getIFICount(group); + + if (ifiCount === 0) { + if (group.member === null || group.member === undefined) { + localErrors.push({ + trace: memberTrace, + message: _errors.xapiValidationErrors.MEMBER_MUST_BE_PROVIDED_FOR_ANONYMOUS_GROUPS, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + } else if (ifiCount > _general.xapiGeneral.NUMER_OF_SPECIFIED_IFI_PROPERTIES) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.GROUP_IFI_PROPERTIES_MUST_BE_SPECIFIED, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + + validateIFIProperties(group, localTrace, localErrors); + + validatePropertyIsString(group, _properties.properties.NAME, localTrace, localErrors, /*isRequired*/false); + + if (group.member !== undefined) { + if (group.member === null || !_utils.xapiValidationUtils.isArray(group.member)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, _properties.properties.MEMBER), + message: _errors.xapiValidationErrors.GROUP_MEMBER_MUST_BE_ARRAY, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } else { + group.member.forEach(function (member, i) { + validateAgent(member, _utils.xapiValidationUtils.addLookupToTrace(memberTrace, i), localErrors); + }); + } + } + + validateAbsenceOfNonWhitelistedProperties(group, _properties.xapiWhiteListProperties.GROUP, localTrace, localErrors); + + return localErrors; +} + +function validateActor(actor, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || _properties.properties.ACTOR; + + if (actor === null || actor === undefined) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.ACTOR_MUST_BE_PROVIDED, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + if (_utils.xapiValidationUtils.isGroup(actor, _properties.objectTypes.GROUP)) { + validateGroup(actor, localTrace, localErrors); + } else { + validateAgent(actor, localTrace, localErrors); + } + + return localErrors; +} + +function validateAuthority(authority, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || _properties.properties.AUTHORITY; + + if (authority === undefined) { + return localErrors; + } + + if (!_utils.xapiValidationUtils.isNonNullMapObject(authority)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.AUTHORITY_MUST_BE_NON_NULL_MAP_OBJECT, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + if (_utils.xapiValidationUtils.isGroup(authority, _properties.objectTypes.GROUP)) { + validateGroup(authority, localTrace, localErrors); + if (!authority.member || !authority.member.length || authority.member.length !== _general.xapiGeneral.GROUP_AUTHORITY_AGENT_MEMBERS) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, _properties.properties.MEMBER), + message: _errors.xapiValidationErrors.GROUP_AUTHORITY_AGENT_MEMBERS_MUST_BE_TWO, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + } else { + validateAgent(authority, localTrace, localErrors); + } + + return localErrors; +} + +function validateContextActivitySubContext(subContext, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || _properties.properties.SUB_CONTEXT; + + if (subContext === undefined) { + return localErrors; + } + + if (subContext === null) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.CONTEXT_ACTIVITIES_MUST_NOT_BE_NULL, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } else if (_utils.xapiValidationUtils.isArray(subContext)) { + subContext.forEach(function (activity, i) { + validateActivity(activity, _utils.xapiValidationUtils.addLookupToTrace(localTrace, i), localErrors); + }); + } else if (_utils.xapiValidationUtils.isObject(subContext)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.CONTEXT_ACTIVITIES_SHOULD_BE_AN_ARRAY, + level: _errors.xapiErrorLevels.SHOULD_VIOLATION + }); + + validateActivity(subContext, localTrace, localErrors); + } else { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.CONTEXT_ACTIVITIES_MUST_BE_ARRAY_OR_ACTIVITY_OBJ, + level: _errors.xapiErrorLevels.MUST_VIOLATION }); + } + return localErrors; +} + +function validateContextActivities(contextActivities, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || _properties.properties.CONTEXT_ACTIVITIES; + + if (contextActivities === undefined) { + return localErrors; + } + + if (!_utils.xapiValidationUtils.isNonNullMapObject(contextActivities)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.CONTEXT_ACTIVITIES_MUST_BE_NON_NULL_MAP_OBJECT, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + return localErrors; + } + + validateContextActivitySubContext(contextActivities.parent, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.PARENT), localErrors); + validateContextActivitySubContext(contextActivities.grouping, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.GROUPING), localErrors); + validateContextActivitySubContext(contextActivities.category, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.CATEGORY), localErrors); + validateContextActivitySubContext(contextActivities.other, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.OTHER), localErrors); + + validateAbsenceOfNonWhitelistedProperties(contextActivities, _properties.xapiWhiteListProperties.CONTEXT_ACTIVITIES, localTrace, localErrors); + + return localErrors; +} + +function validateContext(context, trace, errors, statementObjectObjectType) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || _properties.properties.CONTEXT; + + if (context === undefined) { + return localErrors; + } + + if (!_utils.xapiValidationUtils.isNonNullMapObject(context)) { + localErrors.push({ + trace: localTrace, + message: _errors.xapiValidationErrors.CONTEXT_MUST_BE_NON_NUL_MAP_OBJECT, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + if (context.registration !== undefined && (context.registration === null || !_utils.xapiValidationUtils.isString(context.registration) || !_regex.xapiValidationRegex.UUID.test(context.registration))) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, _properties.properties.REGISTRATION), + message: _errors.xapiValidationErrors.REGISTRATION_MUST_BE_UUID_STRING, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + + if ([_properties.objectTypes.GROUP, _properties.objectTypes.AGENT].indexOf(statementObjectObjectType) !== _general.xapiGeneral.NO_INDEX_FOUND) { + if (context.revision !== undefined) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, _properties.properties.REVISION), + message: _errors.xapiValidationErrors.REVISION_MUST_BE_AGENT_OR_GROUP, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + + if (context.platform !== undefined) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, _properties.properties.PLATFORM), + message: _errors.xapiValidationErrors.PLATFORM_MUST_NOT_BE_USED_WITH_REVISION_AGENT_OR_GROUP, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + } + + validatePropertyIsString(context, _properties.properties.REVISION, localTrace, localErrors, /*isRequired*/false, _errors.xapiErrorLevels.MUST_VIOLATION); + validatePropertyIsString(context, _properties.properties.PLATFORM, localTrace, localErrors, /*isRequired*/false, _errors.xapiErrorLevels.MUST_VIOLATION); + + if (context.team !== undefined) { + validateGroup(context.team, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.TEAM), localErrors); + } + + if (context.contextActivities !== undefined) { + validateContextActivities(context.contextActivities, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.CONTEXT_ACTIVITIES), localErrors); + } + + if (context.language !== undefined && !_utils.xapiValidationUtils.isValidLanguageTag(context.language, _regex.xapiValidationRegex.BCP_47)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, _properties.properties.LANGUAGE), + message: _errors.xapiValidationErrors.LANGUAGE_MUST_BE_STRING, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + + if (context.statement !== undefined) { + validateStatementRef(context.statement, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.STATEMENT), localErrors); + } + + if (context.instructor !== undefined) { + if (_utils.xapiValidationUtils.isGroup(context.instructor, _properties.objectTypes.GROUP)) { + validateGroup(context.instructor, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.INSTRUCTOR), localErrors); + } else { + validateAgent(context.instructor, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.INSTRUCTOR), localErrors); + } + } + + validateExtensions(context.extensions, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.EXTENSIONS), localErrors); + validateAbsenceOfNonWhitelistedProperties(context, _properties.xapiWhiteListProperties.EXTENSIONS, localTrace, localErrors); + + return localErrors; +} + +function validateObject(object, trace, errors, isWithinSubStatement) { + var localErrors, localTrace, objectType; + + localErrors = errors || []; + localTrace = trace || _properties.properties.OBJECT; + + if (object === undefined) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.OBJECT_MUST_BE_DEFINED, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + if (!_utils.xapiValidationUtils.isNonNullMapObject(object)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.OBJECT_MUST_BE_NON_NULL_MAP_OBJECT, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + validatePropertyIsString(object, _properties.properties.OBJECT_TYPE, localTrace, localErrors, /*isRequired*/true, _errors.xapiErrorLevels.SHOULD_VIOLATION); + + objectType = object.objectType || _properties.objectTypes.ACTIVITY; + + switch (objectType) { + case _properties.objectTypes.ACTIVITY: + validateActivity(object, localTrace, localErrors); + break; + case _properties.objectTypes.AGENT: + validateAgent(object, localTrace, localErrors); + break; + case _properties.objectTypes.GROUP: + validateGroup(object, localTrace, localErrors); + break; + case _properties.objectTypes.STATEMENT_REF: + validateStatementRef(object, localTrace, localErrors); + break; + case _properties.objectTypes.SUB_STATEMENT: + if (isWithinSubStatement) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, _properties.properties.OBJECT_TYPE), + message: _errors.xapiValidationErrors.SUB_STATEMENT_MUST_NOT_CONTAIN_SUB_STATEMENT, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + validate(object, localTrace, localErrors, /*isSubStatement*/true); + break; + default: + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, _properties.properties.OBJECT_TYPE), + message: _errors.xapiValidationErrors.OBJECT_TYPE_MUST_BE_VALID_OPTION + ' ' + _properties.xApiValidObjectTypes.toString(), + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + + return localErrors; +} + +function validate(statement, trace, errors, isSubStatement) { + var localErrors, localTrace, statementObjectObjectType, whitelistedProperties; + + localErrors = errors || []; + localTrace = trace || _properties.properties.STATEMENT; + + whitelistedProperties = _properties.xapiWhiteListProperties.STATEMENT; + + if (!_utils.xapiValidationUtils.isNonNullMapObject(statement)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.STATEMENT_REF_MUST_NOT_BE_NULL_MAP_OBJECTS, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + if (!isSubStatement) { + if (statement.id === null || statement.id === undefined || !_utils.xapiValidationUtils.isString(statement.id)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, _properties.properties.ID), + message: _errors.xapiValidationErrors.IDS_SHOULD_BE_GENERATED_BY_LRS, + level: _errors.xapiErrorLevels.SHOULD_VIOLATION + }); + } else if (!_regex.xapiValidationRegex.UUID.test(statement.id)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, _properties.properties.ID), + message: _errors.xapiValidationErrors.ID_MUST_BE_VALID, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + } else { + whitelistedProperties = _properties.xapiWhiteListProperties.SUB_STATEMENT; + } + + validateActor(statement.actor, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.ACTOR), localErrors); + validateVerb(statement.verb, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.VERB), localErrors); + validateObject(statement.object, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.OBJECT), localErrors, isSubStatement); + validateResult(statement.result, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.RESULT), localErrors); + + statementObjectObjectType = statement.object && statement.object.objectType ? statement.object.objectType : _properties.objectTypes.ACTIVITY; + + validateContext(statement.context, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.CONTEXT), localErrors, statementObjectObjectType); + validatePropertyIsISO8601String(statement, _properties.properties.TIMESTAMP, localTrace, localErrors); + validatePropertyIsISO8601String(statement, _properties.properties.STORED, localTrace, localErrors); + + validateAuthority(statement.authority, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.AUTHORITY), localErrors); + validateVersion(statement.version, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.VERSION), localErrors); + validateAttachments(statement.attachments, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.ATTACHMENTS), localErrors); + + validateAbsenceOfNonWhitelistedProperties(statement, whitelistedProperties, localTrace, localErrors); + + return localErrors; +} + +function makeStatementReport(statement) { + var localErrors; + + localErrors = []; + validate(statement, _properties.properties.STATEMENT, localErrors, /*isRequired*/false); + + return makeV1Report(statement, localErrors); +} + +function validateAmbiguousTypeStatement(statement) { + var statementObject; + + if (statement === undefined) { + return makeV1SingleErrorReport( /*instance*/null, { + trace: _properties.properties.STATEMENT, + message: _errors.xapiValidationErrors.STATEMENT_ARGUMENT_MUST_BE_PROVIDED, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + + if (statement === null) { + return makeV1SingleErrorReport( /*instance*/null, { + trace: _properties.properties.STATEMENT, + message: _errors.xapiValidationErrors.STATEMENT_MUST_NOT_BE_NULL, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + + if (_utils.xapiValidationUtils.isString(statement)) { + try { + statementObject = JSON.parse(statement); + if (statementObject === null || !_utils.xapiValidationUtils.isObject(statementObject) || _utils.xapiValidationUtils.isArray(statementObject)) { + return makeV1SingleErrorReport(statementObject, { + trace: _properties.properties.STATEMENT, + message: _errors.xapiValidationErrors.STATEMENT_MUST_BE_PARSED_CORRECTLY, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + } catch (e) { + return makeV1SingleErrorReport(statementObject, { + trace: _properties.properties.STATEMENT, + message: _errors.xapiValidationErrors.INVALID_JSON + ': ' + e.message, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + + return makeStatementReport(statementObject); + } + + if (_utils.xapiValidationUtils.isObject(statement) && !_utils.xapiValidationUtils.isArray(statement)) { + return makeStatementReport(statement); + } + + return makeV1SingleErrorReport( /*instance*/null, { + trace: _properties.properties.STATEMENT, + message: _errors.xapiValidationErrors.STATEMENT_ARGUMENT_IS_NOT_VALID, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); +} + +function dateIncludesZoneInformation(matched) { + return matched[_regex.dateFormatRegexPositions.ZONE] || matched[_regex.dateFormatRegexPositions.RELATIVE_TIME] && matched[_regex.dateFormatRegexPositions.TIME_ZONE_HOUR]; +} + +xapiValidation = { + validateStatement: validateAmbiguousTypeStatement +}; + +module.exports = xapiValidation; + +},{"./constants/errors":42,"./constants/general":43,"./constants/interaction-types":44,"./constants/properties":45,"./constants/regex":46,"./utils/utils":47}],49:[function(require,module,exports){ +'use strict';var _underscore=require('underscore');var _chai=require('chai');var _xapiValidator=require('../src/xapiValidator');// var xapiValidator = require('../xapiValidator'); +describe("xapiValidator",function(){describe("#validateStatement",function(){function reportHasErrorWithTracePrefix(report,prefix,targetLevel){if(report===null||report===undefined||report.errors===null||report.errors===undefined){return false;}var hasTargetLevel=targetLevel!==null&&targetLevel!==undefined;return _underscore._.any(report.errors,function(err){var foundPrefix=err.trace.indexOf(prefix)===0;return hasTargetLevel?targetLevel===err.level&&foundPrefix:foundPrefix;});}describe("when passed no arguments",function(){it("returns non-null report",function(){var result=_xapiValidator.xapiValidator.validateStatement();(0,_chai.expect)(result).to.be.not.null;(0,_chai.expect)(result).to.be.a("Object");});it("includes one error",function(){var result=_xapiValidator.xapiValidator.validateStatement();var errors=result.errors;(0,_chai.expect)(errors).to.be.instanceOf(Array);(0,_chai.expect)(errors).to.have.length(1);(0,_chai.expect)(errors[0]).to.have.property("message").that.is.a('string').that.equals('No statement argument provided.');(0,_chai.expect)(errors[0]).to.have.property("level").that.equals("MUST_VIOLATION");});it("has a null instance property in the report",function(){(0,_chai.expect)(_xapiValidator.xapiValidator.validateStatement()).to.have.property("instance").that.is.null;});});describe("when passed a null argument",function(){it("returns non-null report",function(){var result=_xapiValidator.xapiValidator.validateStatement(null);(0,_chai.expect)(result).to.be.not.null;(0,_chai.expect)(result).to.be.a("Object");(0,_chai.expect)(result).to.have.property("errors").that.is.a("Array");(0,_chai.expect)(result).to.have.property("instance");});it("includes one error",function(){var result=_xapiValidator.xapiValidator.validateStatement(null);var errors=result.errors;(0,_chai.expect)(errors).to.be.instanceOf(Array);(0,_chai.expect)(errors).to.have.length(1);(0,_chai.expect)(errors[0]).to.have.property("message").that.is.a('string').that.equals('Null statement argument provided.');(0,_chai.expect)(errors[0]).to.have.property("level").that.equals("MUST_VIOLATION");});it("has a null instance property in the report",function(){(0,_chai.expect)(_xapiValidator.xapiValidator.validateStatement(null)).to.have.property("instance").that.is.null;});});describe("when passed a json string argument",function(){var minimalJsonString="{\"id\":\"whatever\"}";it("returns non-null report",function(){var result=_xapiValidator.xapiValidator.validateStatement(minimalJsonString);(0,_chai.expect)(result).to.be.not.null;(0,_chai.expect)(result).to.be.a("Object");(0,_chai.expect)(result).to.have.property("errors").that.is.a("Array");(0,_chai.expect)(result).to.have.property("instance");});it("has an instance property with the deserialized JSON in the report",function(){var result=_xapiValidator.xapiValidator.validateStatement(minimalJsonString);(0,_chai.expect)(result).to.have.property("instance").that.is.an("Object").that.deep.equals({"id":"whatever"});});});describe("when passed a json string argument encoding null",function(){var minimalJsonString="null";it("returns non-null report",function(){var result=_xapiValidator.xapiValidator.validateStatement(minimalJsonString);(0,_chai.expect)(result).to.be.not.null;(0,_chai.expect)(result).to.be.a("Object");(0,_chai.expect)(result).to.have.property("errors").that.is.a("Array");(0,_chai.expect)(result).to.have.property("instance");});it("includes one error",function(){var result=_xapiValidator.xapiValidator.validateStatement(minimalJsonString);var errors=result.errors;(0,_chai.expect)(errors).to.be.instanceOf(Array);(0,_chai.expect)(errors).to.have.length(1);(0,_chai.expect)(errors[0]).to.have.property("message");(0,_chai.expect)(errors[0]).to.have.property("level").that.equals("MUST_VIOLATION");});it("has an instance property with null value",function(){var result=_xapiValidator.xapiValidator.validateStatement(minimalJsonString);(0,_chai.expect)(result).to.have.property("instance").that.is.null;});});describe("when passed an invalid json string argument",function(){var minimalJsonString="derp";it("returns non-null report",function(){var result=_xapiValidator.xapiValidator.validateStatement(minimalJsonString);(0,_chai.expect)(result).to.be.not.null;(0,_chai.expect)(result).to.be.a("Object");(0,_chai.expect)(result).to.have.property("errors").that.is.a("Array");(0,_chai.expect)(result).to.have.property("instance");});it("includes one error",function(){var result=_xapiValidator.xapiValidator.validateStatement(minimalJsonString);var errors=result.errors;(0,_chai.expect)(errors).to.be.instanceOf(Array);(0,_chai.expect)(errors).to.have.length(1);(0,_chai.expect)(errors[0]).to.have.property("message");(0,_chai.expect)(errors[0]).to.have.property("level").that.equals("MUST_VIOLATION");});it("has an instance property with null value",function(){var result=_xapiValidator.xapiValidator.validateStatement(minimalJsonString);(0,_chai.expect)(result).to.have.property("instance").that.is.null;});});describe("when passed a statement object",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"}};it("returns non-null report",function(){var result=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(result).to.be.not.null;(0,_chai.expect)(result).to.be.a("Object");(0,_chai.expect)(result).to.have.property("errors").that.is.a("Array");(0,_chai.expect)(result).to.have.property("instance");});it("has an instance property that matches the input object",function(){var result=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(result).to.have.property("instance").that.deep.equals(inputStatement);});});describe("when given a null id property",function(){var inputStatement={id:null,actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"}};it("has an error about the id property",function(){var result=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(reportHasErrorWithTracePrefix(result,"statement.id")).to.be.true;});});describe("when given an invalid UUID id property",function(){var inputStatement={id:"abc123",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"}};it("has an error about the id property",function(){var result=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(reportHasErrorWithTracePrefix(result,"statement.id")).to.be.true;});});describe("when given a valid UUID id property",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"}};it("has an error about the id property",function(){var result=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(reportHasErrorWithTracePrefix(result,"statement.id")).to.be.false;});});describe("when given a null actor property",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:null,verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"}};it("has an error about the actor property",function(){var result=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(reportHasErrorWithTracePrefix(result,"statement.actor")).to.be.true;});});describe("when given an empty non-null actor property",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"}};it("has an error about the actor property",function(){var result=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(reportHasErrorWithTracePrefix(result,"statement.actor")).to.be.true;});});describe("when given an otherwise valid actor",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:group@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"}};it("the name property is optional",function(){var result=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(result.errors).to.have.property("length",0);});it("the name property produces no errors when a simple string",function(){inputStatement.actor.name="hello";var result=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(result.errors).to.have.property("length",0);});it("the name property produces no errors when a simple string",function(){inputStatement.actor.name=1.23;var result=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(reportHasErrorWithTracePrefix(result,"statement.actor.name")).to.be.true;(0,_chai.expect)(result.errors).to.have.property("length",1);});});describe("when given an actor with an objectType of 'Group'",function(){var moreValidStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{objectType:"Group",member:[]},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"}};it("the member property has no errors about it when present",function(){var result=_xapiValidator.xapiValidator.validateStatement(moreValidStatement);(0,_chai.expect)(reportHasErrorWithTracePrefix(result,"statement.actor.member")).to.be.false;});it("the member property is required to be present if the actor is unidentified, and produces an error when absent",function(){var inputInvalidStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{objectType:"Group"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"}};var result=_xapiValidator.xapiValidator.validateStatement(inputInvalidStatement);(0,_chai.expect)(reportHasErrorWithTracePrefix(result,"statement.actor.member")).to.be.true;});it("the member property is not required to be present if the actor is identified",function(){var result=_xapiValidator.xapiValidator.validateStatement({id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{objectType:"Group",mbox:"mailto:group@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"}});(0,_chai.expect)(reportHasErrorWithTracePrefix(result,"statement.actor.member")).to.be.false;});it("the member property is allowed to be present if the actor is identified",function(){var result=_xapiValidator.xapiValidator.validateStatement({id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{objectType:"Group",mbox:"mailto:group@example.com",member:[]},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"}});(0,_chai.expect)(reportHasErrorWithTracePrefix(result,"statement.actor.member")).to.be.false;});});describe("when given an actor with a members property",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{member:[]},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"}};it("the member property has no errors about it when present but empty",function(){(0,_chai.expect)(_xapiValidator.xapiValidator.validateStatement(inputStatement).errors).to.be.empty;});it("the member property has no errors when populated with a simple agent",function(){inputStatement.actor.member=[{mbox:"mailto:group@example.com"}];(0,_chai.expect)(_xapiValidator.xapiValidator.validateStatement(inputStatement).errors).to.be.empty;});it("the member property reports an error when populated with a Group object via objectType",function(){inputStatement.actor.member=[{mbox:"mailto:group@example.com",objectType:"Group"}];(0,_chai.expect)(_xapiValidator.xapiValidator.validateStatement(inputStatement).errors).to.have.property("length",1);});it("the member property's agent reports an error when given an account missing its homePage",function(){inputStatement.actor.member=[{account:{name:"bob"}}];(0,_chai.expect)(reportHasErrorWithTracePrefix(_xapiValidator.xapiValidator.validateStatement(inputStatement),"statement.actor.member[0].account.homePage")).to.be.true;});it("the member property's agent reports an error when given an account missing its name",function(){inputStatement.actor.member=[{account:{homePage:"http://example.com"}}];(0,_chai.expect)(reportHasErrorWithTracePrefix(_xapiValidator.xapiValidator.validateStatement(inputStatement),"statement.actor.member[0].account.name")).to.be.true;});it("the member property's agent reports an error when given an account with an all-lowercase homepage",function(){inputStatement.actor.member=[{account:{homepage:"http://example.com",name:"bob"}}];var report=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(reportHasErrorWithTracePrefix(report,"statement.actor.member[0].account.homepage")).to.be.true;(0,_chai.expect)(report.errors).to.have.property("length",2);});it("the member property's agent reports no error when given a full account",function(){inputStatement.actor.member=[{account:{homePage:"http://example.com",name:"bob"}}];(0,_chai.expect)(_xapiValidator.xapiValidator.validateStatement(inputStatement).errors).to.have.property("length",0);});it("the member property's agent reports no error when given a valid mbox",function(){inputStatement.actor.member=[{mbox:"mailto:bob@example.com"}];(0,_chai.expect)(_xapiValidator.xapiValidator.validateStatement(inputStatement).errors).to.have.property("length",0);});it("the member property's agent reports an error when given an invalid mbox",function(){inputStatement.actor.member=[{mbox:"SOMETHINGWRONG:bob@example.com"}];var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.actor.member[0].mbox")).to.be.true;(0,_chai.expect)(results.errors).to.have.property("length",1);});it("the member property reports an error when populated with a Group object via member",function(){inputStatement.actor.member=[{mbox:"mailto:group@example.com",member:[]}];(0,_chai.expect)(_xapiValidator.xapiValidator.validateStatement(inputStatement).errors).to.have.property("length",1);});});describe("when given a statement without a verb property",function(){it("reports an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{member:[]},object:{id:"http://example.com/myUniqueId",objectType:"Activity"}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.verb")).to.be.true;});});describe("when given a verb without an id property",function(){it("reports an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{member:[]},verb:{"display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.verb.id","MUST_VIOLATION")).to.be.true;});});describe("when given a verb with a non-string id property",function(){it("reports an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{member:[]},verb:{"id":12.34,"display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.verb.id","MUST_VIOLATION")).to.be.true;});});describe("when given a verb with a relative URI id property",function(){it("reports an SHOULD_VIOLATION error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{member:[]},verb:{"id":"fragment","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.verb.id","SHOULD_VIOLATION")).to.be.true;});});describe("when given a verb without a display property",function(){it("reports an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{member:[]},verb:{"id":"http://adlnet.gov/expapi/verbs/created"},object:{id:"http://example.com/myUniqueId",objectType:"Activity"}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.verb.display","SHOULD_VIOLATION")).to.be.true;});});describe("when given a verb with an empty display property",function(){it("reports no errors",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{member:[]},verb:{"id":"http://adlnet.gov/expapi/verbs/created",display:{}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"}};(0,_chai.expect)(_xapiValidator.xapiValidator.validateStatement(inputStatement).errors).to.have.property("length",0);});});describe("when given a verb.display with RFC 5646 key and string value",function(){it("reports no errors",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{member:[]},verb:{"id":"http://adlnet.gov/expapi/verbs/created",display:{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"}};(0,_chai.expect)(_xapiValidator.xapiValidator.validateStatement(inputStatement).errors).to.have.property("length",0);});});describe("when given a verb.display with RFC 5646 key and non-string value",function(){it("reports an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{member:[]},verb:{"id":"http://adlnet.gov/expapi/verbs/created",display:{"en-US":1.23}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.verb.display[\"en-US\"]","MUST_VIOLATION")).to.be.true;});});describe("when given a verb.display with invalid key and string value",function(){it("reports an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{member:[]},verb:{"id":"http://adlnet.gov/expapi/verbs/created",display:{"123totallyWrong":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.verb.display.123totallyWrong","MUST_VIOLATION")).to.be.true;});});describe("when the object property is absent",function(){it("reports a MUST_VIOLATION error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{member:[]},verb:{"id":"http://adlnet.gov/expapi/verbs/created",display:{"en-US":"created"}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.object","MUST_VIOLATION")).to.be.true;});});describe("when the object property is null",function(){it("reports a MUST_VIOLATION error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{member:[]},verb:{"id":"http://adlnet.gov/expapi/verbs/created",display:{"en-US":"created"}},object:null};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.object","MUST_VIOLATION")).to.be.true;});});describe("when the object lacks an objectType property",function(){it("reports a SHOULD_VIOLATION error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{member:[]},verb:{"id":"http://adlnet.gov/expapi/verbs/created",display:{"en-US":"created"}},object:{id:"http://example.com/myUniqueId"}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.object.objectType","SHOULD_VIOLATION")).to.be.true;});});describe("when the object is an activity with a null definition property",function(){it("reports a MUST_VIOLATION error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{member:[]},verb:{"id":"http://adlnet.gov/expapi/verbs/created",display:{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity",definition:null}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.object.definition","MUST_VIOLATION")).to.be.true;});});describe("when the object is an activity with an array definition property",function(){it("reports a MUST_VIOLATION error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{member:[]},verb:{"id":"http://adlnet.gov/expapi/verbs/created",display:{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity",definition:[]}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.object.definition","MUST_VIOLATION")).to.be.true;});});describe("when the object is an Activity with a definition",function(){it("an array for the name property produces a must violation error.",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{member:[]},verb:{"id":"http://adlnet.gov/expapi/verbs/created",display:{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity",definition:{name:[]}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.object.definition.name","MUST_VIOLATION")).to.be.true;});it("a number for the name property produces a must violation error.",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{member:[]},verb:{"id":"http://adlnet.gov/expapi/verbs/created",display:{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity",definition:{name:1.23}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.object.definition.name","MUST_VIOLATION")).to.be.true;});it("an invalid language Map key for the name property produces a must violation error.",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{member:[]},verb:{"id":"http://adlnet.gov/expapi/verbs/created",display:{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity",definition:{name:{"123 totally not a language code":"created"}}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.object.definition.name","MUST_VIOLATION")).to.be.true;});it("a CMI interactionType value produces no errors",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{member:[]},verb:{"id":"http://adlnet.gov/expapi/verbs/created",display:{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity",definition:{type:"http://adlnet.gov/expapi/activities/cmi.interaction",interactionType:"true-false"}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.object.definition.name","MUST_VIOLATION")).to.be.false;});it("a non-CMI interactionType value produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{member:[]},verb:{"id":"http://adlnet.gov/expapi/verbs/created",display:{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity",definition:{type:"http://adlnet.gov/expapi/activities/cmi.interaction",interactionType:"graphicGapMatchInteraction"}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.object.definition.interactionType","MUST_VIOLATION")).to.be.true;});it("a numeric correctResponsesPattern value produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{member:[]},verb:{"id":"http://adlnet.gov/expapi/verbs/created",display:{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity",definition:{correctResponsesPattern:1.23}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.object.definition.correctResponsesPattern","MUST_VIOLATION")).to.be.true;});it("a flat string correctResponsesPattern value produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{member:[]},verb:{"id":"http://adlnet.gov/expapi/verbs/created",display:{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity",definition:{correctResponsesPattern:"1.23"}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.object.definition.correctResponsesPattern","MUST_VIOLATION")).to.be.true;});it("a nested number in a correctResponsesPattern Array value produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{member:[]},verb:{"id":"http://adlnet.gov/expapi/verbs/created",display:{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity",definition:{correctResponsesPattern:[1.23]}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.object.definition.correctResponsesPattern[0]","MUST_VIOLATION")).to.be.true;});it("a nested string in a correctResponsesPattern Array value produces no errors",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{member:[]},verb:{"id":"http://adlnet.gov/expapi/verbs/created",display:{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity",definition:{correctResponsesPattern:["1.23"]}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.object.definition.correctResponsesPattern","MUST_VIOLATION")).to.be.false;});it("an interaction activity without the standard \"http://adlnet.gov/expapi/activities/cmi.interaction\" value for the type property should produce a SHOULD error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{member:[]},verb:{"id":"http://adlnet.gov/expapi/verbs/created",display:{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity",definition:{type:"http://example.com/somethingElse",interactionType:"choice",choices:[]}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.object.definition.type","SHOULD_VIOLATION")).to.be.true;});it("an interaction component array property not associated with the current interactionType produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{member:[]},verb:{"id":"http://adlnet.gov/expapi/verbs/created",display:{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity",definition:{type:"http://adlnet.gov/expapi/activities/cmi.interaction",interactionType:"choice",steps:[]}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.object.definition.steps","SHOULD_VIOLATION")).to.be.true;});it("an interaction component with whitespace in the id property produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{member:[]},verb:{"id":"http://adlnet.gov/expapi/verbs/created",display:{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity",definition:{type:"http://adlnet.gov/expapi/activities/cmi.interaction",interactionType:"choice",choices:[{id:"hello invalid id",description:{}}]}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.object.definition.choices[0]","SHOULD_VIOLATION")).to.be.true;});it("an interaction component with repeated non-unique id produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{member:[]},verb:{"id":"http://adlnet.gov/expapi/verbs/created",display:{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity",definition:{type:"http://adlnet.gov/expapi/activities/cmi.interaction",interactionType:"choice",choices:[{id:"idA",description:{}},{id:"idA",description:{}}]}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.object.definition.choices[1]","MUST_VIOLATION")).to.be.true;});describe("given a statement reference type object",function(){it("reports a MUST error when the id property is missing",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{objectType:"StatementRef"}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.object.id","MUST_VIOLATION")).to.be.true;});it("reports a MUST error when the id property is not a UUID",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"not a UUID",objectType:"StatementRef"}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.object.id","MUST_VIOLATION")).to.be.true;});});describe("given a substatement type object",function(){it("should not report an error when valid",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{objectType:"SubStatement",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("reports a MUST error when the id property is present",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa1",objectType:"SubStatement",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.object.id","MUST_VIOLATION")).to.be.true;});it("reports a MUST error when the version property is present",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{version:"1.0.0",objectType:"SubStatement",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.object.version","MUST_VIOLATION")).to.be.true;});it("reports a MUST error when the stored property is present",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{stored:"2013-05-28T07:12:57.245Z",objectType:"SubStatement",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.object.stored","MUST_VIOLATION")).to.be.true;});it("reports a MUST error when the authority property is present",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{authority:{mbox:"mailto:agent@example.com"},objectType:"SubStatement",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.object.authority","MUST_VIOLATION")).to.be.true;});});describe("given a non-Object results property",function(){it("if null, produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},result:null};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.result","MUST_VIOLATION")).to.be.true;});it("if an Array, produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},result:[]};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.result","MUST_VIOLATION")).to.be.true;});it("if an number, produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},result:1.23};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.result","MUST_VIOLATION")).to.be.true;});});describe("given a results property that is an object",function(){it("if empty, all is okay, no properties were required",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},result:{}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("a non-Boolean success property produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},result:{success:123}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.result.success","MUST_VIOLATION")).to.be.true;});it("a Boolean success property produces no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},result:{success:false}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("a non-Boolean completion property produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},result:{completion:123}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.result.completion","MUST_VIOLATION")).to.be.true;});it("a Boolean completion property produces no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},result:{completion:false}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("a non-String response property produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},result:{response:123}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.result.response","MUST_VIOLATION")).to.be.true;});it("a String response property produces no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},result:{response:"idA"}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("a non-String duration property produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},result:{duration:123}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.result.duration","MUST_VIOLATION")).to.be.true;});it("a non-ISO 8601 duration String duration property produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},result:{duration:"not an ISO compliant duration"}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.result.duration","MUST_VIOLATION")).to.be.true;});it("an ISO 8601 duration String response property produces no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},result:{duration:"P3Y6M4DT12H30M5S"}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("an ISO 8601 duration String response property with fractional seconds produces no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},result:{duration:"P3Y6M4DT12H30M5.01S"}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});});describe("given a score property on the results",function(){it("a non-Number raw property produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},result:{score:{raw:"123"}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.result.score.raw","MUST_VIOLATION")).to.be.true;});it("a Number raw property produces no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},result:{score:{raw:123}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("a Number raw property below min produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},result:{score:{raw:123,min:200}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.result.score.raw","MUST_VIOLATION")).to.be.true;});it("a Number raw property above max produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},result:{score:{raw:123,max:100}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.result.score.raw","MUST_VIOLATION")).to.be.true;});it("a Number raw property between min and max produces no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},result:{score:{raw:123,min:120,max:125}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("a non-Number scaled property produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},result:{score:{scaled:"0.5"}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.result.score.scaled","MUST_VIOLATION")).to.be.true;});it("a Number scaled property produces no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},result:{score:{scaled:0.5}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("a Number scaled property below 0 produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},result:{score:{scaled:-0.5}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.result.score.scaled","MUST_VIOLATION")).to.be.true;});it("a Number scaled property above 1 produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},result:{score:{scaled:2}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.result.score.scaled","MUST_VIOLATION")).to.be.true;});it("a non-Number max property produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},result:{score:{max:"123"}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.result.score.max","MUST_VIOLATION")).to.be.true;});it("a Number max property produces no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},result:{score:{max:123}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("a Number max property below min produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},result:{score:{max:123,min:200}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.result.score.max","MUST_VIOLATION")).to.be.true;});it("a non-Number min property produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},result:{score:{min:"123"}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.result.score.min","MUST_VIOLATION")).to.be.true;});it("a Number min property produces no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},result:{score:{min:123}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("a Number min property above max produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},result:{score:{max:123,min:200}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.result.score.max","MUST_VIOLATION")).to.be.true;});});describe("for a given defined context property",function(){it("an empty object produces no errors",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:{}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("an non-object context value produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:123};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.context","MUST_VIOLATION")).to.be.true;});it("an array context value produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:[]};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.context","MUST_VIOLATION")).to.be.true;});it("a non-UUID registration value produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:{registration:"not a UUID"}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.context.registration","MUST_VIOLATION")).to.be.true;});it("a UUID registration value produces no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:{registration:"ed41c918-b88b-4b20-a0a5-a4c32391aaa0"}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("an empty map for an instructor value produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:{instructor:{}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.context.instructor","MUST_VIOLATION")).to.be.true;});it("an unidentified Agent for an instructor value produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:{instructor:{objectType:"Agent"}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.context.instructor","MUST_VIOLATION")).to.be.true;});it("an unidentified Group with no member property for an instructor value produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:{instructor:{objectType:"Group"}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.context.instructor","MUST_VIOLATION")).to.be.true;});it("an Agent instructor value produces no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:{instructor:{mbox:"mailto:bob@example.com"}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("a Group instructor identified by member property produces no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:{instructor:{mbox:"mailto:bob@example.com",member:[]}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("a Group instructor identified by objectType property produces no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:{instructor:{mbox:"mailto:bob@example.com",objectType:"Group"}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("if the statement's object is an Agent, the presence of the revision property will result in an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{mbox:"mailto:bob@example.com",objectType:"Agent"},context:{revision:"1.0"}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.context.revision","MUST_VIOLATION")).to.be.true;});it("if the statement's object is an Group, the presence of the revision property will result in an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{mbox:"mailto:group@example.com",objectType:"Group"},context:{revision:"1.0"}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.context.revision","MUST_VIOLATION")).to.be.true;});it("a String revision property produces no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:{revision:"1.0"}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("a non-String numeric revision property will result in an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:{revision:1.0}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.context.revision","MUST_VIOLATION")).to.be.true;});it("a null revision property will result in an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:{revision:null}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.context.revision","MUST_VIOLATION")).to.be.true;});/// +it("if the statement's object is an Agent, the presence of the platform property will result in an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{mbox:"mailto:bob@example.com",objectType:"Agent"},context:{platform:"1.0"}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.context.platform","MUST_VIOLATION")).to.be.true;});it("if the statement's object is an Group, the presence of the platform property will result in an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{mbox:"mailto:group@example.com",objectType:"Group"},context:{platform:"1.0"}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.context.platform","MUST_VIOLATION")).to.be.true;});it("a String platform property produces no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:{platform:"1.0"}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("a non-String numeric platform property will result in an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:{platform:1.0}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.context.platform","MUST_VIOLATION")).to.be.true;});it("a null platform property will result in an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:{platform:null}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.context.platform","MUST_VIOLATION")).to.be.true;});it("a null team property will result in an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:{team:null}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.context.team","MUST_VIOLATION")).to.be.true;});it("a Group object team property will result in no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:{team:{objectType:"Group",mbox:"mailto:group@example.com"}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("a RFC 5646 string value for the language property will result in no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:{language:"en-US"}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("a non-RFC 5646 string value for the language property will result in an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:{language:"123 totally not RFC compliant"}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.context.language","MUST_VIOLATION")).to.be.true;});it("a null value for the language property will result in an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:{language:null}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.context.language","MUST_VIOLATION")).to.be.true;});it("a non-String value for the language property will result in an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:{language:1}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.context.language","MUST_VIOLATION")).to.be.true;});it("a null value for the context's statement property will result in an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:{statement:null}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.context.statement","MUST_VIOLATION")).to.be.true;});it("an Array value for the context's statement property will result in an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:{statement:[]}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.context.statement","MUST_VIOLATION")).to.be.true;});it("an empty object value for the context's statement property will result in errors",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:{statement:{}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",2);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.context.statement.objectType","MUST_VIOLATION")).to.be.true;(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.context.statement.id","MUST_VIOLATION")).to.be.true;});it("a valid statement reference for the context's statement property will result in no errors",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:{statement:{objectType:"StatementRef",id:"abcdc918-b88b-4b20-a0a5-a4c32391aaa0"}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});});describe("for a context property with a contextActivities property",function(){it("a null contextActivities value produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:{contextActivities:null}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.context.contextActivities","MUST_VIOLATION")).to.be.true;});it("an Array contextActivities value produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:{contextActivities:[]}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.context.contextActivities","MUST_VIOLATION")).to.be.true;});it("an Numeric contextActivities value produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:{contextActivities:1.23}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.context.contextActivities","MUST_VIOLATION")).to.be.true;});it("an empty contextActivities object value produces no errors",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:{contextActivities:{}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("a single Activity parent property value produces a SHOULD warning",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:{contextActivities:{parent:{id:"http://example.com/myOtherActivityUniqueId",objectType:"Activity"}}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.context.contextActivities","SHOULD_VIOLATION")).to.be.true;});it("an empty Array parent property value produces no errors",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:{contextActivities:{parent:[]}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("an Array with a valid Activity in the parent property produces no errors",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:{contextActivities:{parent:[{id:"http://example.com/myOtherActivityUniqueId",objectType:"Activity"}]}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("an Array with a invalid Activity in the parent property produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},context:{contextActivities:{parent:[{objectType:"Activity"}]}}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.context.contextActivities.parent[0].id","MUST_VIOLATION")).to.be.true;});});describe("given a timestamp property on the statement",function(){it("a null value produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},timestamp:null};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.timestamp","MUST_VIOLATION")).to.be.true;});it("a numeric value produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},timestamp:1.23};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.timestamp","MUST_VIOLATION")).to.be.true;});it("a Date value produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},timestamp:new Date()};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.timestamp","MUST_VIOLATION")).to.be.true;});it("a String value not in ISO 8601 produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},timestamp:"totally wrong"};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.timestamp","MUST_VIOLATION")).to.be.true;});it("a String value with ISO 8601 at UTC via Z produces no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},timestamp:"2013-05-09T14:45:15Z"};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("a String value with ISO 8601 at UTC via Z with millisecond precision produces no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},timestamp:"2013-05-09T14:45:15.008Z"};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("a String value with ISO 8601 with a positive timezone offset hour produces no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},timestamp:"2013-05-09T14:45:15+01"};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("a String value with ISO 8601 with a positive timezone offset hour and minutes produces no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},timestamp:"2013-05-09T14:45:15+01:02"};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("a String value with ISO 8601 with a negative timezone offset hour produces no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},timestamp:"2013-05-09T14:45:15-01"};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("a String value with ISO 8601 with a negative timezone offset hour and minutes produces no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},timestamp:"2013-05-09T14:45:15-01:02"};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("a String value with ISO8601 with no timezone offset or Z produces a SHOULD error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},timestamp:"2013-05-09T14:45:15"};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.timestamp","SHOULD_VIOLATION")).to.be.true;});});describe("given a stored property on the statement",function(){it("a null value produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},stored:null};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.stored","MUST_VIOLATION")).to.be.true;});it("a numeric value produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},stored:1.23};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.stored","MUST_VIOLATION")).to.be.true;});it("a Date value produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},stored:new Date()};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.stored","MUST_VIOLATION")).to.be.true;});it("a String value not in ISO 8601 produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},stored:"totally wrong"};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.stored","MUST_VIOLATION")).to.be.true;});it("a String value with ISO 8601 at UTC via Z produces no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},stored:"2013-05-09T14:45:15Z"};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("a String value with ISO 8601 at UTC via Z with millisecond precision produces no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},stored:"2013-05-09T14:45:15.008Z"};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("a String value with ISO 8601 with a positive timezone offset hour produces no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},stored:"2013-05-09T14:45:15+01"};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("a String value with ISO 8601 with a positive timezone offset hour and minutes produces no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},stored:"2013-05-09T14:45:15+01:02"};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("a String value with ISO 8601 with a negative timezone offset hour produces no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},stored:"2013-05-09T14:45:15-01"};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("a String value with ISO 8601 with a negative timezone offset hour and minutes produces no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},stored:"2013-05-09T14:45:15-01:02"};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("a String value with ISO8601 with no timezone offset or Z produces a SHOULD error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},stored:"2013-05-09T14:45:15"};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.stored","SHOULD_VIOLATION")).to.be.true;});});describe("for a non-object authority property on the statement",function(){it("a null authority value produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},authority:null};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.authority","MUST_VIOLATION")).to.be.true;});it("an Array authority value produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},authority:[]};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.authority","MUST_VIOLATION")).to.be.true;});it("an Numeric authority value produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},authority:[]};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.authority","MUST_VIOLATION")).to.be.true;});});describe("for an authority property with an object value on the statement",function(){it("an Agent authority value produces no errors",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},authority:{objectType:"Agent",mbox:"mailto:bob@example.com"}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("an Agent authority value produces an error if an invalid Agent",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},authority:{objectType:"Agent"}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.authority","MUST_VIOLATION")).to.be.true;});it("an Group authority value with two members produces no errors",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},authority:{objectType:"Group",member:[{objectType:"Agent",mbox:"mailto:bob@example.com"},{objectType:"Agent",mbox:"mailto:tom@example.com"}]}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("an Group authority value with less than two members produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},authority:{objectType:"Group",member:[{objectType:"Agent",mbox:"mailto:bob@example.com"}]}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.authority.member","MUST_VIOLATION")).to.be.true;});it("an Group authority value with more than two members produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},authority:{objectType:"Group",member:[{objectType:"Agent",mbox:"mailto:bob@example.com"},{objectType:"Agent",mbox:"mailto:tom@example.com"},{objectType:"Agent",mbox:"mailto:frank@example.com"}]}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.authority.member","MUST_VIOLATION")).to.be.true;});it("an Group authority value with an invalid member produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},authority:{objectType:"Group",member:[{objectType:"Agent",mbox:"mailto:bob@example.com"},{objectType:"Agent"}]}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.authority.member[1]","MUST_VIOLATION")).to.be.true;});});describe("for an version property on the statement with a non-string value",function(){it("a null value produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},version:null};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.version","MUST_VIOLATION")).to.be.true;});it("a numeric value produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},version:1.0};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.version","MUST_VIOLATION")).to.be.true;});});describe("for an version property with a string value",function(){it("a simple semantic version produces no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},version:"1.0.0"};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("a semantic version with intermixed non-numbers in the major/minor/patch produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},version:"1.0.a"};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.version","MUST_VIOLATION")).to.be.true;});it("a semantic version with valid pre-release info produces no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},version:"1.0.0-rc1"};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("a semantic version with invalid pre-release info produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},version:"1.0.0-rc.1"};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.version","MUST_VIOLATION")).to.be.true;});it("a semantic version with SemVer 2.0.0 build release info characters not in SemVer 1.0.0 produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},version:"1.0.0-alpha.1"};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.version","MUST_VIOLATION")).to.be.true;});it("a semantic version with SemVer 2.0.0 build release metadata not in SemVer 1.0.0 produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},version:"1.0.0-alpha+001"};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.version","MUST_VIOLATION")).to.be.true;});});describe("for an attachments property on the statement with a non-Array value",function(){it("a null value produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},attachments:null};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.attachments","MUST_VIOLATION")).to.be.true;});it("a numeric value produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},attachments:1.0};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.attachments","MUST_VIOLATION")).to.be.true;});it("an object map value produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},attachments:{}};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.attachments","MUST_VIOLATION")).to.be.true;});});describe("for an attachments property on the statement with an Array value",function(){it("an empty Array produces no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},attachments:[]};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});});describe("for an attachment object within the attachments property's Array on the statement",function(){it("a null object produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},attachments:[null]};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.attachments[0]","MUST_VIOLATION")).to.be.true;});it("minimal valid attachment object produces no error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},attachments:[{usageType:"http://example.com/usage/info/A",display:{},contentType:"text/plain",length:11,sha2:"uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek="}]};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",0);});it("an absent usageType property object produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},attachments:[{display:{},contentType:"text/plain",length:11,sha2:"uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek="}]};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.attachments[0].usageType","MUST_VIOLATION")).to.be.true;});it("a null usageType property object produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},attachments:[{usageType:null,display:{},contentType:"text/plain",length:11,sha2:"uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek="}]};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.attachments[0].usageType","MUST_VIOLATION")).to.be.true;});it("a numeric usageType property object produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},attachments:[{usageType:123,display:{},contentType:"text/plain",length:11,sha2:"uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek="}]};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.attachments[0].usageType","MUST_VIOLATION")).to.be.true;});it("an object usageType property object produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},attachments:[{usageType:{},display:{},contentType:"text/plain",length:11,sha2:"uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek="}]};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.attachments[0].usageType","MUST_VIOLATION")).to.be.true;});it("an absent contentType property object produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},attachments:[{usageType:"http://example.com/usage/info/A",display:{},length:11,sha2:"uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek="}]};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.attachments[0].contentType","MUST_VIOLATION")).to.be.true;});it("a null contentType property object produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},attachments:[{usageType:"http://example.com/usage/info/A",display:{},contentType:null,length:11,sha2:"uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek="}]};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.attachments[0].contentType","MUST_VIOLATION")).to.be.true;});it("an absent length property object produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},attachments:[{usageType:"http://example.com/usage/info/A",display:{},contentType:"text/plain",sha2:"uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek="}]};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.attachments[0].length","MUST_VIOLATION")).to.be.true;});it("a null length property object produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},attachments:[{usageType:"http://example.com/usage/info/A",display:{},contentType:"text/plain",length:null,sha2:"uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek="}]};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.attachments[0].length","MUST_VIOLATION")).to.be.true;});it("a string length property object produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},attachments:[{usageType:"http://example.com/usage/info/A",display:{},contentType:"text/plain",length:"11",sha2:"uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek="}]};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.attachments[0].length","MUST_VIOLATION")).to.be.true;});it("a non-integer length property object produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},attachments:[{usageType:"http://example.com/usage/info/A",display:{},contentType:"text/plain",length:11.5,sha2:"uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek="}]};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.attachments[0].length","MUST_VIOLATION")).to.be.true;});it("a null sha2 property produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},attachments:[{usageType:"http://example.com/usage/info/A",display:{},contentType:"text/plain",length:11,sha2:null}]};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.attachments[0].sha2","MUST_VIOLATION")).to.be.true;});it("an absent sha2 property produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},attachments:[{usageType:"http://example.com/usage/info/A",display:{},contentType:"text/plain",length:11}]};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.attachments[0].sha2","MUST_VIOLATION")).to.be.true;});it("a numeric sha2 property produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},attachments:[{usageType:"http://example.com/usage/info/A",display:{},contentType:"text/plain",length:11,sha2:1.23}]};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.attachments[0].sha2","MUST_VIOLATION")).to.be.true;});it("a non-base64 sha2 property object produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},attachments:[{usageType:"http://example.com/usage/info/A",display:{},contentType:"text/plain",length:11,sha2:"uses ~ - characters &^% not in base64"}]};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.attachments[0].sha2","MUST_VIOLATION")).to.be.true;});it("a null fileUrl property produces an error",function(){var inputStatement={id:"fd41c918-b88b-4b20-a0a5-a4c32391aaa0",actor:{mbox:"mailto:agent@example.com"},verb:{"id":"http://adlnet.gov/expapi/verbs/created","display":{"en-US":"created"}},object:{id:"http://example.com/myUniqueId",objectType:"Activity"},attachments:[{usageType:"http://example.com/usage/info/A",display:{},fileUrl:null,contentType:"text/plain",length:11,sha2:"uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek="}]};var results=_xapiValidator.xapiValidator.validateStatement(inputStatement);(0,_chai.expect)(results.errors).to.have.property("length",1);(0,_chai.expect)(reportHasErrorWithTracePrefix(results,"statement.attachments[0].fileUrl","MUST_VIOLATION")).to.be.true;});});});});}); + +},{"../src/xapiValidator":48,"chai":4,"underscore":41}]},{},[49])(49) +}); +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJub2RlX21vZHVsZXMvYXNzZXJ0aW9uLWVycm9yL2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2Jhc2U2NC1qcy9pbmRleC5qcyIsIm5vZGVfbW9kdWxlcy9idWZmZXIvaW5kZXguanMiLCJub2RlX21vZHVsZXMvY2hhaS9pbmRleC5qcyIsIm5vZGVfbW9kdWxlcy9jaGFpL2xpYi9jaGFpLmpzIiwibm9kZV9tb2R1bGVzL2NoYWkvbGliL2NoYWkvYXNzZXJ0aW9uLmpzIiwibm9kZV9tb2R1bGVzL2NoYWkvbGliL2NoYWkvY29uZmlnLmpzIiwibm9kZV9tb2R1bGVzL2NoYWkvbGliL2NoYWkvY29yZS9hc3NlcnRpb25zLmpzIiwibm9kZV9tb2R1bGVzL2NoYWkvbGliL2NoYWkvaW50ZXJmYWNlL2Fzc2VydC5qcyIsIm5vZGVfbW9kdWxlcy9jaGFpL2xpYi9jaGFpL2ludGVyZmFjZS9leHBlY3QuanMiLCJub2RlX21vZHVsZXMvY2hhaS9saWIvY2hhaS9pbnRlcmZhY2Uvc2hvdWxkLmpzIiwibm9kZV9tb2R1bGVzL2NoYWkvbGliL2NoYWkvdXRpbHMvYWRkQ2hhaW5hYmxlTWV0aG9kLmpzIiwibm9kZV9tb2R1bGVzL2NoYWkvbGliL2NoYWkvdXRpbHMvYWRkTWV0aG9kLmpzIiwibm9kZV9tb2R1bGVzL2NoYWkvbGliL2NoYWkvdXRpbHMvYWRkUHJvcGVydHkuanMiLCJub2RlX21vZHVsZXMvY2hhaS9saWIvY2hhaS91dGlscy9leHBlY3RUeXBlcy5qcyIsIm5vZGVfbW9kdWxlcy9jaGFpL2xpYi9jaGFpL3V0aWxzL2ZsYWcuanMiLCJub2RlX21vZHVsZXMvY2hhaS9saWIvY2hhaS91dGlscy9nZXRBY3R1YWwuanMiLCJub2RlX21vZHVsZXMvY2hhaS9saWIvY2hhaS91dGlscy9nZXRFbnVtZXJhYmxlUHJvcGVydGllcy5qcyIsIm5vZGVfbW9kdWxlcy9jaGFpL2xpYi9jaGFpL3V0aWxzL2dldE1lc3NhZ2UuanMiLCJub2RlX21vZHVsZXMvY2hhaS9saWIvY2hhaS91dGlscy9nZXROYW1lLmpzIiwibm9kZV9tb2R1bGVzL2NoYWkvbGliL2NoYWkvdXRpbHMvZ2V0UGF0aEluZm8uanMiLCJub2RlX21vZHVsZXMvY2hhaS9saWIvY2hhaS91dGlscy9nZXRQYXRoVmFsdWUuanMiLCJub2RlX21vZHVsZXMvY2hhaS9saWIvY2hhaS91dGlscy9nZXRQcm9wZXJ0aWVzLmpzIiwibm9kZV9tb2R1bGVzL2NoYWkvbGliL2NoYWkvdXRpbHMvaGFzUHJvcGVydHkuanMiLCJub2RlX21vZHVsZXMvY2hhaS9saWIvY2hhaS91dGlscy9pbmRleC5qcyIsIm5vZGVfbW9kdWxlcy9jaGFpL2xpYi9jaGFpL3V0aWxzL2luc3BlY3QuanMiLCJub2RlX21vZHVsZXMvY2hhaS9saWIvY2hhaS91dGlscy9vYmpEaXNwbGF5LmpzIiwibm9kZV9tb2R1bGVzL2NoYWkvbGliL2NoYWkvdXRpbHMvb3ZlcndyaXRlQ2hhaW5hYmxlTWV0aG9kLmpzIiwibm9kZV9tb2R1bGVzL2NoYWkvbGliL2NoYWkvdXRpbHMvb3ZlcndyaXRlTWV0aG9kLmpzIiwibm9kZV9tb2R1bGVzL2NoYWkvbGliL2NoYWkvdXRpbHMvb3ZlcndyaXRlUHJvcGVydHkuanMiLCJub2RlX21vZHVsZXMvY2hhaS9saWIvY2hhaS91dGlscy90ZXN0LmpzIiwibm9kZV9tb2R1bGVzL2NoYWkvbGliL2NoYWkvdXRpbHMvdHJhbnNmZXJGbGFncy5qcyIsIm5vZGVfbW9kdWxlcy9kZWVwLWVxbC9pbmRleC5qcyIsIm5vZGVfbW9kdWxlcy9kZWVwLWVxbC9saWIvZXFsLmpzIiwibm9kZV9tb2R1bGVzL2RlZXAtZXFsL25vZGVfbW9kdWxlcy90eXBlLWRldGVjdC9pbmRleC5qcyIsIm5vZGVfbW9kdWxlcy9kZWVwLWVxbC9ub2RlX21vZHVsZXMvdHlwZS1kZXRlY3QvbGliL3R5cGUuanMiLCJub2RlX21vZHVsZXMvaWVlZTc1NC9pbmRleC5qcyIsIm5vZGVfbW9kdWxlcy9pc2FycmF5L2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL3R5cGUtZGV0ZWN0L2xpYi90eXBlLmpzIiwibm9kZV9tb2R1bGVzL3VuZGVyc2NvcmUvdW5kZXJzY29yZS5qcyIsInNyYy9jb25zdGFudHMvZXJyb3JzLmpzIiwic3JjL2NvbnN0YW50cy9nZW5lcmFsLmpzIiwic3JjL2NvbnN0YW50cy9pbnRlcmFjdGlvbi10eXBlcy5qcyIsInNyYy9jb25zdGFudHMvcHJvcGVydGllcy5qcyIsInNyYy9jb25zdGFudHMvcmVnZXguanMiLCJzcmMvdXRpbHMvdXRpbHMuanMiLCJzcmMveGFwaVZhbGlkYXRvci5qcyIsInRlc3QveGFwaVZhbGlkYXRvci50ZXN0LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FDbEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUM3dkRBO0FBQ0E7O0FDREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN0ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcDBEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdtREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDek1BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25EQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbElBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvVUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN0NBO0FBQ0E7O0FDREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pRQTtBQUNBOztBQ0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUlBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUNMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdElBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FB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dkIsQ0FBMEIsSUFBMUIsQ0FBK0IsUUFBL0IsQ0FBd0MsUUFBeEMsQ0FBa0QsQ0FBbEQsRUFDQSxpQkFBTyw4QkFBOEIsT0FBOUIsQ0FBdUMsa0NBQXZDLENBQTJFLGdCQUEzRSxDQUFQLEVBQXFHLEVBQXJHLENBQXdHLEVBQXhHLENBQTJHLElBQTNHLENBQ0gsQ0FURCxFQVVELENBMUxELEVBMkxELENBbG5ERCxFQW1uREQsQ0EvbUVELEVBZ25FRCxDQWpuRUQiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKTt0aHJvdyBmLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30pIiwiLyohXG4gKiBhc3NlcnRpb24tZXJyb3JcbiAqIENvcHlyaWdodChjKSAyMDEzIEpha2UgTHVlciA8amFrZUBxdWFsaWFuY3kuY29tPlxuICogTUlUIExpY2Vuc2VkXG4gKi9cblxuLyohXG4gKiBSZXR1cm4gYSBmdW5jdGlvbiB0aGF0IHdpbGwgY29weSBwcm9wZXJ0aWVzIGZyb21cbiAqIG9uZSBvYmplY3QgdG8gYW5vdGhlciBleGNsdWRpbmcgYW55IG9yaWdpbmFsbHlcbiAqIGxpc3RlZC4gUmV0dXJuZWQgZnVuY3Rpb24gd2lsbCBjcmVhdGUgYSBuZXcgYHt9YC5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gZXhjbHVkZWQgcHJvcGVydGllcyAuLi5cbiAqIEByZXR1cm4ge0Z1bmN0aW9ufVxuICovXG5cbmZ1bmN0aW9uIGV4Y2x1ZGUgKCkge1xuICB2YXIgZXhjbHVkZXMgPSBbXS5zbGljZS5jYWxsKGFyZ3VtZW50cyk7XG5cbiAgZnVuY3Rpb24gZXhjbHVkZVByb3BzIChyZXMsIG9iaikge1xuICAgIE9iamVjdC5rZXlzKG9iaikuZm9yRWFjaChmdW5jdGlvbiAoa2V5KSB7XG4gICAgICBpZiAoIX5leGNsdWRlcy5pbmRleE9mKGtleSkpIHJlc1trZXldID0gb2JqW2tleV07XG4gICAgfSk7XG4gIH1cblxuICByZXR1cm4gZnVuY3Rpb24gZXh0ZW5kRXhjbHVkZSAoKSB7XG4gICAgdmFyIGFyZ3MgPSBbXS5zbGljZS5jYWxsKGFyZ3VtZW50cylcbiAgICAgICwgaSA9IDBcbiAgICAgICwgcmVzID0ge307XG5cbiAgICBmb3IgKDsgaSA8IGFyZ3MubGVuZ3RoOyBpKyspIHtcbiAgICAgIGV4Y2x1ZGVQcm9wcyhyZXMsIGFyZ3NbaV0pO1xuICAgIH1cblxuICAgIHJldHVybiByZXM7XG4gIH07XG59O1xuXG4vKiFcbiAqIFByaW1hcnkgRXhwb3J0c1xuICovXG5cbm1vZHVsZS5leHBvcnRzID0gQXNzZXJ0aW9uRXJyb3I7XG5cbi8qKlxuICogIyMjIEFzc2VydGlvbkVycm9yXG4gKlxuICogQW4gZXh0ZW5zaW9uIG9mIHRoZSBKYXZhU2NyaXB0IGBFcnJvcmAgY29uc3RydWN0b3IgZm9yXG4gKiBhc3NlcnRpb24gYW5kIHZhbGlkYXRpb24gc2NlbmFyaW9zLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlXG4gKiBAcGFyYW0ge09iamVjdH0gcHJvcGVydGllcyB0byBpbmNsdWRlIChvcHRpb25hbClcbiAqIEBwYXJhbSB7Y2FsbGVlfSBzdGFydCBzdGFjayBmdW5jdGlvbiAob3B0aW9uYWwpXG4gKi9cblxuZnVuY3Rpb24gQXNzZXJ0aW9uRXJyb3IgKG1lc3NhZ2UsIF9wcm9wcywgc3NmKSB7XG4gIHZhciBleHRlbmQgPSBleGNsdWRlKCduYW1lJywgJ21lc3NhZ2UnLCAnc3RhY2snLCAnY29uc3RydWN0b3InLCAndG9KU09OJylcbiAgICAsIHByb3BzID0gZXh0ZW5kKF9wcm9wcyB8fCB7fSk7XG5cbiAgLy8gZGVmYXVsdCB2YWx1ZXNcbiAgdGhpcy5tZXNzYWdlID0gbWVzc2FnZSB8fCAnVW5zcGVjaWZpZWQgQXNzZXJ0aW9uRXJyb3InO1xuICB0aGlzLnNob3dEaWZmID0gZmFsc2U7XG5cbiAgLy8gY29weSBmcm9tIHByb3BlcnRpZXNcbiAgZm9yICh2YXIga2V5IGluIHByb3BzKSB7XG4gICAgdGhpc1trZXldID0gcHJvcHNba2V5XTtcbiAgfVxuXG4gIC8vIGNhcHR1cmUgc3RhY2sgdHJhY2VcbiAgc3NmID0gc3NmIHx8IGFyZ3VtZW50cy5jYWxsZWU7XG4gIGlmIChzc2YgJiYgRXJyb3IuY2FwdHVyZVN0YWNrVHJhY2UpIHtcbiAgICBFcnJvci5jYXB0dXJlU3RhY2tUcmFjZSh0aGlzLCBzc2YpO1xuICB9IGVsc2Uge1xuICAgIHRyeSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoKTtcbiAgICB9IGNhdGNoKGUpIHtcbiAgICAgIHRoaXMuc3RhY2sgPSBlLnN0YWNrO1xuICAgIH1cbiAgfVxufVxuXG4vKiFcbiAqIEluaGVyaXQgZnJvbSBFcnJvci5wcm90b3R5cGVcbiAqL1xuXG5Bc3NlcnRpb25FcnJvci5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKEVycm9yLnByb3RvdHlwZSk7XG5cbi8qIVxuICogU3RhdGljYWxseSBzZXQgbmFtZVxuICovXG5cbkFzc2VydGlvbkVycm9yLnByb3RvdHlwZS5uYW1lID0gJ0Fzc2VydGlvbkVycm9yJztcblxuLyohXG4gKiBFbnN1cmUgY29ycmVjdCBjb25zdHJ1Y3RvclxuICovXG5cbkFzc2VydGlvbkVycm9yLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IEFzc2VydGlvbkVycm9yO1xuXG4vKipcbiAqIEFsbG93IGVycm9ycyB0byBiZSBjb252ZXJ0ZWQgdG8gSlNPTiBmb3Igc3RhdGljIHRyYW5zZmVyLlxuICpcbiAqIEBwYXJhbSB7Qm9vbGVhbn0gaW5jbHVkZSBzdGFjayAoZGVmYXVsdDogYHRydWVgKVxuICogQHJldHVybiB7T2JqZWN0fSBvYmplY3QgdGhhdCBjYW4gYmUgYEpTT04uc3RyaW5naWZ5YFxuICovXG5cbkFzc2VydGlvbkVycm9yLnByb3RvdHlwZS50b0pTT04gPSBmdW5jdGlvbiAoc3RhY2spIHtcbiAgdmFyIGV4dGVuZCA9IGV4Y2x1ZGUoJ2NvbnN0cnVjdG9yJywgJ3RvSlNPTicsICdzdGFjaycpXG4gICAgLCBwcm9wcyA9IGV4dGVuZCh7IG5hbWU6IHRoaXMubmFtZSB9LCB0aGlzKTtcblxuICAvLyBpbmNsdWRlIHN0YWNrIGlmIGV4aXN0cyBhbmQgbm90IHR1cm5lZCBvZmZcbiAgaWYgKGZhbHNlICE9PSBzdGFjayAmJiB0aGlzLnN0YWNrKSB7XG4gICAgcHJvcHMuc3RhY2sgPSB0aGlzLnN0YWNrO1xuICB9XG5cbiAgcmV0dXJuIHByb3BzO1xufTtcbiIsIid1c2Ugc3RyaWN0J1xuXG5leHBvcnRzLmJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoXG5leHBvcnRzLnRvQnl0ZUFycmF5ID0gdG9CeXRlQXJyYXlcbmV4cG9ydHMuZnJvbUJ5dGVBcnJheSA9IGZyb21CeXRlQXJyYXlcblxudmFyIGxvb2t1cCA9IFtdXG52YXIgcmV2TG9va3VwID0gW11cbnZhciBBcnIgPSB0eXBlb2YgVWludDhBcnJheSAhPT0gJ3VuZGVmaW5lZCcgPyBVaW50OEFycmF5IDogQXJyYXlcblxudmFyIGNvZGUgPSAnQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODkrLydcbmZvciAodmFyIGkgPSAwLCBsZW4gPSBjb2RlLmxlbmd0aDsgaSA8IGxlbjsgKytpKSB7XG4gIGxvb2t1cFtpXSA9IGNvZGVbaV1cbiAgcmV2TG9va3VwW2NvZGUuY2hhckNvZGVBdChpKV0gPSBpXG59XG5cbnJldkxvb2t1cFsnLScuY2hhckNvZGVBdCgwKV0gPSA2MlxucmV2TG9va3VwWydfJy5jaGFyQ29kZUF0KDApXSA9IDYzXG5cbmZ1bmN0aW9uIHBsYWNlSG9sZGVyc0NvdW50IChiNjQpIHtcbiAgdmFyIGxlbiA9IGI2NC5sZW5ndGhcbiAgaWYgKGxlbiAlIDQgPiAwKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIHN0cmluZy4gTGVuZ3RoIG11c3QgYmUgYSBtdWx0aXBsZSBvZiA0JylcbiAgfVxuXG4gIC8vIHRoZSBudW1iZXIgb2YgZXF1YWwgc2lnbnMgKHBsYWNlIGhvbGRlcnMpXG4gIC8vIGlmIHRoZXJlIGFyZSB0d28gcGxhY2Vob2xkZXJzLCB0aGFuIHRoZSB0d28gY2hhcmFjdGVycyBiZWZvcmUgaXRcbiAgLy8gcmVwcmVzZW50IG9uZSBieXRlXG4gIC8vIGlmIHRoZXJlIGlzIG9ubHkgb25lLCB0aGVuIHRoZSB0aHJlZSBjaGFyYWN0ZXJzIGJlZm9yZSBpdCByZXByZXNlbnQgMiBieXRlc1xuICAvLyB0aGlzIGlzIGp1c3QgYSBjaGVhcCBoYWNrIHRvIG5vdCBkbyBpbmRleE9mIHR3aWNlXG4gIHJldHVybiBiNjRbbGVuIC0gMl0gPT09ICc9JyA/IDIgOiBiNjRbbGVuIC0gMV0gPT09ICc9JyA/IDEgOiAwXG59XG5cbmZ1bmN0aW9uIGJ5dGVMZW5ndGggKGI2NCkge1xuICAvLyBiYXNlNjQgaXMgNC8zICsgdXAgdG8gdHdvIGNoYXJhY3RlcnMgb2YgdGhlIG9yaWdpbmFsIGRhdGFcbiAgcmV0dXJuIGI2NC5sZW5ndGggKiAzIC8gNCAtIHBsYWNlSG9sZGVyc0NvdW50KGI2NClcbn1cblxuZnVuY3Rpb24gdG9CeXRlQXJyYXkgKGI2NCkge1xuICB2YXIgaSwgaiwgbCwgdG1wLCBwbGFjZUhvbGRlcnMsIGFyclxuICB2YXIgbGVuID0gYjY0Lmxlbmd0aFxuICBwbGFjZUhvbGRlcnMgPSBwbGFjZUhvbGRlcnNDb3VudChiNjQpXG5cbiAgYXJyID0gbmV3IEFycihsZW4gKiAzIC8gNCAtIHBsYWNlSG9sZGVycylcblxuICAvLyBpZiB0aGVyZSBhcmUgcGxhY2Vob2xkZXJzLCBvbmx5IGdldCB1cCB0byB0aGUgbGFzdCBjb21wbGV0ZSA0IGNoYXJzXG4gIGwgPSBwbGFjZUhvbGRlcnMgPiAwID8gbGVuIC0gNCA6IGxlblxuXG4gIHZhciBMID0gMFxuXG4gIGZvciAoaSA9IDAsIGogPSAwOyBpIDwgbDsgaSArPSA0LCBqICs9IDMpIHtcbiAgICB0bXAgPSAocmV2TG9va3VwW2I2NC5jaGFyQ29kZUF0KGkpXSA8PCAxOCkgfCAocmV2TG9va3VwW2I2NC5jaGFyQ29kZUF0KGkgKyAxKV0gPDwgMTIpIHwgKHJldkxvb2t1cFtiNjQuY2hhckNvZGVBdChpICsgMildIDw8IDYpIHwgcmV2TG9va3VwW2I2NC5jaGFyQ29kZUF0KGkgKyAzKV1cbiAgICBhcnJbTCsrXSA9ICh0bXAgPj4gMTYpICYgMHhGRlxuICAgIGFycltMKytdID0gKHRtcCA+PiA4KSAmIDB4RkZcbiAgICBhcnJbTCsrXSA9IHRtcCAmIDB4RkZcbiAgfVxuXG4gIGlmIChwbGFjZUhvbGRlcnMgPT09IDIpIHtcbiAgICB0bXAgPSAocmV2TG9va3VwW2I2NC5jaGFyQ29kZUF0KGkpXSA8PCAyKSB8IChyZXZMb29rdXBbYjY0LmNoYXJDb2RlQXQoaSArIDEpXSA+PiA0KVxuICAgIGFycltMKytdID0gdG1wICYgMHhGRlxuICB9IGVsc2UgaWYgKHBsYWNlSG9sZGVycyA9PT0gMSkge1xuICAgIHRtcCA9IChyZXZMb29rdXBbYjY0LmNoYXJDb2RlQXQoaSldIDw8IDEwKSB8IChyZXZMb29rdXBbYjY0LmNoYXJDb2RlQXQoaSArIDEpXSA8PCA0KSB8IChyZXZMb29rdXBbYjY0LmNoYXJDb2RlQXQoaSArIDIpXSA+PiAyKVxuICAgIGFycltMKytdID0gKHRtcCA+PiA4KSAmIDB4RkZcbiAgICBhcnJbTCsrXSA9IHRtcCAmIDB4RkZcbiAgfVxuXG4gIHJldHVybiBhcnJcbn1cblxuZnVuY3Rpb24gdHJpcGxldFRvQmFzZTY0IChudW0pIHtcbiAgcmV0dXJuIGxvb2t1cFtudW0gPj4gMTggJiAweDNGXSArIGxvb2t1cFtudW0gPj4gMTIgJiAweDNGXSArIGxvb2t1cFtudW0gPj4gNiAmIDB4M0ZdICsgbG9va3VwW251bSAmIDB4M0ZdXG59XG5cbmZ1bmN0aW9uIGVuY29kZUNodW5rICh1aW50OCwgc3RhcnQsIGVuZCkge1xuICB2YXIgdG1wXG4gIHZhciBvdXRwdXQgPSBbXVxuICBmb3IgKHZhciBpID0gc3RhcnQ7IGkgPCBlbmQ7IGkgKz0gMykge1xuICAgIHRtcCA9ICh1aW50OFtpXSA8PCAxNikgKyAodWludDhbaSArIDFdIDw8IDgpICsgKHVpbnQ4W2kgKyAyXSlcbiAgICBvdXRwdXQucHVzaCh0cmlwbGV0VG9CYXNlNjQodG1wKSlcbiAgfVxuICByZXR1cm4gb3V0cHV0LmpvaW4oJycpXG59XG5cbmZ1bmN0aW9uIGZyb21CeXRlQXJyYXkgKHVpbnQ4KSB7XG4gIHZhciB0bXBcbiAgdmFyIGxlbiA9IHVpbnQ4Lmxlbmd0aFxuICB2YXIgZXh0cmFCeXRlcyA9IGxlbiAlIDMgLy8gaWYgd2UgaGF2ZSAxIGJ5dGUgbGVmdCwgcGFkIDIgYnl0ZXNcbiAgdmFyIG91dHB1dCA9ICcnXG4gIHZhciBwYXJ0cyA9IFtdXG4gIHZhciBtYXhDaHVua0xlbmd0aCA9IDE2MzgzIC8vIG11c3QgYmUgbXVsdGlwbGUgb2YgM1xuXG4gIC8vIGdvIHRocm91Z2ggdGhlIGFycmF5IGV2ZXJ5IHRocmVlIGJ5dGVzLCB3ZSdsbCBkZWFsIHdpdGggdHJhaWxpbmcgc3R1ZmYgbGF0ZXJcbiAgZm9yICh2YXIgaSA9IDAsIGxlbjIgPSBsZW4gLSBleHRyYUJ5dGVzOyBpIDwgbGVuMjsgaSArPSBtYXhDaHVua0xlbmd0aCkge1xuICAgIHBhcnRzLnB1c2goZW5jb2RlQ2h1bmsodWludDgsIGksIChpICsgbWF4Q2h1bmtMZW5ndGgpID4gbGVuMiA/IGxlbjIgOiAoaSArIG1heENodW5rTGVuZ3RoKSkpXG4gIH1cblxuICAvLyBwYWQgdGhlIGVuZCB3aXRoIHplcm9zLCBidXQgbWFrZSBzdXJlIHRvIG5vdCBmb3JnZXQgdGhlIGV4dHJhIGJ5dGVzXG4gIGlmIChleHRyYUJ5dGVzID09PSAxKSB7XG4gICAgdG1wID0gdWludDhbbGVuIC0gMV1cbiAgICBvdXRwdXQgKz0gbG9va3VwW3RtcCA+PiAyXVxuICAgIG91dHB1dCArPSBsb29rdXBbKHRtcCA8PCA0KSAmIDB4M0ZdXG4gICAgb3V0cHV0ICs9ICc9PSdcbiAgfSBlbHNlIGlmIChleHRyYUJ5dGVzID09PSAyKSB7XG4gICAgdG1wID0gKHVpbnQ4W2xlbiAtIDJdIDw8IDgpICsgKHVpbnQ4W2xlbiAtIDFdKVxuICAgIG91dHB1dCArPSBsb29rdXBbdG1wID4+IDEwXVxuICAgIG91dHB1dCArPSBsb29rdXBbKHRtcCA+PiA0KSAmIDB4M0ZdXG4gICAgb3V0cHV0ICs9IGxvb2t1cFsodG1wIDw8IDIpICYgMHgzRl1cbiAgICBvdXRwdXQgKz0gJz0nXG4gIH1cblxuICBwYXJ0cy5wdXNoKG91dHB1dClcblxuICByZXR1cm4gcGFydHMuam9pbignJylcbn1cbiIsIi8qIVxuICogVGhlIGJ1ZmZlciBtb2R1bGUgZnJvbSBub2RlLmpzLCBmb3IgdGhlIGJyb3dzZXIuXG4gKlxuICogQGF1dGhvciAgIEZlcm9zcyBBYm91a2hhZGlqZWggPGZlcm9zc0BmZXJvc3Mub3JnPiA8aHR0cDovL2Zlcm9zcy5vcmc+XG4gKiBAbGljZW5zZSAgTUlUXG4gKi9cbi8qIGVzbGludC1kaXNhYmxlIG5vLXByb3RvICovXG5cbid1c2Ugc3RyaWN0J1xuXG52YXIgYmFzZTY0ID0gcmVxdWlyZSgnYmFzZTY0LWpzJylcbnZhciBpZWVlNzU0ID0gcmVxdWlyZSgnaWVlZTc1NCcpXG52YXIgaXNBcnJheSA9IHJlcXVpcmUoJ2lzYXJyYXknKVxuXG5leHBvcnRzLkJ1ZmZlciA9IEJ1ZmZlclxuZXhwb3J0cy5TbG93QnVmZmVyID0gU2xvd0J1ZmZlclxuZXhwb3J0cy5JTlNQRUNUX01BWF9CWVRFUyA9IDUwXG5cbi8qKlxuICogSWYgYEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUYDpcbiAqICAgPT09IHRydWUgICAgVXNlIFVpbnQ4QXJyYXkgaW1wbGVtZW50YXRpb24gKGZhc3Rlc3QpXG4gKiAgID09PSBmYWxzZSAgIFVzZSBPYmplY3QgaW1wbGVtZW50YXRpb24gKG1vc3QgY29tcGF0aWJsZSwgZXZlbiBJRTYpXG4gKlxuICogQnJvd3NlcnMgdGhhdCBzdXBwb3J0IHR5cGVkIGFycmF5cyBhcmUgSUUgMTArLCBGaXJlZm94IDQrLCBDaHJvbWUgNyssIFNhZmFyaSA1LjErLFxuICogT3BlcmEgMTEuNissIGlPUyA0LjIrLlxuICpcbiAqIER1ZSB0byB2YXJpb3VzIGJyb3dzZXIgYnVncywgc29tZXRpbWVzIHRoZSBPYmplY3QgaW1wbGVtZW50YXRpb24gd2lsbCBiZSB1c2VkIGV2ZW5cbiAqIHdoZW4gdGhlIGJyb3dzZXIgc3VwcG9ydHMgdHlwZWQgYXJyYXlzLlxuICpcbiAqIE5vdGU6XG4gKlxuICogICAtIEZpcmVmb3ggNC0yOSBsYWNrcyBzdXBwb3J0IGZvciBhZGRpbmcgbmV3IHByb3BlcnRpZXMgdG8gYFVpbnQ4QXJyYXlgIGluc3RhbmNlcyxcbiAqICAgICBTZWU6IGh0dHBzOi8vYnVnemlsbGEubW96aWxsYS5vcmcvc2hvd19idWcuY2dpP2lkPTY5NTQzOC5cbiAqXG4gKiAgIC0gQ2hyb21lIDktMTAgaXMgbWlzc2luZyB0aGUgYFR5cGVkQXJyYXkucHJvdG90eXBlLnN1YmFycmF5YCBmdW5jdGlvbi5cbiAqXG4gKiAgIC0gSUUxMCBoYXMgYSBicm9rZW4gYFR5cGVkQXJyYXkucHJvdG90eXBlLnN1YmFycmF5YCBmdW5jdGlvbiB3aGljaCByZXR1cm5zIGFycmF5cyBvZlxuICogICAgIGluY29ycmVjdCBsZW5ndGggaW4gc29tZSBzaXR1YXRpb25zLlxuXG4gKiBXZSBkZXRlY3QgdGhlc2UgYnVnZ3kgYnJvd3NlcnMgYW5kIHNldCBgQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlRgIHRvIGBmYWxzZWAgc28gdGhleVxuICogZ2V0IHRoZSBPYmplY3QgaW1wbGVtZW50YXRpb24sIHdoaWNoIGlzIHNsb3dlciBidXQgYmVoYXZlcyBjb3JyZWN0bHkuXG4gKi9cbkJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUID0gZ2xvYmFsLlRZUEVEX0FSUkFZX1NVUFBPUlQgIT09IHVuZGVmaW5lZFxuICA/IGdsb2JhbC5UWVBFRF9BUlJBWV9TVVBQT1JUXG4gIDogdHlwZWRBcnJheVN1cHBvcnQoKVxuXG4vKlxuICogRXhwb3J0IGtNYXhMZW5ndGggYWZ0ZXIgdHlwZWQgYXJyYXkgc3VwcG9ydCBpcyBkZXRlcm1pbmVkLlxuICovXG5leHBvcnRzLmtNYXhMZW5ndGggPSBrTWF4TGVuZ3RoKClcblxuZnVuY3Rpb24gdHlwZWRBcnJheVN1cHBvcnQgKCkge1xuICB0cnkge1xuICAgIHZhciBhcnIgPSBuZXcgVWludDhBcnJheSgxKVxuICAgIGFyci5fX3Byb3RvX18gPSB7X19wcm90b19fOiBVaW50OEFycmF5LnByb3RvdHlwZSwgZm9vOiBmdW5jdGlvbiAoKSB7IHJldHVybiA0MiB9fVxuICAgIHJldHVybiBhcnIuZm9vKCkgPT09IDQyICYmIC8vIHR5cGVkIGFycmF5IGluc3RhbmNlcyBjYW4gYmUgYXVnbWVudGVkXG4gICAgICAgIHR5cGVvZiBhcnIuc3ViYXJyYXkgPT09ICdmdW5jdGlvbicgJiYgLy8gY2hyb21lIDktMTAgbGFjayBgc3ViYXJyYXlgXG4gICAgICAgIGFyci5zdWJhcnJheSgxLCAxKS5ieXRlTGVuZ3RoID09PSAwIC8vIGllMTAgaGFzIGJyb2tlbiBgc3ViYXJyYXlgXG4gIH0gY2F0Y2ggKGUpIHtcbiAgICByZXR1cm4gZmFsc2VcbiAgfVxufVxuXG5mdW5jdGlvbiBrTWF4TGVuZ3RoICgpIHtcbiAgcmV0dXJuIEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUXG4gICAgPyAweDdmZmZmZmZmXG4gICAgOiAweDNmZmZmZmZmXG59XG5cbmZ1bmN0aW9uIGNyZWF0ZUJ1ZmZlciAodGhhdCwgbGVuZ3RoKSB7XG4gIGlmIChrTWF4TGVuZ3RoKCkgPCBsZW5ndGgpIHtcbiAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignSW52YWxpZCB0eXBlZCBhcnJheSBsZW5ndGgnKVxuICB9XG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIC8vIFJldHVybiBhbiBhdWdtZW50ZWQgYFVpbnQ4QXJyYXlgIGluc3RhbmNlLCBmb3IgYmVzdCBwZXJmb3JtYW5jZVxuICAgIHRoYXQgPSBuZXcgVWludDhBcnJheShsZW5ndGgpXG4gICAgdGhhdC5fX3Byb3RvX18gPSBCdWZmZXIucHJvdG90eXBlXG4gIH0gZWxzZSB7XG4gICAgLy8gRmFsbGJhY2s6IFJldHVybiBhbiBvYmplY3QgaW5zdGFuY2Ugb2YgdGhlIEJ1ZmZlciBjbGFzc1xuICAgIGlmICh0aGF0ID09PSBudWxsKSB7XG4gICAgICB0aGF0ID0gbmV3IEJ1ZmZlcihsZW5ndGgpXG4gICAgfVxuICAgIHRoYXQubGVuZ3RoID0gbGVuZ3RoXG4gIH1cblxuICByZXR1cm4gdGhhdFxufVxuXG4vKipcbiAqIFRoZSBCdWZmZXIgY29uc3RydWN0b3IgcmV0dXJucyBpbnN0YW5jZXMgb2YgYFVpbnQ4QXJyYXlgIHRoYXQgaGF2ZSB0aGVpclxuICogcHJvdG90eXBlIGNoYW5nZWQgdG8gYEJ1ZmZlci5wcm90b3R5cGVgLiBGdXJ0aGVybW9yZSwgYEJ1ZmZlcmAgaXMgYSBzdWJjbGFzcyBvZlxuICogYFVpbnQ4QXJyYXlgLCBzbyB0aGUgcmV0dXJuZWQgaW5zdGFuY2VzIHdpbGwgaGF2ZSBhbGwgdGhlIG5vZGUgYEJ1ZmZlcmAgbWV0aG9kc1xuICogYW5kIHRoZSBgVWludDhBcnJheWAgbWV0aG9kcy4gU3F1YXJlIGJyYWNrZXQgbm90YXRpb24gd29ya3MgYXMgZXhwZWN0ZWQgLS0gaXRcbiAqIHJldHVybnMgYSBzaW5nbGUgb2N0ZXQuXG4gKlxuICogVGhlIGBVaW50OEFycmF5YCBwcm90b3R5cGUgcmVtYWlucyB1bm1vZGlmaWVkLlxuICovXG5cbmZ1bmN0aW9uIEJ1ZmZlciAoYXJnLCBlbmNvZGluZ09yT2Zmc2V0LCBsZW5ndGgpIHtcbiAgaWYgKCFCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCAmJiAhKHRoaXMgaW5zdGFuY2VvZiBCdWZmZXIpKSB7XG4gICAgcmV0dXJuIG5ldyBCdWZmZXIoYXJnLCBlbmNvZGluZ09yT2Zmc2V0LCBsZW5ndGgpXG4gIH1cblxuICAvLyBDb21tb24gY2FzZS5cbiAgaWYgKHR5cGVvZiBhcmcgPT09ICdudW1iZXInKSB7XG4gICAgaWYgKHR5cGVvZiBlbmNvZGluZ09yT2Zmc2V0ID09PSAnc3RyaW5nJykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAnSWYgZW5jb2RpbmcgaXMgc3BlY2lmaWVkIHRoZW4gdGhlIGZpcnN0IGFyZ3VtZW50IG11c3QgYmUgYSBzdHJpbmcnXG4gICAgICApXG4gICAgfVxuICAgIHJldHVybiBhbGxvY1Vuc2FmZSh0aGlzLCBhcmcpXG4gIH1cbiAgcmV0dXJuIGZyb20odGhpcywgYXJnLCBlbmNvZGluZ09yT2Zmc2V0LCBsZW5ndGgpXG59XG5cbkJ1ZmZlci5wb29sU2l6ZSA9IDgxOTIgLy8gbm90IHVzZWQgYnkgdGhpcyBpbXBsZW1lbnRhdGlvblxuXG4vLyBUT0RPOiBMZWdhY3ksIG5vdCBuZWVkZWQgYW55bW9yZS4gUmVtb3ZlIGluIG5leHQgbWFqb3IgdmVyc2lvbi5cbkJ1ZmZlci5fYXVnbWVudCA9IGZ1bmN0aW9uIChhcnIpIHtcbiAgYXJyLl9fcHJvdG9fXyA9IEJ1ZmZlci5wcm90b3R5cGVcbiAgcmV0dXJuIGFyclxufVxuXG5mdW5jdGlvbiBmcm9tICh0aGF0LCB2YWx1ZSwgZW5jb2RpbmdPck9mZnNldCwgbGVuZ3RoKSB7XG4gIGlmICh0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignXCJ2YWx1ZVwiIGFyZ3VtZW50IG11c3Qgbm90IGJlIGEgbnVtYmVyJylcbiAgfVxuXG4gIGlmICh0eXBlb2YgQXJyYXlCdWZmZXIgIT09ICd1bmRlZmluZWQnICYmIHZhbHVlIGluc3RhbmNlb2YgQXJyYXlCdWZmZXIpIHtcbiAgICByZXR1cm4gZnJvbUFycmF5QnVmZmVyKHRoYXQsIHZhbHVlLCBlbmNvZGluZ09yT2Zmc2V0LCBsZW5ndGgpXG4gIH1cblxuICBpZiAodHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJykge1xuICAgIHJldHVybiBmcm9tU3RyaW5nKHRoYXQsIHZhbHVlLCBlbmNvZGluZ09yT2Zmc2V0KVxuICB9XG5cbiAgcmV0dXJuIGZyb21PYmplY3QodGhhdCwgdmFsdWUpXG59XG5cbi8qKlxuICogRnVuY3Rpb25hbGx5IGVxdWl2YWxlbnQgdG8gQnVmZmVyKGFyZywgZW5jb2RpbmcpIGJ1dCB0aHJvd3MgYSBUeXBlRXJyb3JcbiAqIGlmIHZhbHVlIGlzIGEgbnVtYmVyLlxuICogQnVmZmVyLmZyb20oc3RyWywgZW5jb2RpbmddKVxuICogQnVmZmVyLmZyb20oYXJyYXkpXG4gKiBCdWZmZXIuZnJvbShidWZmZXIpXG4gKiBCdWZmZXIuZnJvbShhcnJheUJ1ZmZlclssIGJ5dGVPZmZzZXRbLCBsZW5ndGhdXSlcbiAqKi9cbkJ1ZmZlci5mcm9tID0gZnVuY3Rpb24gKHZhbHVlLCBlbmNvZGluZ09yT2Zmc2V0LCBsZW5ndGgpIHtcbiAgcmV0dXJuIGZyb20obnVsbCwgdmFsdWUsIGVuY29kaW5nT3JPZmZzZXQsIGxlbmd0aClcbn1cblxuaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gIEJ1ZmZlci5wcm90b3R5cGUuX19wcm90b19fID0gVWludDhBcnJheS5wcm90b3R5cGVcbiAgQnVmZmVyLl9fcHJvdG9fXyA9IFVpbnQ4QXJyYXlcbiAgaWYgKHR5cGVvZiBTeW1ib2wgIT09ICd1bmRlZmluZWQnICYmIFN5bWJvbC5zcGVjaWVzICYmXG4gICAgICBCdWZmZXJbU3ltYm9sLnNwZWNpZXNdID09PSBCdWZmZXIpIHtcbiAgICAvLyBGaXggc3ViYXJyYXkoKSBpbiBFUzIwMTYuIFNlZTogaHR0cHM6Ly9naXRodWIuY29tL2Zlcm9zcy9idWZmZXIvcHVsbC85N1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShCdWZmZXIsIFN5bWJvbC5zcGVjaWVzLCB7XG4gICAgICB2YWx1ZTogbnVsbCxcbiAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZVxuICAgIH0pXG4gIH1cbn1cblxuZnVuY3Rpb24gYXNzZXJ0U2l6ZSAoc2l6ZSkge1xuICBpZiAodHlwZW9mIHNpemUgIT09ICdudW1iZXInKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignXCJzaXplXCIgYXJndW1lbnQgbXVzdCBiZSBhIG51bWJlcicpXG4gIH0gZWxzZSBpZiAoc2l6ZSA8IDApIHtcbiAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignXCJzaXplXCIgYXJndW1lbnQgbXVzdCBub3QgYmUgbmVnYXRpdmUnKVxuICB9XG59XG5cbmZ1bmN0aW9uIGFsbG9jICh0aGF0LCBzaXplLCBmaWxsLCBlbmNvZGluZykge1xuICBhc3NlcnRTaXplKHNpemUpXG4gIGlmIChzaXplIDw9IDApIHtcbiAgICByZXR1cm4gY3JlYXRlQnVmZmVyKHRoYXQsIHNpemUpXG4gIH1cbiAgaWYgKGZpbGwgIT09IHVuZGVmaW5lZCkge1xuICAgIC8vIE9ubHkgcGF5IGF0dGVudGlvbiB0byBlbmNvZGluZyBpZiBpdCdzIGEgc3RyaW5nLiBUaGlzXG4gICAgLy8gcHJldmVudHMgYWNjaWRlbnRhbGx5IHNlbmRpbmcgaW4gYSBudW1iZXIgdGhhdCB3b3VsZFxuICAgIC8vIGJlIGludGVycHJldHRlZCBhcyBhIHN0YXJ0IG9mZnNldC5cbiAgICByZXR1cm4gdHlwZW9mIGVuY29kaW5nID09PSAnc3RyaW5nJ1xuICAgICAgPyBjcmVhdGVCdWZmZXIodGhhdCwgc2l6ZSkuZmlsbChmaWxsLCBlbmNvZGluZylcbiAgICAgIDogY3JlYXRlQnVmZmVyKHRoYXQsIHNpemUpLmZpbGwoZmlsbClcbiAgfVxuICByZXR1cm4gY3JlYXRlQnVmZmVyKHRoYXQsIHNpemUpXG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIG5ldyBmaWxsZWQgQnVmZmVyIGluc3RhbmNlLlxuICogYWxsb2Moc2l6ZVssIGZpbGxbLCBlbmNvZGluZ11dKVxuICoqL1xuQnVmZmVyLmFsbG9jID0gZnVuY3Rpb24gKHNpemUsIGZpbGwsIGVuY29kaW5nKSB7XG4gIHJldHVybiBhbGxvYyhudWxsLCBzaXplLCBmaWxsLCBlbmNvZGluZylcbn1cblxuZnVuY3Rpb24gYWxsb2NVbnNhZmUgKHRoYXQsIHNpemUpIHtcbiAgYXNzZXJ0U2l6ZShzaXplKVxuICB0aGF0ID0gY3JlYXRlQnVmZmVyKHRoYXQsIHNpemUgPCAwID8gMCA6IGNoZWNrZWQoc2l6ZSkgfCAwKVxuICBpZiAoIUJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzaXplOyArK2kpIHtcbiAgICAgIHRoYXRbaV0gPSAwXG4gICAgfVxuICB9XG4gIHJldHVybiB0aGF0XG59XG5cbi8qKlxuICogRXF1aXZhbGVudCB0byBCdWZmZXIobnVtKSwgYnkgZGVmYXVsdCBjcmVhdGVzIGEgbm9uLXplcm8tZmlsbGVkIEJ1ZmZlciBpbnN0YW5jZS5cbiAqICovXG5CdWZmZXIuYWxsb2NVbnNhZmUgPSBmdW5jdGlvbiAoc2l6ZSkge1xuICByZXR1cm4gYWxsb2NVbnNhZmUobnVsbCwgc2l6ZSlcbn1cbi8qKlxuICogRXF1aXZhbGVudCB0byBTbG93QnVmZmVyKG51bSksIGJ5IGRlZmF1bHQgY3JlYXRlcyBhIG5vbi16ZXJvLWZpbGxlZCBCdWZmZXIgaW5zdGFuY2UuXG4gKi9cbkJ1ZmZlci5hbGxvY1Vuc2FmZVNsb3cgPSBmdW5jdGlvbiAoc2l6ZSkge1xuICByZXR1cm4gYWxsb2NVbnNhZmUobnVsbCwgc2l6ZSlcbn1cblxuZnVuY3Rpb24gZnJvbVN0cmluZyAodGhhdCwgc3RyaW5nLCBlbmNvZGluZykge1xuICBpZiAodHlwZW9mIGVuY29kaW5nICE9PSAnc3RyaW5nJyB8fCBlbmNvZGluZyA9PT0gJycpIHtcbiAgICBlbmNvZGluZyA9ICd1dGY4J1xuICB9XG5cbiAgaWYgKCFCdWZmZXIuaXNFbmNvZGluZyhlbmNvZGluZykpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdcImVuY29kaW5nXCIgbXVzdCBiZSBhIHZhbGlkIHN0cmluZyBlbmNvZGluZycpXG4gIH1cblxuICB2YXIgbGVuZ3RoID0gYnl0ZUxlbmd0aChzdHJpbmcsIGVuY29kaW5nKSB8IDBcbiAgdGhhdCA9IGNyZWF0ZUJ1ZmZlcih0aGF0LCBsZW5ndGgpXG5cbiAgdmFyIGFjdHVhbCA9IHRoYXQud3JpdGUoc3RyaW5nLCBlbmNvZGluZylcblxuICBpZiAoYWN0dWFsICE9PSBsZW5ndGgpIHtcbiAgICAvLyBXcml0aW5nIGEgaGV4IHN0cmluZywgZm9yIGV4YW1wbGUsIHRoYXQgY29udGFpbnMgaW52YWxpZCBjaGFyYWN0ZXJzIHdpbGxcbiAgICAvLyBjYXVzZSBldmVyeXRoaW5nIGFmdGVyIHRoZSBmaXJzdCBpbnZhbGlkIGNoYXJhY3RlciB0byBiZSBpZ25vcmVkLiAoZS5nLlxuICAgIC8vICdhYnh4Y2QnIHdpbGwgYmUgdHJlYXRlZCBhcyAnYWInKVxuICAgIHRoYXQgPSB0aGF0LnNsaWNlKDAsIGFjdHVhbClcbiAgfVxuXG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGZyb21BcnJheUxpa2UgKHRoYXQsIGFycmF5KSB7XG4gIHZhciBsZW5ndGggPSBhcnJheS5sZW5ndGggPCAwID8gMCA6IGNoZWNrZWQoYXJyYXkubGVuZ3RoKSB8IDBcbiAgdGhhdCA9IGNyZWF0ZUJ1ZmZlcih0aGF0LCBsZW5ndGgpXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpICs9IDEpIHtcbiAgICB0aGF0W2ldID0gYXJyYXlbaV0gJiAyNTVcbiAgfVxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBmcm9tQXJyYXlCdWZmZXIgKHRoYXQsIGFycmF5LCBieXRlT2Zmc2V0LCBsZW5ndGgpIHtcbiAgYXJyYXkuYnl0ZUxlbmd0aCAvLyB0aGlzIHRocm93cyBpZiBgYXJyYXlgIGlzIG5vdCBhIHZhbGlkIEFycmF5QnVmZmVyXG5cbiAgaWYgKGJ5dGVPZmZzZXQgPCAwIHx8IGFycmF5LmJ5dGVMZW5ndGggPCBieXRlT2Zmc2V0KSB7XG4gICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ1xcJ29mZnNldFxcJyBpcyBvdXQgb2YgYm91bmRzJylcbiAgfVxuXG4gIGlmIChhcnJheS5ieXRlTGVuZ3RoIDwgYnl0ZU9mZnNldCArIChsZW5ndGggfHwgMCkpIHtcbiAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignXFwnbGVuZ3RoXFwnIGlzIG91dCBvZiBib3VuZHMnKVxuICB9XG5cbiAgaWYgKGJ5dGVPZmZzZXQgPT09IHVuZGVmaW5lZCAmJiBsZW5ndGggPT09IHVuZGVmaW5lZCkge1xuICAgIGFycmF5ID0gbmV3IFVpbnQ4QXJyYXkoYXJyYXkpXG4gIH0gZWxzZSBpZiAobGVuZ3RoID09PSB1bmRlZmluZWQpIHtcbiAgICBhcnJheSA9IG5ldyBVaW50OEFycmF5KGFycmF5LCBieXRlT2Zmc2V0KVxuICB9IGVsc2Uge1xuICAgIGFycmF5ID0gbmV3IFVpbnQ4QXJyYXkoYXJyYXksIGJ5dGVPZmZzZXQsIGxlbmd0aClcbiAgfVxuXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIC8vIFJldHVybiBhbiBhdWdtZW50ZWQgYFVpbnQ4QXJyYXlgIGluc3RhbmNlLCBmb3IgYmVzdCBwZXJmb3JtYW5jZVxuICAgIHRoYXQgPSBhcnJheVxuICAgIHRoYXQuX19wcm90b19fID0gQnVmZmVyLnByb3RvdHlwZVxuICB9IGVsc2Uge1xuICAgIC8vIEZhbGxiYWNrOiBSZXR1cm4gYW4gb2JqZWN0IGluc3RhbmNlIG9mIHRoZSBCdWZmZXIgY2xhc3NcbiAgICB0aGF0ID0gZnJvbUFycmF5TGlrZSh0aGF0LCBhcnJheSlcbiAgfVxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBmcm9tT2JqZWN0ICh0aGF0LCBvYmopIHtcbiAgaWYgKEJ1ZmZlci5pc0J1ZmZlcihvYmopKSB7XG4gICAgdmFyIGxlbiA9IGNoZWNrZWQob2JqLmxlbmd0aCkgfCAwXG4gICAgdGhhdCA9IGNyZWF0ZUJ1ZmZlcih0aGF0LCBsZW4pXG5cbiAgICBpZiAodGhhdC5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybiB0aGF0XG4gICAgfVxuXG4gICAgb2JqLmNvcHkodGhhdCwgMCwgMCwgbGVuKVxuICAgIHJldHVybiB0aGF0XG4gIH1cblxuICBpZiAob2JqKSB7XG4gICAgaWYgKCh0eXBlb2YgQXJyYXlCdWZmZXIgIT09ICd1bmRlZmluZWQnICYmXG4gICAgICAgIG9iai5idWZmZXIgaW5zdGFuY2VvZiBBcnJheUJ1ZmZlcikgfHwgJ2xlbmd0aCcgaW4gb2JqKSB7XG4gICAgICBpZiAodHlwZW9mIG9iai5sZW5ndGggIT09ICdudW1iZXInIHx8IGlzbmFuKG9iai5sZW5ndGgpKSB7XG4gICAgICAgIHJldHVybiBjcmVhdGVCdWZmZXIodGhhdCwgMClcbiAgICAgIH1cbiAgICAgIHJldHVybiBmcm9tQXJyYXlMaWtlKHRoYXQsIG9iailcbiAgICB9XG5cbiAgICBpZiAob2JqLnR5cGUgPT09ICdCdWZmZXInICYmIGlzQXJyYXkob2JqLmRhdGEpKSB7XG4gICAgICByZXR1cm4gZnJvbUFycmF5TGlrZSh0aGF0LCBvYmouZGF0YSlcbiAgICB9XG4gIH1cblxuICB0aHJvdyBuZXcgVHlwZUVycm9yKCdGaXJzdCBhcmd1bWVudCBtdXN0IGJlIGEgc3RyaW5nLCBCdWZmZXIsIEFycmF5QnVmZmVyLCBBcnJheSwgb3IgYXJyYXktbGlrZSBvYmplY3QuJylcbn1cblxuZnVuY3Rpb24gY2hlY2tlZCAobGVuZ3RoKSB7XG4gIC8vIE5vdGU6IGNhbm5vdCB1c2UgYGxlbmd0aCA8IGtNYXhMZW5ndGgoKWAgaGVyZSBiZWNhdXNlIHRoYXQgZmFpbHMgd2hlblxuICAvLyBsZW5ndGggaXMgTmFOICh3aGljaCBpcyBvdGhlcndpc2UgY29lcmNlZCB0byB6ZXJvLilcbiAgaWYgKGxlbmd0aCA+PSBrTWF4TGVuZ3RoKCkpIHtcbiAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignQXR0ZW1wdCB0byBhbGxvY2F0ZSBCdWZmZXIgbGFyZ2VyIHRoYW4gbWF4aW11bSAnICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAnc2l6ZTogMHgnICsga01heExlbmd0aCgpLnRvU3RyaW5nKDE2KSArICcgYnl0ZXMnKVxuICB9XG4gIHJldHVybiBsZW5ndGggfCAwXG59XG5cbmZ1bmN0aW9uIFNsb3dCdWZmZXIgKGxlbmd0aCkge1xuICBpZiAoK2xlbmd0aCAhPSBsZW5ndGgpIHsgLy8gZXNsaW50LWRpc2FibGUtbGluZSBlcWVxZXFcbiAgICBsZW5ndGggPSAwXG4gIH1cbiAgcmV0dXJuIEJ1ZmZlci5hbGxvYygrbGVuZ3RoKVxufVxuXG5CdWZmZXIuaXNCdWZmZXIgPSBmdW5jdGlvbiBpc0J1ZmZlciAoYikge1xuICByZXR1cm4gISEoYiAhPSBudWxsICYmIGIuX2lzQnVmZmVyKVxufVxuXG5CdWZmZXIuY29tcGFyZSA9IGZ1bmN0aW9uIGNvbXBhcmUgKGEsIGIpIHtcbiAgaWYgKCFCdWZmZXIuaXNCdWZmZXIoYSkgfHwgIUJ1ZmZlci5pc0J1ZmZlcihiKSkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0FyZ3VtZW50cyBtdXN0IGJlIEJ1ZmZlcnMnKVxuICB9XG5cbiAgaWYgKGEgPT09IGIpIHJldHVybiAwXG5cbiAgdmFyIHggPSBhLmxlbmd0aFxuICB2YXIgeSA9IGIubGVuZ3RoXG5cbiAgZm9yICh2YXIgaSA9IDAsIGxlbiA9IE1hdGgubWluKHgsIHkpOyBpIDwgbGVuOyArK2kpIHtcbiAgICBpZiAoYVtpXSAhPT0gYltpXSkge1xuICAgICAgeCA9IGFbaV1cbiAgICAgIHkgPSBiW2ldXG4gICAgICBicmVha1xuICAgIH1cbiAgfVxuXG4gIGlmICh4IDwgeSkgcmV0dXJuIC0xXG4gIGlmICh5IDwgeCkgcmV0dXJuIDFcbiAgcmV0dXJuIDBcbn1cblxuQnVmZmVyLmlzRW5jb2RpbmcgPSBmdW5jdGlvbiBpc0VuY29kaW5nIChlbmNvZGluZykge1xuICBzd2l0Y2ggKFN0cmluZyhlbmNvZGluZykudG9Mb3dlckNhc2UoKSkge1xuICAgIGNhc2UgJ2hleCc6XG4gICAgY2FzZSAndXRmOCc6XG4gICAgY2FzZSAndXRmLTgnOlxuICAgIGNhc2UgJ2FzY2lpJzpcbiAgICBjYXNlICdsYXRpbjEnOlxuICAgIGNhc2UgJ2JpbmFyeSc6XG4gICAgY2FzZSAnYmFzZTY0JzpcbiAgICBjYXNlICd1Y3MyJzpcbiAgICBjYXNlICd1Y3MtMic6XG4gICAgY2FzZSAndXRmMTZsZSc6XG4gICAgY2FzZSAndXRmLTE2bGUnOlxuICAgICAgcmV0dXJuIHRydWVcbiAgICBkZWZhdWx0OlxuICAgICAgcmV0dXJuIGZhbHNlXG4gIH1cbn1cblxuQnVmZmVyLmNvbmNhdCA9IGZ1bmN0aW9uIGNvbmNhdCAobGlzdCwgbGVuZ3RoKSB7XG4gIGlmICghaXNBcnJheShsaXN0KSkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ1wibGlzdFwiIGFyZ3VtZW50IG11c3QgYmUgYW4gQXJyYXkgb2YgQnVmZmVycycpXG4gIH1cblxuICBpZiAobGlzdC5sZW5ndGggPT09IDApIHtcbiAgICByZXR1cm4gQnVmZmVyLmFsbG9jKDApXG4gIH1cblxuICB2YXIgaVxuICBpZiAobGVuZ3RoID09PSB1bmRlZmluZWQpIHtcbiAgICBsZW5ndGggPSAwXG4gICAgZm9yIChpID0gMDsgaSA8IGxpc3QubGVuZ3RoOyArK2kpIHtcbiAgICAgIGxlbmd0aCArPSBsaXN0W2ldLmxlbmd0aFxuICAgIH1cbiAgfVxuXG4gIHZhciBidWZmZXIgPSBCdWZmZXIuYWxsb2NVbnNhZmUobGVuZ3RoKVxuICB2YXIgcG9zID0gMFxuICBmb3IgKGkgPSAwOyBpIDwgbGlzdC5sZW5ndGg7ICsraSkge1xuICAgIHZhciBidWYgPSBsaXN0W2ldXG4gICAgaWYgKCFCdWZmZXIuaXNCdWZmZXIoYnVmKSkge1xuICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignXCJsaXN0XCIgYXJndW1lbnQgbXVzdCBiZSBhbiBBcnJheSBvZiBCdWZmZXJzJylcbiAgICB9XG4gICAgYnVmLmNvcHkoYnVmZmVyLCBwb3MpXG4gICAgcG9zICs9IGJ1Zi5sZW5ndGhcbiAgfVxuICByZXR1cm4gYnVmZmVyXG59XG5cbmZ1bmN0aW9uIGJ5dGVMZW5ndGggKHN0cmluZywgZW5jb2RpbmcpIHtcbiAgaWYgKEJ1ZmZlci5pc0J1ZmZlcihzdHJpbmcpKSB7XG4gICAgcmV0dXJuIHN0cmluZy5sZW5ndGhcbiAgfVxuICBpZiAodHlwZW9mIEFycmF5QnVmZmVyICE9PSAndW5kZWZpbmVkJyAmJiB0eXBlb2YgQXJyYXlCdWZmZXIuaXNWaWV3ID09PSAnZnVuY3Rpb24nICYmXG4gICAgICAoQXJyYXlCdWZmZXIuaXNWaWV3KHN0cmluZykgfHwgc3RyaW5nIGluc3RhbmNlb2YgQXJyYXlCdWZmZXIpKSB7XG4gICAgcmV0dXJuIHN0cmluZy5ieXRlTGVuZ3RoXG4gIH1cbiAgaWYgKHR5cGVvZiBzdHJpbmcgIT09ICdzdHJpbmcnKSB7XG4gICAgc3RyaW5nID0gJycgKyBzdHJpbmdcbiAgfVxuXG4gIHZhciBsZW4gPSBzdHJpbmcubGVuZ3RoXG4gIGlmIChsZW4gPT09IDApIHJldHVybiAwXG5cbiAgLy8gVXNlIGEgZm9yIGxvb3AgdG8gYXZvaWQgcmVjdXJzaW9uXG4gIHZhciBsb3dlcmVkQ2FzZSA9IGZhbHNlXG4gIGZvciAoOzspIHtcbiAgICBzd2l0Y2ggKGVuY29kaW5nKSB7XG4gICAgICBjYXNlICdhc2NpaSc6XG4gICAgICBjYXNlICdsYXRpbjEnOlxuICAgICAgY2FzZSAnYmluYXJ5JzpcbiAgICAgICAgcmV0dXJuIGxlblxuICAgICAgY2FzZSAndXRmOCc6XG4gICAgICBjYXNlICd1dGYtOCc6XG4gICAgICBjYXNlIHVuZGVmaW5lZDpcbiAgICAgICAgcmV0dXJuIHV0ZjhUb0J5dGVzKHN0cmluZykubGVuZ3RoXG4gICAgICBjYXNlICd1Y3MyJzpcbiAgICAgIGNhc2UgJ3Vjcy0yJzpcbiAgICAgIGNhc2UgJ3V0ZjE2bGUnOlxuICAgICAgY2FzZSAndXRmLTE2bGUnOlxuICAgICAgICByZXR1cm4gbGVuICogMlxuICAgICAgY2FzZSAnaGV4JzpcbiAgICAgICAgcmV0dXJuIGxlbiA+Pj4gMVxuICAgICAgY2FzZSAnYmFzZTY0JzpcbiAgICAgICAgcmV0dXJuIGJhc2U2NFRvQnl0ZXMoc3RyaW5nKS5sZW5ndGhcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIGlmIChsb3dlcmVkQ2FzZSkgcmV0dXJuIHV0ZjhUb0J5dGVzKHN0cmluZykubGVuZ3RoIC8vIGFzc3VtZSB1dGY4XG4gICAgICAgIGVuY29kaW5nID0gKCcnICsgZW5jb2RpbmcpLnRvTG93ZXJDYXNlKClcbiAgICAgICAgbG93ZXJlZENhc2UgPSB0cnVlXG4gICAgfVxuICB9XG59XG5CdWZmZXIuYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGhcblxuZnVuY3Rpb24gc2xvd1RvU3RyaW5nIChlbmNvZGluZywgc3RhcnQsIGVuZCkge1xuICB2YXIgbG93ZXJlZENhc2UgPSBmYWxzZVxuXG4gIC8vIE5vIG5lZWQgdG8gdmVyaWZ5IHRoYXQgXCJ0aGlzLmxlbmd0aCA8PSBNQVhfVUlOVDMyXCIgc2luY2UgaXQncyBhIHJlYWQtb25seVxuICAvLyBwcm9wZXJ0eSBvZiBhIHR5cGVkIGFycmF5LlxuXG4gIC8vIFRoaXMgYmVoYXZlcyBuZWl0aGVyIGxpa2UgU3RyaW5nIG5vciBVaW50OEFycmF5IGluIHRoYXQgd2Ugc2V0IHN0YXJ0L2VuZFxuICAvLyB0byB0aGVpciB1cHBlci9sb3dlciBib3VuZHMgaWYgdGhlIHZhbHVlIHBhc3NlZCBpcyBvdXQgb2YgcmFuZ2UuXG4gIC8vIHVuZGVmaW5lZCBpcyBoYW5kbGVkIHNwZWNpYWxseSBhcyBwZXIgRUNNQS0yNjIgNnRoIEVkaXRpb24sXG4gIC8vIFNlY3Rpb24gMTMuMy4zLjcgUnVudGltZSBTZW1hbnRpY3M6IEtleWVkQmluZGluZ0luaXRpYWxpemF0aW9uLlxuICBpZiAoc3RhcnQgPT09IHVuZGVmaW5lZCB8fCBzdGFydCA8IDApIHtcbiAgICBzdGFydCA9IDBcbiAgfVxuICAvLyBSZXR1cm4gZWFybHkgaWYgc3RhcnQgPiB0aGlzLmxlbmd0aC4gRG9uZSBoZXJlIHRvIHByZXZlbnQgcG90ZW50aWFsIHVpbnQzMlxuICAvLyBjb2VyY2lvbiBmYWlsIGJlbG93LlxuICBpZiAoc3RhcnQgPiB0aGlzLmxlbmd0aCkge1xuICAgIHJldHVybiAnJ1xuICB9XG5cbiAgaWYgKGVuZCA9PT0gdW5kZWZpbmVkIHx8IGVuZCA+IHRoaXMubGVuZ3RoKSB7XG4gICAgZW5kID0gdGhpcy5sZW5ndGhcbiAgfVxuXG4gIGlmIChlbmQgPD0gMCkge1xuICAgIHJldHVybiAnJ1xuICB9XG5cbiAgLy8gRm9yY2UgY29lcnNpb24gdG8gdWludDMyLiBUaGlzIHdpbGwgYWxzbyBjb2VyY2UgZmFsc2V5L05hTiB2YWx1ZXMgdG8gMC5cbiAgZW5kID4+Pj0gMFxuICBzdGFydCA+Pj49IDBcblxuICBpZiAoZW5kIDw9IHN0YXJ0KSB7XG4gICAgcmV0dXJuICcnXG4gIH1cblxuICBpZiAoIWVuY29kaW5nKSBlbmNvZGluZyA9ICd1dGY4J1xuXG4gIHdoaWxlICh0cnVlKSB7XG4gICAgc3dpdGNoIChlbmNvZGluZykge1xuICAgICAgY2FzZSAnaGV4JzpcbiAgICAgICAgcmV0dXJuIGhleFNsaWNlKHRoaXMsIHN0YXJ0LCBlbmQpXG5cbiAgICAgIGNhc2UgJ3V0ZjgnOlxuICAgICAgY2FzZSAndXRmLTgnOlxuICAgICAgICByZXR1cm4gdXRmOFNsaWNlKHRoaXMsIHN0YXJ0LCBlbmQpXG5cbiAgICAgIGNhc2UgJ2FzY2lpJzpcbiAgICAgICAgcmV0dXJuIGFzY2lpU2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAnbGF0aW4xJzpcbiAgICAgIGNhc2UgJ2JpbmFyeSc6XG4gICAgICAgIHJldHVybiBsYXRpbjFTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBjYXNlICdiYXNlNjQnOlxuICAgICAgICByZXR1cm4gYmFzZTY0U2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAndWNzMic6XG4gICAgICBjYXNlICd1Y3MtMic6XG4gICAgICBjYXNlICd1dGYxNmxlJzpcbiAgICAgIGNhc2UgJ3V0Zi0xNmxlJzpcbiAgICAgICAgcmV0dXJuIHV0ZjE2bGVTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBkZWZhdWx0OlxuICAgICAgICBpZiAobG93ZXJlZENhc2UpIHRocm93IG5ldyBUeXBlRXJyb3IoJ1Vua25vd24gZW5jb2Rpbmc6ICcgKyBlbmNvZGluZylcbiAgICAgICAgZW5jb2RpbmcgPSAoZW5jb2RpbmcgKyAnJykudG9Mb3dlckNhc2UoKVxuICAgICAgICBsb3dlcmVkQ2FzZSA9IHRydWVcbiAgICB9XG4gIH1cbn1cblxuLy8gVGhlIHByb3BlcnR5IGlzIHVzZWQgYnkgYEJ1ZmZlci5pc0J1ZmZlcmAgYW5kIGBpcy1idWZmZXJgIChpbiBTYWZhcmkgNS03KSB0byBkZXRlY3Rcbi8vIEJ1ZmZlciBpbnN0YW5jZXMuXG5CdWZmZXIucHJvdG90eXBlLl9pc0J1ZmZlciA9IHRydWVcblxuZnVuY3Rpb24gc3dhcCAoYiwgbiwgbSkge1xuICB2YXIgaSA9IGJbbl1cbiAgYltuXSA9IGJbbV1cbiAgYlttXSA9IGlcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5zd2FwMTYgPSBmdW5jdGlvbiBzd2FwMTYgKCkge1xuICB2YXIgbGVuID0gdGhpcy5sZW5ndGhcbiAgaWYgKGxlbiAlIDIgIT09IDApIHtcbiAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignQnVmZmVyIHNpemUgbXVzdCBiZSBhIG11bHRpcGxlIG9mIDE2LWJpdHMnKVxuICB9XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuOyBpICs9IDIpIHtcbiAgICBzd2FwKHRoaXMsIGksIGkgKyAxKVxuICB9XG4gIHJldHVybiB0aGlzXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUuc3dhcDMyID0gZnVuY3Rpb24gc3dhcDMyICgpIHtcbiAgdmFyIGxlbiA9IHRoaXMubGVuZ3RoXG4gIGlmIChsZW4gJSA0ICE9PSAwKSB7XG4gICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ0J1ZmZlciBzaXplIG11c3QgYmUgYSBtdWx0aXBsZSBvZiAzMi1iaXRzJylcbiAgfVxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbjsgaSArPSA0KSB7XG4gICAgc3dhcCh0aGlzLCBpLCBpICsgMylcbiAgICBzd2FwKHRoaXMsIGkgKyAxLCBpICsgMilcbiAgfVxuICByZXR1cm4gdGhpc1xufVxuXG5CdWZmZXIucHJvdG90eXBlLnN3YXA2NCA9IGZ1bmN0aW9uIHN3YXA2NCAoKSB7XG4gIHZhciBsZW4gPSB0aGlzLmxlbmd0aFxuICBpZiAobGVuICUgOCAhPT0gMCkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCdCdWZmZXIgc2l6ZSBtdXN0IGJlIGEgbXVsdGlwbGUgb2YgNjQtYml0cycpXG4gIH1cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW47IGkgKz0gOCkge1xuICAgIHN3YXAodGhpcywgaSwgaSArIDcpXG4gICAgc3dhcCh0aGlzLCBpICsgMSwgaSArIDYpXG4gICAgc3dhcCh0aGlzLCBpICsgMiwgaSArIDUpXG4gICAgc3dhcCh0aGlzLCBpICsgMywgaSArIDQpXG4gIH1cbiAgcmV0dXJuIHRoaXNcbn1cblxuQnVmZmVyLnByb3RvdHlwZS50b1N0cmluZyA9IGZ1bmN0aW9uIHRvU3RyaW5nICgpIHtcbiAgdmFyIGxlbmd0aCA9IHRoaXMubGVuZ3RoIHwgMFxuICBpZiAobGVuZ3RoID09PSAwKSByZXR1cm4gJydcbiAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPT09IDApIHJldHVybiB1dGY4U2xpY2UodGhpcywgMCwgbGVuZ3RoKVxuICByZXR1cm4gc2xvd1RvU3RyaW5nLmFwcGx5KHRoaXMsIGFyZ3VtZW50cylcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5lcXVhbHMgPSBmdW5jdGlvbiBlcXVhbHMgKGIpIHtcbiAgaWYgKCFCdWZmZXIuaXNCdWZmZXIoYikpIHRocm93IG5ldyBUeXBlRXJyb3IoJ0FyZ3VtZW50IG11c3QgYmUgYSBCdWZmZXInKVxuICBpZiAodGhpcyA9PT0gYikgcmV0dXJuIHRydWVcbiAgcmV0dXJuIEJ1ZmZlci5jb21wYXJlKHRoaXMsIGIpID09PSAwXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUuaW5zcGVjdCA9IGZ1bmN0aW9uIGluc3BlY3QgKCkge1xuICB2YXIgc3RyID0gJydcbiAgdmFyIG1heCA9IGV4cG9ydHMuSU5TUEVDVF9NQVhfQllURVNcbiAgaWYgKHRoaXMubGVuZ3RoID4gMCkge1xuICAgIHN0ciA9IHRoaXMudG9TdHJpbmcoJ2hleCcsIDAsIG1heCkubWF0Y2goLy57Mn0vZykuam9pbignICcpXG4gICAgaWYgKHRoaXMubGVuZ3RoID4gbWF4KSBzdHIgKz0gJyAuLi4gJ1xuICB9XG4gIHJldHVybiAnPEJ1ZmZlciAnICsgc3RyICsgJz4nXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUuY29tcGFyZSA9IGZ1bmN0aW9uIGNvbXBhcmUgKHRhcmdldCwgc3RhcnQsIGVuZCwgdGhpc1N0YXJ0LCB0aGlzRW5kKSB7XG4gIGlmICghQnVmZmVyLmlzQnVmZmVyKHRhcmdldCkpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdBcmd1bWVudCBtdXN0IGJlIGEgQnVmZmVyJylcbiAgfVxuXG4gIGlmIChzdGFydCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgc3RhcnQgPSAwXG4gIH1cbiAgaWYgKGVuZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgZW5kID0gdGFyZ2V0ID8gdGFyZ2V0Lmxlbmd0aCA6IDBcbiAgfVxuICBpZiAodGhpc1N0YXJ0ID09PSB1bmRlZmluZWQpIHtcbiAgICB0aGlzU3RhcnQgPSAwXG4gIH1cbiAgaWYgKHRoaXNFbmQgPT09IHVuZGVmaW5lZCkge1xuICAgIHRoaXNFbmQgPSB0aGlzLmxlbmd0aFxuICB9XG5cbiAgaWYgKHN0YXJ0IDwgMCB8fCBlbmQgPiB0YXJnZXQubGVuZ3RoIHx8IHRoaXNTdGFydCA8IDAgfHwgdGhpc0VuZCA+IHRoaXMubGVuZ3RoKSB7XG4gICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ291dCBvZiByYW5nZSBpbmRleCcpXG4gIH1cblxuICBpZiAodGhpc1N0YXJ0ID49IHRoaXNFbmQgJiYgc3RhcnQgPj0gZW5kKSB7XG4gICAgcmV0dXJuIDBcbiAgfVxuICBpZiAodGhpc1N0YXJ0ID49IHRoaXNFbmQpIHtcbiAgICByZXR1cm4gLTFcbiAgfVxuICBpZiAoc3RhcnQgPj0gZW5kKSB7XG4gICAgcmV0dXJuIDFcbiAgfVxuXG4gIHN0YXJ0ID4+Pj0gMFxuICBlbmQgPj4+PSAwXG4gIHRoaXNTdGFydCA+Pj49IDBcbiAgdGhpc0VuZCA+Pj49IDBcblxuICBpZiAodGhpcyA9PT0gdGFyZ2V0KSByZXR1cm4gMFxuXG4gIHZhciB4ID0gdGhpc0VuZCAtIHRoaXNTdGFydFxuICB2YXIgeSA9IGVuZCAtIHN0YXJ0XG4gIHZhciBsZW4gPSBNYXRoLm1pbih4LCB5KVxuXG4gIHZhciB0aGlzQ29weSA9IHRoaXMuc2xpY2UodGhpc1N0YXJ0LCB0aGlzRW5kKVxuICB2YXIgdGFyZ2V0Q29weSA9IHRhcmdldC5zbGljZShzdGFydCwgZW5kKVxuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuOyArK2kpIHtcbiAgICBpZiAodGhpc0NvcHlbaV0gIT09IHRhcmdldENvcHlbaV0pIHtcbiAgICAgIHggPSB0aGlzQ29weVtpXVxuICAgICAgeSA9IHRhcmdldENvcHlbaV1cbiAgICAgIGJyZWFrXG4gICAgfVxuICB9XG5cbiAgaWYgKHggPCB5KSByZXR1cm4gLTFcbiAgaWYgKHkgPCB4KSByZXR1cm4gMVxuICByZXR1cm4gMFxufVxuXG4vLyBGaW5kcyBlaXRoZXIgdGhlIGZpcnN0IGluZGV4IG9mIGB2YWxgIGluIGBidWZmZXJgIGF0IG9mZnNldCA+PSBgYnl0ZU9mZnNldGAsXG4vLyBPUiB0aGUgbGFzdCBpbmRleCBvZiBgdmFsYCBpbiBgYnVmZmVyYCBhdCBvZmZzZXQgPD0gYGJ5dGVPZmZzZXRgLlxuLy9cbi8vIEFyZ3VtZW50czpcbi8vIC0gYnVmZmVyIC0gYSBCdWZmZXIgdG8gc2VhcmNoXG4vLyAtIHZhbCAtIGEgc3RyaW5nLCBCdWZmZXIsIG9yIG51bWJlclxuLy8gLSBieXRlT2Zmc2V0IC0gYW4gaW5kZXggaW50byBgYnVmZmVyYDsgd2lsbCBiZSBjbGFtcGVkIHRvIGFuIGludDMyXG4vLyAtIGVuY29kaW5nIC0gYW4gb3B0aW9uYWwgZW5jb2RpbmcsIHJlbGV2YW50IGlzIHZhbCBpcyBhIHN0cmluZ1xuLy8gLSBkaXIgLSB0cnVlIGZvciBpbmRleE9mLCBmYWxzZSBmb3IgbGFzdEluZGV4T2ZcbmZ1bmN0aW9uIGJpZGlyZWN0aW9uYWxJbmRleE9mIChidWZmZXIsIHZhbCwgYnl0ZU9mZnNldCwgZW5jb2RpbmcsIGRpcikge1xuICAvLyBFbXB0eSBidWZmZXIgbWVhbnMgbm8gbWF0Y2hcbiAgaWYgKGJ1ZmZlci5sZW5ndGggPT09IDApIHJldHVybiAtMVxuXG4gIC8vIE5vcm1hbGl6ZSBieXRlT2Zmc2V0XG4gIGlmICh0eXBlb2YgYnl0ZU9mZnNldCA9PT0gJ3N0cmluZycpIHtcbiAgICBlbmNvZGluZyA9IGJ5dGVPZmZzZXRcbiAgICBieXRlT2Zmc2V0ID0gMFxuICB9IGVsc2UgaWYgKGJ5dGVPZmZzZXQgPiAweDdmZmZmZmZmKSB7XG4gICAgYnl0ZU9mZnNldCA9IDB4N2ZmZmZmZmZcbiAgfSBlbHNlIGlmIChieXRlT2Zmc2V0IDwgLTB4ODAwMDAwMDApIHtcbiAgICBieXRlT2Zmc2V0ID0gLTB4ODAwMDAwMDBcbiAgfVxuICBieXRlT2Zmc2V0ID0gK2J5dGVPZmZzZXQgIC8vIENvZXJjZSB0byBOdW1iZXIuXG4gIGlmIChpc05hTihieXRlT2Zmc2V0KSkge1xuICAgIC8vIGJ5dGVPZmZzZXQ6IGl0IGl0J3MgdW5kZWZpbmVkLCBudWxsLCBOYU4sIFwiZm9vXCIsIGV0Yywgc2VhcmNoIHdob2xlIGJ1ZmZlclxuICAgIGJ5dGVPZmZzZXQgPSBkaXIgPyAwIDogKGJ1ZmZlci5sZW5ndGggLSAxKVxuICB9XG5cbiAgLy8gTm9ybWFsaXplIGJ5dGVPZmZzZXQ6IG5lZ2F0aXZlIG9mZnNldHMgc3RhcnQgZnJvbSB0aGUgZW5kIG9mIHRoZSBidWZmZXJcbiAgaWYgKGJ5dGVPZmZzZXQgPCAwKSBieXRlT2Zmc2V0ID0gYnVmZmVyLmxlbmd0aCArIGJ5dGVPZmZzZXRcbiAgaWYgKGJ5dGVPZmZzZXQgPj0gYnVmZmVyLmxlbmd0aCkge1xuICAgIGlmIChkaXIpIHJldHVybiAtMVxuICAgIGVsc2UgYnl0ZU9mZnNldCA9IGJ1ZmZlci5sZW5ndGggLSAxXG4gIH0gZWxzZSBpZiAoYnl0ZU9mZnNldCA8IDApIHtcbiAgICBpZiAoZGlyKSBieXRlT2Zmc2V0ID0gMFxuICAgIGVsc2UgcmV0dXJuIC0xXG4gIH1cblxuICAvLyBOb3JtYWxpemUgdmFsXG4gIGlmICh0eXBlb2YgdmFsID09PSAnc3RyaW5nJykge1xuICAgIHZhbCA9IEJ1ZmZlci5mcm9tKHZhbCwgZW5jb2RpbmcpXG4gIH1cblxuICAvLyBGaW5hbGx5LCBzZWFyY2ggZWl0aGVyIGluZGV4T2YgKGlmIGRpciBpcyB0cnVlKSBvciBsYXN0SW5kZXhPZlxuICBpZiAoQnVmZmVyLmlzQnVmZmVyKHZhbCkpIHtcbiAgICAvLyBTcGVjaWFsIGNhc2U6IGxvb2tpbmcgZm9yIGVtcHR5IHN0cmluZy9idWZmZXIgYWx3YXlzIGZhaWxzXG4gICAgaWYgKHZhbC5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybiAtMVxuICAgIH1cbiAgICByZXR1cm4gYXJyYXlJbmRleE9mKGJ1ZmZlciwgdmFsLCBieXRlT2Zmc2V0LCBlbmNvZGluZywgZGlyKVxuICB9IGVsc2UgaWYgKHR5cGVvZiB2YWwgPT09ICdudW1iZXInKSB7XG4gICAgdmFsID0gdmFsICYgMHhGRiAvLyBTZWFyY2ggZm9yIGEgYnl0ZSB2YWx1ZSBbMC0yNTVdXG4gICAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUICYmXG4gICAgICAgIHR5cGVvZiBVaW50OEFycmF5LnByb3RvdHlwZS5pbmRleE9mID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICBpZiAoZGlyKSB7XG4gICAgICAgIHJldHVybiBVaW50OEFycmF5LnByb3RvdHlwZS5pbmRleE9mLmNhbGwoYnVmZmVyLCB2YWwsIGJ5dGVPZmZzZXQpXG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gVWludDhBcnJheS5wcm90b3R5cGUubGFzdEluZGV4T2YuY2FsbChidWZmZXIsIHZhbCwgYnl0ZU9mZnNldClcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGFycmF5SW5kZXhPZihidWZmZXIsIFsgdmFsIF0sIGJ5dGVPZmZzZXQsIGVuY29kaW5nLCBkaXIpXG4gIH1cblxuICB0aHJvdyBuZXcgVHlwZUVycm9yKCd2YWwgbXVzdCBiZSBzdHJpbmcsIG51bWJlciBvciBCdWZmZXInKVxufVxuXG5mdW5jdGlvbiBhcnJheUluZGV4T2YgKGFyciwgdmFsLCBieXRlT2Zmc2V0LCBlbmNvZGluZywgZGlyKSB7XG4gIHZhciBpbmRleFNpemUgPSAxXG4gIHZhciBhcnJMZW5ndGggPSBhcnIubGVuZ3RoXG4gIHZhciB2YWxMZW5ndGggPSB2YWwubGVuZ3RoXG5cbiAgaWYgKGVuY29kaW5nICE9PSB1bmRlZmluZWQpIHtcbiAgICBlbmNvZGluZyA9IFN0cmluZyhlbmNvZGluZykudG9Mb3dlckNhc2UoKVxuICAgIGlmIChlbmNvZGluZyA9PT0gJ3VjczInIHx8IGVuY29kaW5nID09PSAndWNzLTInIHx8XG4gICAgICAgIGVuY29kaW5nID09PSAndXRmMTZsZScgfHwgZW5jb2RpbmcgPT09ICd1dGYtMTZsZScpIHtcbiAgICAgIGlmIChhcnIubGVuZ3RoIDwgMiB8fCB2YWwubGVuZ3RoIDwgMikge1xuICAgICAgICByZXR1cm4gLTFcbiAgICAgIH1cbiAgICAgIGluZGV4U2l6ZSA9IDJcbiAgICAgIGFyckxlbmd0aCAvPSAyXG4gICAgICB2YWxMZW5ndGggLz0gMlxuICAgICAgYnl0ZU9mZnNldCAvPSAyXG4gICAgfVxuICB9XG5cbiAgZnVuY3Rpb24gcmVhZCAoYnVmLCBpKSB7XG4gICAgaWYgKGluZGV4U2l6ZSA9PT0gMSkge1xuICAgICAgcmV0dXJuIGJ1ZltpXVxuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gYnVmLnJlYWRVSW50MTZCRShpICogaW5kZXhTaXplKVxuICAgIH1cbiAgfVxuXG4gIHZhciBpXG4gIGlmIChkaXIpIHtcbiAgICB2YXIgZm91bmRJbmRleCA9IC0xXG4gICAgZm9yIChpID0gYnl0ZU9mZnNldDsgaSA8IGFyckxlbmd0aDsgaSsrKSB7XG4gICAgICBpZiAocmVhZChhcnIsIGkpID09PSByZWFkKHZhbCwgZm91bmRJbmRleCA9PT0gLTEgPyAwIDogaSAtIGZvdW5kSW5kZXgpKSB7XG4gICAgICAgIGlmIChmb3VuZEluZGV4ID09PSAtMSkgZm91bmRJbmRleCA9IGlcbiAgICAgICAgaWYgKGkgLSBmb3VuZEluZGV4ICsgMSA9PT0gdmFsTGVuZ3RoKSByZXR1cm4gZm91bmRJbmRleCAqIGluZGV4U2l6ZVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaWYgKGZvdW5kSW5kZXggIT09IC0xKSBpIC09IGkgLSBmb3VuZEluZGV4XG4gICAgICAgIGZvdW5kSW5kZXggPSAtMVxuICAgICAgfVxuICAgIH1cbiAgfSBlbHNlIHtcbiAgICBpZiAoYnl0ZU9mZnNldCArIHZhbExlbmd0aCA+IGFyckxlbmd0aCkgYnl0ZU9mZnNldCA9IGFyckxlbmd0aCAtIHZhbExlbmd0aFxuICAgIGZvciAoaSA9IGJ5dGVPZmZzZXQ7IGkgPj0gMDsgaS0tKSB7XG4gICAgICB2YXIgZm91bmQgPSB0cnVlXG4gICAgICBmb3IgKHZhciBqID0gMDsgaiA8IHZhbExlbmd0aDsgaisrKSB7XG4gICAgICAgIGlmIChyZWFkKGFyciwgaSArIGopICE9PSByZWFkKHZhbCwgaikpIHtcbiAgICAgICAgICBmb3VuZCA9IGZhbHNlXG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaWYgKGZvdW5kKSByZXR1cm4gaVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiAtMVxufVxuXG5CdWZmZXIucHJvdG90eXBlLmluY2x1ZGVzID0gZnVuY3Rpb24gaW5jbHVkZXMgKHZhbCwgYnl0ZU9mZnNldCwgZW5jb2RpbmcpIHtcbiAgcmV0dXJuIHRoaXMuaW5kZXhPZih2YWwsIGJ5dGVPZmZzZXQsIGVuY29kaW5nKSAhPT0gLTFcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5pbmRleE9mID0gZnVuY3Rpb24gaW5kZXhPZiAodmFsLCBieXRlT2Zmc2V0LCBlbmNvZGluZykge1xuICByZXR1cm4gYmlkaXJlY3Rpb25hbEluZGV4T2YodGhpcywgdmFsLCBieXRlT2Zmc2V0LCBlbmNvZGluZywgdHJ1ZSlcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5sYXN0SW5kZXhPZiA9IGZ1bmN0aW9uIGxhc3RJbmRleE9mICh2YWwsIGJ5dGVPZmZzZXQsIGVuY29kaW5nKSB7XG4gIHJldHVybiBiaWRpcmVjdGlvbmFsSW5kZXhPZih0aGlzLCB2YWwsIGJ5dGVPZmZzZXQsIGVuY29kaW5nLCBmYWxzZSlcbn1cblxuZnVuY3Rpb24gaGV4V3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICBvZmZzZXQgPSBOdW1iZXIob2Zmc2V0KSB8fCAwXG4gIHZhciByZW1haW5pbmcgPSBidWYubGVuZ3RoIC0gb2Zmc2V0XG4gIGlmICghbGVuZ3RoKSB7XG4gICAgbGVuZ3RoID0gcmVtYWluaW5nXG4gIH0gZWxzZSB7XG4gICAgbGVuZ3RoID0gTnVtYmVyKGxlbmd0aClcbiAgICBpZiAobGVuZ3RoID4gcmVtYWluaW5nKSB7XG4gICAgICBsZW5ndGggPSByZW1haW5pbmdcbiAgICB9XG4gIH1cblxuICAvLyBtdXN0IGJlIGFuIGV2ZW4gbnVtYmVyIG9mIGRpZ2l0c1xuICB2YXIgc3RyTGVuID0gc3RyaW5nLmxlbmd0aFxuICBpZiAoc3RyTGVuICUgMiAhPT0gMCkgdGhyb3cgbmV3IFR5cGVFcnJvcignSW52YWxpZCBoZXggc3RyaW5nJylcblxuICBpZiAobGVuZ3RoID4gc3RyTGVuIC8gMikge1xuICAgIGxlbmd0aCA9IHN0ckxlbiAvIDJcbiAgfVxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgKytpKSB7XG4gICAgdmFyIHBhcnNlZCA9IHBhcnNlSW50KHN0cmluZy5zdWJzdHIoaSAqIDIsIDIpLCAxNilcbiAgICBpZiAoaXNOYU4ocGFyc2VkKSkgcmV0dXJuIGlcbiAgICBidWZbb2Zmc2V0ICsgaV0gPSBwYXJzZWRcbiAgfVxuICByZXR1cm4gaVxufVxuXG5mdW5jdGlvbiB1dGY4V3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICByZXR1cm4gYmxpdEJ1ZmZlcih1dGY4VG9CeXRlcyhzdHJpbmcsIGJ1Zi5sZW5ndGggLSBvZmZzZXQpLCBidWYsIG9mZnNldCwgbGVuZ3RoKVxufVxuXG5mdW5jdGlvbiBhc2NpaVdyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgcmV0dXJuIGJsaXRCdWZmZXIoYXNjaWlUb0J5dGVzKHN0cmluZyksIGJ1Ziwgb2Zmc2V0LCBsZW5ndGgpXG59XG5cbmZ1bmN0aW9uIGxhdGluMVdyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgcmV0dXJuIGFzY2lpV3JpdGUoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxufVxuXG5mdW5jdGlvbiBiYXNlNjRXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIHJldHVybiBibGl0QnVmZmVyKGJhc2U2NFRvQnl0ZXMoc3RyaW5nKSwgYnVmLCBvZmZzZXQsIGxlbmd0aClcbn1cblxuZnVuY3Rpb24gdWNzMldyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgcmV0dXJuIGJsaXRCdWZmZXIodXRmMTZsZVRvQnl0ZXMoc3RyaW5nLCBidWYubGVuZ3RoIC0gb2Zmc2V0KSwgYnVmLCBvZmZzZXQsIGxlbmd0aClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZSA9IGZ1bmN0aW9uIHdyaXRlIChzdHJpbmcsIG9mZnNldCwgbGVuZ3RoLCBlbmNvZGluZykge1xuICAvLyBCdWZmZXIjd3JpdGUoc3RyaW5nKVxuICBpZiAob2Zmc2V0ID09PSB1bmRlZmluZWQpIHtcbiAgICBlbmNvZGluZyA9ICd1dGY4J1xuICAgIGxlbmd0aCA9IHRoaXMubGVuZ3RoXG4gICAgb2Zmc2V0ID0gMFxuICAvLyBCdWZmZXIjd3JpdGUoc3RyaW5nLCBlbmNvZGluZylcbiAgfSBlbHNlIGlmIChsZW5ndGggPT09IHVuZGVmaW5lZCAmJiB0eXBlb2Ygb2Zmc2V0ID09PSAnc3RyaW5nJykge1xuICAgIGVuY29kaW5nID0gb2Zmc2V0XG4gICAgbGVuZ3RoID0gdGhpcy5sZW5ndGhcbiAgICBvZmZzZXQgPSAwXG4gIC8vIEJ1ZmZlciN3cml0ZShzdHJpbmcsIG9mZnNldFssIGxlbmd0aF1bLCBlbmNvZGluZ10pXG4gIH0gZWxzZSBpZiAoaXNGaW5pdGUob2Zmc2V0KSkge1xuICAgIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgICBpZiAoaXNGaW5pdGUobGVuZ3RoKSkge1xuICAgICAgbGVuZ3RoID0gbGVuZ3RoIHwgMFxuICAgICAgaWYgKGVuY29kaW5nID09PSB1bmRlZmluZWQpIGVuY29kaW5nID0gJ3V0ZjgnXG4gICAgfSBlbHNlIHtcbiAgICAgIGVuY29kaW5nID0gbGVuZ3RoXG4gICAgICBsZW5ndGggPSB1bmRlZmluZWRcbiAgICB9XG4gIC8vIGxlZ2FjeSB3cml0ZShzdHJpbmcsIGVuY29kaW5nLCBvZmZzZXQsIGxlbmd0aCkgLSByZW1vdmUgaW4gdjAuMTNcbiAgfSBlbHNlIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAnQnVmZmVyLndyaXRlKHN0cmluZywgZW5jb2RpbmcsIG9mZnNldFssIGxlbmd0aF0pIGlzIG5vIGxvbmdlciBzdXBwb3J0ZWQnXG4gICAgKVxuICB9XG5cbiAgdmFyIHJlbWFpbmluZyA9IHRoaXMubGVuZ3RoIC0gb2Zmc2V0XG4gIGlmIChsZW5ndGggPT09IHVuZGVmaW5lZCB8fCBsZW5ndGggPiByZW1haW5pbmcpIGxlbmd0aCA9IHJlbWFpbmluZ1xuXG4gIGlmICgoc3RyaW5nLmxlbmd0aCA+IDAgJiYgKGxlbmd0aCA8IDAgfHwgb2Zmc2V0IDwgMCkpIHx8IG9mZnNldCA+IHRoaXMubGVuZ3RoKSB7XG4gICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ0F0dGVtcHQgdG8gd3JpdGUgb3V0c2lkZSBidWZmZXIgYm91bmRzJylcbiAgfVxuXG4gIGlmICghZW5jb2RpbmcpIGVuY29kaW5nID0gJ3V0ZjgnXG5cbiAgdmFyIGxvd2VyZWRDYXNlID0gZmFsc2VcbiAgZm9yICg7Oykge1xuICAgIHN3aXRjaCAoZW5jb2RpbmcpIHtcbiAgICAgIGNhc2UgJ2hleCc6XG4gICAgICAgIHJldHVybiBoZXhXcml0ZSh0aGlzLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxuXG4gICAgICBjYXNlICd1dGY4JzpcbiAgICAgIGNhc2UgJ3V0Zi04JzpcbiAgICAgICAgcmV0dXJuIHV0ZjhXcml0ZSh0aGlzLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxuXG4gICAgICBjYXNlICdhc2NpaSc6XG4gICAgICAgIHJldHVybiBhc2NpaVdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGNhc2UgJ2xhdGluMSc6XG4gICAgICBjYXNlICdiaW5hcnknOlxuICAgICAgICByZXR1cm4gbGF0aW4xV3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcblxuICAgICAgY2FzZSAnYmFzZTY0JzpcbiAgICAgICAgLy8gV2FybmluZzogbWF4TGVuZ3RoIG5vdCB0YWtlbiBpbnRvIGFjY291bnQgaW4gYmFzZTY0V3JpdGVcbiAgICAgICAgcmV0dXJuIGJhc2U2NFdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGNhc2UgJ3VjczInOlxuICAgICAgY2FzZSAndWNzLTInOlxuICAgICAgY2FzZSAndXRmMTZsZSc6XG4gICAgICBjYXNlICd1dGYtMTZsZSc6XG4gICAgICAgIHJldHVybiB1Y3MyV3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcblxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgaWYgKGxvd2VyZWRDYXNlKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdVbmtub3duIGVuY29kaW5nOiAnICsgZW5jb2RpbmcpXG4gICAgICAgIGVuY29kaW5nID0gKCcnICsgZW5jb2RpbmcpLnRvTG93ZXJDYXNlKClcbiAgICAgICAgbG93ZXJlZENhc2UgPSB0cnVlXG4gICAgfVxuICB9XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUudG9KU09OID0gZnVuY3Rpb24gdG9KU09OICgpIHtcbiAgcmV0dXJuIHtcbiAgICB0eXBlOiAnQnVmZmVyJyxcbiAgICBkYXRhOiBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbCh0aGlzLl9hcnIgfHwgdGhpcywgMClcbiAgfVxufVxuXG5mdW5jdGlvbiBiYXNlNjRTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIGlmIChzdGFydCA9PT0gMCAmJiBlbmQgPT09IGJ1Zi5sZW5ndGgpIHtcbiAgICByZXR1cm4gYmFzZTY0LmZyb21CeXRlQXJyYXkoYnVmKVxuICB9IGVsc2Uge1xuICAgIHJldHVybiBiYXNlNjQuZnJvbUJ5dGVBcnJheShidWYuc2xpY2Uoc3RhcnQsIGVuZCkpXG4gIH1cbn1cblxuZnVuY3Rpb24gdXRmOFNsaWNlIChidWYsIHN0YXJ0LCBlbmQpIHtcbiAgZW5kID0gTWF0aC5taW4oYnVmLmxlbmd0aCwgZW5kKVxuICB2YXIgcmVzID0gW11cblxuICB2YXIgaSA9IHN0YXJ0XG4gIHdoaWxlIChpIDwgZW5kKSB7XG4gICAgdmFyIGZpcnN0Qnl0ZSA9IGJ1ZltpXVxuICAgIHZhciBjb2RlUG9pbnQgPSBudWxsXG4gICAgdmFyIGJ5dGVzUGVyU2VxdWVuY2UgPSAoZmlyc3RCeXRlID4gMHhFRikgPyA0XG4gICAgICA6IChmaXJzdEJ5dGUgPiAweERGKSA/IDNcbiAgICAgIDogKGZpcnN0Qnl0ZSA+IDB4QkYpID8gMlxuICAgICAgOiAxXG5cbiAgICBpZiAoaSArIGJ5dGVzUGVyU2VxdWVuY2UgPD0gZW5kKSB7XG4gICAgICB2YXIgc2Vjb25kQnl0ZSwgdGhpcmRCeXRlLCBmb3VydGhCeXRlLCB0ZW1wQ29kZVBvaW50XG5cbiAgICAgIHN3aXRjaCAoYnl0ZXNQZXJTZXF1ZW5jZSkge1xuICAgICAgICBjYXNlIDE6XG4gICAgICAgICAgaWYgKGZpcnN0Qnl0ZSA8IDB4ODApIHtcbiAgICAgICAgICAgIGNvZGVQb2ludCA9IGZpcnN0Qnl0ZVxuICAgICAgICAgIH1cbiAgICAgICAgICBicmVha1xuICAgICAgICBjYXNlIDI6XG4gICAgICAgICAgc2Vjb25kQnl0ZSA9IGJ1ZltpICsgMV1cbiAgICAgICAgICBpZiAoKHNlY29uZEJ5dGUgJiAweEMwKSA9PT0gMHg4MCkge1xuICAgICAgICAgICAgdGVtcENvZGVQb2ludCA9IChmaXJzdEJ5dGUgJiAweDFGKSA8PCAweDYgfCAoc2Vjb25kQnl0ZSAmIDB4M0YpXG4gICAgICAgICAgICBpZiAodGVtcENvZGVQb2ludCA+IDB4N0YpIHtcbiAgICAgICAgICAgICAgY29kZVBvaW50ID0gdGVtcENvZGVQb2ludFxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBicmVha1xuICAgICAgICBjYXNlIDM6XG4gICAgICAgICAgc2Vjb25kQnl0ZSA9IGJ1ZltpICsgMV1cbiAgICAgICAgICB0aGlyZEJ5dGUgPSBidWZbaSArIDJdXG4gICAgICAgICAgaWYgKChzZWNvbmRCeXRlICYgMHhDMCkgPT09IDB4ODAgJiYgKHRoaXJkQnl0ZSAmIDB4QzApID09PSAweDgwKSB7XG4gICAgICAgICAgICB0ZW1wQ29kZVBvaW50ID0gKGZpcnN0Qnl0ZSAmIDB4RikgPDwgMHhDIHwgKHNlY29uZEJ5dGUgJiAweDNGKSA8PCAweDYgfCAodGhpcmRCeXRlICYgMHgzRilcbiAgICAgICAgICAgIGlmICh0ZW1wQ29kZVBvaW50ID4gMHg3RkYgJiYgKHRlbXBDb2RlUG9pbnQgPCAweEQ4MDAgfHwgdGVtcENvZGVQb2ludCA+IDB4REZGRikpIHtcbiAgICAgICAgICAgICAgY29kZVBvaW50ID0gdGVtcENvZGVQb2ludFxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBicmVha1xuICAgICAgICBjYXNlIDQ6XG4gICAgICAgICAgc2Vjb25kQnl0ZSA9IGJ1ZltpICsgMV1cbiAgICAgICAgICB0aGlyZEJ5dGUgPSBidWZbaSArIDJdXG4gICAgICAgICAgZm91cnRoQnl0ZSA9IGJ1ZltpICsgM11cbiAgICAgICAgICBpZiAoKHNlY29uZEJ5dGUgJiAweEMwKSA9PT0gMHg4MCAmJiAodGhpcmRCeXRlICYgMHhDMCkgPT09IDB4ODAgJiYgKGZvdXJ0aEJ5dGUgJiAweEMwKSA9PT0gMHg4MCkge1xuICAgICAgICAgICAgdGVtcENvZGVQb2ludCA9IChmaXJzdEJ5dGUgJiAweEYpIDw8IDB4MTIgfCAoc2Vjb25kQnl0ZSAmIDB4M0YpIDw8IDB4QyB8ICh0aGlyZEJ5dGUgJiAweDNGKSA8PCAweDYgfCAoZm91cnRoQnl0ZSAmIDB4M0YpXG4gICAgICAgICAgICBpZiAodGVtcENvZGVQb2ludCA+IDB4RkZGRiAmJiB0ZW1wQ29kZVBvaW50IDwgMHgxMTAwMDApIHtcbiAgICAgICAgICAgICAgY29kZVBvaW50ID0gdGVtcENvZGVQb2ludFxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoY29kZVBvaW50ID09PSBudWxsKSB7XG4gICAgICAvLyB3ZSBkaWQgbm90IGdlbmVyYXRlIGEgdmFsaWQgY29kZVBvaW50IHNvIGluc2VydCBhXG4gICAgICAvLyByZXBsYWNlbWVudCBjaGFyIChVK0ZGRkQpIGFuZCBhZHZhbmNlIG9ubHkgMSBieXRlXG4gICAgICBjb2RlUG9pbnQgPSAweEZGRkRcbiAgICAgIGJ5dGVzUGVyU2VxdWVuY2UgPSAxXG4gICAgfSBlbHNlIGlmIChjb2RlUG9pbnQgPiAweEZGRkYpIHtcbiAgICAgIC8vIGVuY29kZSB0byB1dGYxNiAoc3Vycm9nYXRlIHBhaXIgZGFuY2UpXG4gICAgICBjb2RlUG9pbnQgLT0gMHgxMDAwMFxuICAgICAgcmVzLnB1c2goY29kZVBvaW50ID4+PiAxMCAmIDB4M0ZGIHwgMHhEODAwKVxuICAgICAgY29kZVBvaW50ID0gMHhEQzAwIHwgY29kZVBvaW50ICYgMHgzRkZcbiAgICB9XG5cbiAgICByZXMucHVzaChjb2RlUG9pbnQpXG4gICAgaSArPSBieXRlc1BlclNlcXVlbmNlXG4gIH1cblxuICByZXR1cm4gZGVjb2RlQ29kZVBvaW50c0FycmF5KHJlcylcbn1cblxuLy8gQmFzZWQgb24gaHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tL2EvMjI3NDcyNzIvNjgwNzQyLCB0aGUgYnJvd3NlciB3aXRoXG4vLyB0aGUgbG93ZXN0IGxpbWl0IGlzIENocm9tZSwgd2l0aCAweDEwMDAwIGFyZ3MuXG4vLyBXZSBnbyAxIG1hZ25pdHVkZSBsZXNzLCBmb3Igc2FmZXR5XG52YXIgTUFYX0FSR1VNRU5UU19MRU5HVEggPSAweDEwMDBcblxuZnVuY3Rpb24gZGVjb2RlQ29kZVBvaW50c0FycmF5IChjb2RlUG9pbnRzKSB7XG4gIHZhciBsZW4gPSBjb2RlUG9pbnRzLmxlbmd0aFxuICBpZiAobGVuIDw9IE1BWF9BUkdVTUVOVFNfTEVOR1RIKSB7XG4gICAgcmV0dXJuIFN0cmluZy5mcm9tQ2hhckNvZGUuYXBwbHkoU3RyaW5nLCBjb2RlUG9pbnRzKSAvLyBhdm9pZCBleHRyYSBzbGljZSgpXG4gIH1cblxuICAvLyBEZWNvZGUgaW4gY2h1bmtzIHRvIGF2b2lkIFwiY2FsbCBzdGFjayBzaXplIGV4Y2VlZGVkXCIuXG4gIHZhciByZXMgPSAnJ1xuICB2YXIgaSA9IDBcbiAgd2hpbGUgKGkgPCBsZW4pIHtcbiAgICByZXMgKz0gU3RyaW5nLmZyb21DaGFyQ29kZS5hcHBseShcbiAgICAgIFN0cmluZyxcbiAgICAgIGNvZGVQb2ludHMuc2xpY2UoaSwgaSArPSBNQVhfQVJHVU1FTlRTX0xFTkdUSClcbiAgICApXG4gIH1cbiAgcmV0dXJuIHJlc1xufVxuXG5mdW5jdGlvbiBhc2NpaVNsaWNlIChidWYsIHN0YXJ0LCBlbmQpIHtcbiAgdmFyIHJldCA9ICcnXG4gIGVuZCA9IE1hdGgubWluKGJ1Zi5sZW5ndGgsIGVuZClcblxuICBmb3IgKHZhciBpID0gc3RhcnQ7IGkgPCBlbmQ7ICsraSkge1xuICAgIHJldCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGJ1ZltpXSAmIDB4N0YpXG4gIH1cbiAgcmV0dXJuIHJldFxufVxuXG5mdW5jdGlvbiBsYXRpbjFTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIHZhciByZXQgPSAnJ1xuICBlbmQgPSBNYXRoLm1pbihidWYubGVuZ3RoLCBlbmQpXG5cbiAgZm9yICh2YXIgaSA9IHN0YXJ0OyBpIDwgZW5kOyArK2kpIHtcbiAgICByZXQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShidWZbaV0pXG4gIH1cbiAgcmV0dXJuIHJldFxufVxuXG5mdW5jdGlvbiBoZXhTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIHZhciBsZW4gPSBidWYubGVuZ3RoXG5cbiAgaWYgKCFzdGFydCB8fCBzdGFydCA8IDApIHN0YXJ0ID0gMFxuICBpZiAoIWVuZCB8fCBlbmQgPCAwIHx8IGVuZCA+IGxlbikgZW5kID0gbGVuXG5cbiAgdmFyIG91dCA9ICcnXG4gIGZvciAodmFyIGkgPSBzdGFydDsgaSA8IGVuZDsgKytpKSB7XG4gICAgb3V0ICs9IHRvSGV4KGJ1ZltpXSlcbiAgfVxuICByZXR1cm4gb3V0XG59XG5cbmZ1bmN0aW9uIHV0ZjE2bGVTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIHZhciBieXRlcyA9IGJ1Zi5zbGljZShzdGFydCwgZW5kKVxuICB2YXIgcmVzID0gJydcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBieXRlcy5sZW5ndGg7IGkgKz0gMikge1xuICAgIHJlcyArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGJ5dGVzW2ldICsgYnl0ZXNbaSArIDFdICogMjU2KVxuICB9XG4gIHJldHVybiByZXNcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5zbGljZSA9IGZ1bmN0aW9uIHNsaWNlIChzdGFydCwgZW5kKSB7XG4gIHZhciBsZW4gPSB0aGlzLmxlbmd0aFxuICBzdGFydCA9IH5+c3RhcnRcbiAgZW5kID0gZW5kID09PSB1bmRlZmluZWQgPyBsZW4gOiB+fmVuZFxuXG4gIGlmIChzdGFydCA8IDApIHtcbiAgICBzdGFydCArPSBsZW5cbiAgICBpZiAoc3RhcnQgPCAwKSBzdGFydCA9IDBcbiAgfSBlbHNlIGlmIChzdGFydCA+IGxlbikge1xuICAgIHN0YXJ0ID0gbGVuXG4gIH1cblxuICBpZiAoZW5kIDwgMCkge1xuICAgIGVuZCArPSBsZW5cbiAgICBpZiAoZW5kIDwgMCkgZW5kID0gMFxuICB9IGVsc2UgaWYgKGVuZCA+IGxlbikge1xuICAgIGVuZCA9IGxlblxuICB9XG5cbiAgaWYgKGVuZCA8IHN0YXJ0KSBlbmQgPSBzdGFydFxuXG4gIHZhciBuZXdCdWZcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgbmV3QnVmID0gdGhpcy5zdWJhcnJheShzdGFydCwgZW5kKVxuICAgIG5ld0J1Zi5fX3Byb3RvX18gPSBCdWZmZXIucHJvdG90eXBlXG4gIH0gZWxzZSB7XG4gICAgdmFyIHNsaWNlTGVuID0gZW5kIC0gc3RhcnRcbiAgICBuZXdCdWYgPSBuZXcgQnVmZmVyKHNsaWNlTGVuLCB1bmRlZmluZWQpXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzbGljZUxlbjsgKytpKSB7XG4gICAgICBuZXdCdWZbaV0gPSB0aGlzW2kgKyBzdGFydF1cbiAgICB9XG4gIH1cblxuICByZXR1cm4gbmV3QnVmXG59XG5cbi8qXG4gKiBOZWVkIHRvIG1ha2Ugc3VyZSB0aGF0IGJ1ZmZlciBpc24ndCB0cnlpbmcgdG8gd3JpdGUgb3V0IG9mIGJvdW5kcy5cbiAqL1xuZnVuY3Rpb24gY2hlY2tPZmZzZXQgKG9mZnNldCwgZXh0LCBsZW5ndGgpIHtcbiAgaWYgKChvZmZzZXQgJSAxKSAhPT0gMCB8fCBvZmZzZXQgPCAwKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignb2Zmc2V0IGlzIG5vdCB1aW50JylcbiAgaWYgKG9mZnNldCArIGV4dCA+IGxlbmd0aCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ1RyeWluZyB0byBhY2Nlc3MgYmV5b25kIGJ1ZmZlciBsZW5ndGgnKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50TEUgPSBmdW5jdGlvbiByZWFkVUludExFIChvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgYnl0ZUxlbmd0aCwgdGhpcy5sZW5ndGgpXG5cbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0XVxuICB2YXIgbXVsID0gMVxuICB2YXIgaSA9IDBcbiAgd2hpbGUgKCsraSA8IGJ5dGVMZW5ndGggJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB2YWwgKz0gdGhpc1tvZmZzZXQgKyBpXSAqIG11bFxuICB9XG5cbiAgcmV0dXJuIHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50QkUgPSBmdW5jdGlvbiByZWFkVUludEJFIChvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIHtcbiAgICBjaGVja09mZnNldChvZmZzZXQsIGJ5dGVMZW5ndGgsIHRoaXMubGVuZ3RoKVxuICB9XG5cbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0ICsgLS1ieXRlTGVuZ3RoXVxuICB2YXIgbXVsID0gMVxuICB3aGlsZSAoYnl0ZUxlbmd0aCA+IDAgJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB2YWwgKz0gdGhpc1tvZmZzZXQgKyAtLWJ5dGVMZW5ndGhdICogbXVsXG4gIH1cblxuICByZXR1cm4gdmFsXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnQ4ID0gZnVuY3Rpb24gcmVhZFVJbnQ4IChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMSwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiB0aGlzW29mZnNldF1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludDE2TEUgPSBmdW5jdGlvbiByZWFkVUludDE2TEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCAyLCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIHRoaXNbb2Zmc2V0XSB8ICh0aGlzW29mZnNldCArIDFdIDw8IDgpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnQxNkJFID0gZnVuY3Rpb24gcmVhZFVJbnQxNkJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMiwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiAodGhpc1tvZmZzZXRdIDw8IDgpIHwgdGhpc1tvZmZzZXQgKyAxXVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50MzJMRSA9IGZ1bmN0aW9uIHJlYWRVSW50MzJMRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDQsIHRoaXMubGVuZ3RoKVxuXG4gIHJldHVybiAoKHRoaXNbb2Zmc2V0XSkgfFxuICAgICAgKHRoaXNbb2Zmc2V0ICsgMV0gPDwgOCkgfFxuICAgICAgKHRoaXNbb2Zmc2V0ICsgMl0gPDwgMTYpKSArXG4gICAgICAodGhpc1tvZmZzZXQgKyAzXSAqIDB4MTAwMDAwMClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludDMyQkUgPSBmdW5jdGlvbiByZWFkVUludDMyQkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcblxuICByZXR1cm4gKHRoaXNbb2Zmc2V0XSAqIDB4MTAwMDAwMCkgK1xuICAgICgodGhpc1tvZmZzZXQgKyAxXSA8PCAxNikgfFxuICAgICh0aGlzW29mZnNldCArIDJdIDw8IDgpIHxcbiAgICB0aGlzW29mZnNldCArIDNdKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnRMRSA9IGZ1bmN0aW9uIHJlYWRJbnRMRSAob2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoIHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIGJ5dGVMZW5ndGgsIHRoaXMubGVuZ3RoKVxuXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldF1cbiAgdmFyIG11bCA9IDFcbiAgdmFyIGkgPSAwXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdmFsICs9IHRoaXNbb2Zmc2V0ICsgaV0gKiBtdWxcbiAgfVxuICBtdWwgKj0gMHg4MFxuXG4gIGlmICh2YWwgPj0gbXVsKSB2YWwgLT0gTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGgpXG5cbiAgcmV0dXJuIHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnRCRSA9IGZ1bmN0aW9uIHJlYWRJbnRCRSAob2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoIHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIGJ5dGVMZW5ndGgsIHRoaXMubGVuZ3RoKVxuXG4gIHZhciBpID0gYnl0ZUxlbmd0aFxuICB2YXIgbXVsID0gMVxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXQgKyAtLWldXG4gIHdoaWxlIChpID4gMCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHZhbCArPSB0aGlzW29mZnNldCArIC0taV0gKiBtdWxcbiAgfVxuICBtdWwgKj0gMHg4MFxuXG4gIGlmICh2YWwgPj0gbXVsKSB2YWwgLT0gTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGgpXG5cbiAgcmV0dXJuIHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnQ4ID0gZnVuY3Rpb24gcmVhZEludDggKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCAxLCB0aGlzLmxlbmd0aClcbiAgaWYgKCEodGhpc1tvZmZzZXRdICYgMHg4MCkpIHJldHVybiAodGhpc1tvZmZzZXRdKVxuICByZXR1cm4gKCgweGZmIC0gdGhpc1tvZmZzZXRdICsgMSkgKiAtMSlcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50MTZMRSA9IGZ1bmN0aW9uIHJlYWRJbnQxNkxFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMiwgdGhpcy5sZW5ndGgpXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldF0gfCAodGhpc1tvZmZzZXQgKyAxXSA8PCA4KVxuICByZXR1cm4gKHZhbCAmIDB4ODAwMCkgPyB2YWwgfCAweEZGRkYwMDAwIDogdmFsXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludDE2QkUgPSBmdW5jdGlvbiByZWFkSW50MTZCRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDIsIHRoaXMubGVuZ3RoKVxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXQgKyAxXSB8ICh0aGlzW29mZnNldF0gPDwgOClcbiAgcmV0dXJuICh2YWwgJiAweDgwMDApID8gdmFsIHwgMHhGRkZGMDAwMCA6IHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnQzMkxFID0gZnVuY3Rpb24gcmVhZEludDMyTEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcblxuICByZXR1cm4gKHRoaXNbb2Zmc2V0XSkgfFxuICAgICh0aGlzW29mZnNldCArIDFdIDw8IDgpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAyXSA8PCAxNikgfFxuICAgICh0aGlzW29mZnNldCArIDNdIDw8IDI0KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnQzMkJFID0gZnVuY3Rpb24gcmVhZEludDMyQkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcblxuICByZXR1cm4gKHRoaXNbb2Zmc2V0XSA8PCAyNCkgfFxuICAgICh0aGlzW29mZnNldCArIDFdIDw8IDE2KSB8XG4gICAgKHRoaXNbb2Zmc2V0ICsgMl0gPDwgOCkgfFxuICAgICh0aGlzW29mZnNldCArIDNdKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRGbG9hdExFID0gZnVuY3Rpb24gcmVhZEZsb2F0TEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIGllZWU3NTQucmVhZCh0aGlzLCBvZmZzZXQsIHRydWUsIDIzLCA0KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRGbG9hdEJFID0gZnVuY3Rpb24gcmVhZEZsb2F0QkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIGllZWU3NTQucmVhZCh0aGlzLCBvZmZzZXQsIGZhbHNlLCAyMywgNClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkRG91YmxlTEUgPSBmdW5jdGlvbiByZWFkRG91YmxlTEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA4LCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIGllZWU3NTQucmVhZCh0aGlzLCBvZmZzZXQsIHRydWUsIDUyLCA4KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWREb3VibGVCRSA9IGZ1bmN0aW9uIHJlYWREb3VibGVCRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDgsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gaWVlZTc1NC5yZWFkKHRoaXMsIG9mZnNldCwgZmFsc2UsIDUyLCA4KVxufVxuXG5mdW5jdGlvbiBjaGVja0ludCAoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBleHQsIG1heCwgbWluKSB7XG4gIGlmICghQnVmZmVyLmlzQnVmZmVyKGJ1ZikpIHRocm93IG5ldyBUeXBlRXJyb3IoJ1wiYnVmZmVyXCIgYXJndW1lbnQgbXVzdCBiZSBhIEJ1ZmZlciBpbnN0YW5jZScpXG4gIGlmICh2YWx1ZSA+IG1heCB8fCB2YWx1ZSA8IG1pbikgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ1widmFsdWVcIiBhcmd1bWVudCBpcyBvdXQgb2YgYm91bmRzJylcbiAgaWYgKG9mZnNldCArIGV4dCA+IGJ1Zi5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdJbmRleCBvdXQgb2YgcmFuZ2UnKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludExFID0gZnVuY3Rpb24gd3JpdGVVSW50TEUgKHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIHtcbiAgICB2YXIgbWF4Qnl0ZXMgPSBNYXRoLnBvdygyLCA4ICogYnl0ZUxlbmd0aCkgLSAxXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbWF4Qnl0ZXMsIDApXG4gIH1cblxuICB2YXIgbXVsID0gMVxuICB2YXIgaSA9IDBcbiAgdGhpc1tvZmZzZXRdID0gdmFsdWUgJiAweEZGXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICh2YWx1ZSAvIG11bCkgJiAweEZGXG4gIH1cblxuICByZXR1cm4gb2Zmc2V0ICsgYnl0ZUxlbmd0aFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludEJFID0gZnVuY3Rpb24gd3JpdGVVSW50QkUgKHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIHtcbiAgICB2YXIgbWF4Qnl0ZXMgPSBNYXRoLnBvdygyLCA4ICogYnl0ZUxlbmd0aCkgLSAxXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbWF4Qnl0ZXMsIDApXG4gIH1cblxuICB2YXIgaSA9IGJ5dGVMZW5ndGggLSAxXG4gIHZhciBtdWwgPSAxXG4gIHRoaXNbb2Zmc2V0ICsgaV0gPSB2YWx1ZSAmIDB4RkZcbiAgd2hpbGUgKC0taSA+PSAwICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICh2YWx1ZSAvIG11bCkgJiAweEZGXG4gIH1cblxuICByZXR1cm4gb2Zmc2V0ICsgYnl0ZUxlbmd0aFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludDggPSBmdW5jdGlvbiB3cml0ZVVJbnQ4ICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDEsIDB4ZmYsIDApXG4gIGlmICghQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHZhbHVlID0gTWF0aC5mbG9vcih2YWx1ZSlcbiAgdGhpc1tvZmZzZXRdID0gKHZhbHVlICYgMHhmZilcbiAgcmV0dXJuIG9mZnNldCArIDFcbn1cblxuZnVuY3Rpb24gb2JqZWN0V3JpdGVVSW50MTYgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuKSB7XG4gIGlmICh2YWx1ZSA8IDApIHZhbHVlID0gMHhmZmZmICsgdmFsdWUgKyAxXG4gIGZvciAodmFyIGkgPSAwLCBqID0gTWF0aC5taW4oYnVmLmxlbmd0aCAtIG9mZnNldCwgMik7IGkgPCBqOyArK2kpIHtcbiAgICBidWZbb2Zmc2V0ICsgaV0gPSAodmFsdWUgJiAoMHhmZiA8PCAoOCAqIChsaXR0bGVFbmRpYW4gPyBpIDogMSAtIGkpKSkpID4+PlxuICAgICAgKGxpdHRsZUVuZGlhbiA/IGkgOiAxIC0gaSkgKiA4XG4gIH1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQxNkxFID0gZnVuY3Rpb24gd3JpdGVVSW50MTZMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAyLCAweGZmZmYsIDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gOClcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQxNih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyAyXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50MTZCRSA9IGZ1bmN0aW9uIHdyaXRlVUludDE2QkUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMiwgMHhmZmZmLCAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MTYodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDJcbn1cblxuZnVuY3Rpb24gb2JqZWN0V3JpdGVVSW50MzIgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuKSB7XG4gIGlmICh2YWx1ZSA8IDApIHZhbHVlID0gMHhmZmZmZmZmZiArIHZhbHVlICsgMVxuICBmb3IgKHZhciBpID0gMCwgaiA9IE1hdGgubWluKGJ1Zi5sZW5ndGggLSBvZmZzZXQsIDQpOyBpIDwgajsgKytpKSB7XG4gICAgYnVmW29mZnNldCArIGldID0gKHZhbHVlID4+PiAobGl0dGxlRW5kaWFuID8gaSA6IDMgLSBpKSAqIDgpICYgMHhmZlxuICB9XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50MzJMRSA9IGZ1bmN0aW9uIHdyaXRlVUludDMyTEUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgNCwgMHhmZmZmZmZmZiwgMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXQgKyAzXSA9ICh2YWx1ZSA+Pj4gMjQpXG4gICAgdGhpc1tvZmZzZXQgKyAyXSA9ICh2YWx1ZSA+Pj4gMTYpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDMyKHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDRcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQzMkJFID0gZnVuY3Rpb24gd3JpdGVVSW50MzJCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCA0LCAweGZmZmZmZmZmLCAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgPj4+IDI0KVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgPj4+IDE2KVxuICAgIHRoaXNbb2Zmc2V0ICsgMl0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAzXSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MzIodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDRcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludExFID0gZnVuY3Rpb24gd3JpdGVJbnRMRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgdmFyIGxpbWl0ID0gTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGggLSAxKVxuXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbGltaXQgLSAxLCAtbGltaXQpXG4gIH1cblxuICB2YXIgaSA9IDBcbiAgdmFyIG11bCA9IDFcbiAgdmFyIHN1YiA9IDBcbiAgdGhpc1tvZmZzZXRdID0gdmFsdWUgJiAweEZGXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgaWYgKHZhbHVlIDwgMCAmJiBzdWIgPT09IDAgJiYgdGhpc1tvZmZzZXQgKyBpIC0gMV0gIT09IDApIHtcbiAgICAgIHN1YiA9IDFcbiAgICB9XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICgodmFsdWUgLyBtdWwpID4+IDApIC0gc3ViICYgMHhGRlxuICB9XG5cbiAgcmV0dXJuIG9mZnNldCArIGJ5dGVMZW5ndGhcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludEJFID0gZnVuY3Rpb24gd3JpdGVJbnRCRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgdmFyIGxpbWl0ID0gTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGggLSAxKVxuXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbGltaXQgLSAxLCAtbGltaXQpXG4gIH1cblxuICB2YXIgaSA9IGJ5dGVMZW5ndGggLSAxXG4gIHZhciBtdWwgPSAxXG4gIHZhciBzdWIgPSAwXG4gIHRoaXNbb2Zmc2V0ICsgaV0gPSB2YWx1ZSAmIDB4RkZcbiAgd2hpbGUgKC0taSA+PSAwICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgaWYgKHZhbHVlIDwgMCAmJiBzdWIgPT09IDAgJiYgdGhpc1tvZmZzZXQgKyBpICsgMV0gIT09IDApIHtcbiAgICAgIHN1YiA9IDFcbiAgICB9XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICgodmFsdWUgLyBtdWwpID4+IDApIC0gc3ViICYgMHhGRlxuICB9XG5cbiAgcmV0dXJuIG9mZnNldCArIGJ5dGVMZW5ndGhcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludDggPSBmdW5jdGlvbiB3cml0ZUludDggKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMSwgMHg3ZiwgLTB4ODApXG4gIGlmICghQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHZhbHVlID0gTWF0aC5mbG9vcih2YWx1ZSlcbiAgaWYgKHZhbHVlIDwgMCkgdmFsdWUgPSAweGZmICsgdmFsdWUgKyAxXG4gIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIHJldHVybiBvZmZzZXQgKyAxXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQxNkxFID0gZnVuY3Rpb24gd3JpdGVJbnQxNkxFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDIsIDB4N2ZmZiwgLTB4ODAwMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlICYgMHhmZilcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlID4+PiA4KVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDE2KHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDJcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludDE2QkUgPSBmdW5jdGlvbiB3cml0ZUludDE2QkUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMiwgMHg3ZmZmLCAtMHg4MDAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MTYodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDJcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludDMyTEUgPSBmdW5jdGlvbiB3cml0ZUludDMyTEUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgNCwgMHg3ZmZmZmZmZiwgLTB4ODAwMDAwMDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldCArIDJdID0gKHZhbHVlID4+PiAxNilcbiAgICB0aGlzW29mZnNldCArIDNdID0gKHZhbHVlID4+PiAyNClcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQzMih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyA0XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQzMkJFID0gZnVuY3Rpb24gd3JpdGVJbnQzMkJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDQsIDB4N2ZmZmZmZmYsIC0weDgwMDAwMDAwKVxuICBpZiAodmFsdWUgPCAwKSB2YWx1ZSA9IDB4ZmZmZmZmZmYgKyB2YWx1ZSArIDFcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlID4+PiAyNClcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlID4+PiAxNilcbiAgICB0aGlzW29mZnNldCArIDJdID0gKHZhbHVlID4+PiA4KVxuICAgIHRoaXNbb2Zmc2V0ICsgM10gPSAodmFsdWUgJiAweGZmKVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDMyKHRoaXMsIHZhbHVlLCBvZmZzZXQsIGZhbHNlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyA0XG59XG5cbmZ1bmN0aW9uIGNoZWNrSUVFRTc1NCAoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBleHQsIG1heCwgbWluKSB7XG4gIGlmIChvZmZzZXQgKyBleHQgPiBidWYubGVuZ3RoKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignSW5kZXggb3V0IG9mIHJhbmdlJylcbiAgaWYgKG9mZnNldCA8IDApIHRocm93IG5ldyBSYW5nZUVycm9yKCdJbmRleCBvdXQgb2YgcmFuZ2UnKVxufVxuXG5mdW5jdGlvbiB3cml0ZUZsb2F0IChidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkge1xuICAgIGNoZWNrSUVFRTc1NChidWYsIHZhbHVlLCBvZmZzZXQsIDQsIDMuNDAyODIzNDY2Mzg1Mjg4NmUrMzgsIC0zLjQwMjgyMzQ2NjM4NTI4ODZlKzM4KVxuICB9XG4gIGllZWU3NTQud3JpdGUoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBsaXR0bGVFbmRpYW4sIDIzLCA0KVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlRmxvYXRMRSA9IGZ1bmN0aW9uIHdyaXRlRmxvYXRMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgcmV0dXJuIHdyaXRlRmxvYXQodGhpcywgdmFsdWUsIG9mZnNldCwgdHJ1ZSwgbm9Bc3NlcnQpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVGbG9hdEJFID0gZnVuY3Rpb24gd3JpdGVGbG9hdEJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICByZXR1cm4gd3JpdGVGbG9hdCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSwgbm9Bc3NlcnQpXG59XG5cbmZ1bmN0aW9uIHdyaXRlRG91YmxlIChidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkge1xuICAgIGNoZWNrSUVFRTc1NChidWYsIHZhbHVlLCBvZmZzZXQsIDgsIDEuNzk3NjkzMTM0ODYyMzE1N0UrMzA4LCAtMS43OTc2OTMxMzQ4NjIzMTU3RSszMDgpXG4gIH1cbiAgaWVlZTc1NC53cml0ZShidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgNTIsIDgpXG4gIHJldHVybiBvZmZzZXQgKyA4XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVEb3VibGVMRSA9IGZ1bmN0aW9uIHdyaXRlRG91YmxlTEUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHJldHVybiB3cml0ZURvdWJsZSh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlLCBub0Fzc2VydClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZURvdWJsZUJFID0gZnVuY3Rpb24gd3JpdGVEb3VibGVCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgcmV0dXJuIHdyaXRlRG91YmxlKHRoaXMsIHZhbHVlLCBvZmZzZXQsIGZhbHNlLCBub0Fzc2VydClcbn1cblxuLy8gY29weSh0YXJnZXRCdWZmZXIsIHRhcmdldFN0YXJ0PTAsIHNvdXJjZVN0YXJ0PTAsIHNvdXJjZUVuZD1idWZmZXIubGVuZ3RoKVxuQnVmZmVyLnByb3RvdHlwZS5jb3B5ID0gZnVuY3Rpb24gY29weSAodGFyZ2V0LCB0YXJnZXRTdGFydCwgc3RhcnQsIGVuZCkge1xuICBpZiAoIXN0YXJ0KSBzdGFydCA9IDBcbiAgaWYgKCFlbmQgJiYgZW5kICE9PSAwKSBlbmQgPSB0aGlzLmxlbmd0aFxuICBpZiAodGFyZ2V0U3RhcnQgPj0gdGFyZ2V0Lmxlbmd0aCkgdGFyZ2V0U3RhcnQgPSB0YXJnZXQubGVuZ3RoXG4gIGlmICghdGFyZ2V0U3RhcnQpIHRhcmdldFN0YXJ0ID0gMFxuICBpZiAoZW5kID4gMCAmJiBlbmQgPCBzdGFydCkgZW5kID0gc3RhcnRcblxuICAvLyBDb3B5IDAgYnl0ZXM7IHdlJ3JlIGRvbmVcbiAgaWYgKGVuZCA9PT0gc3RhcnQpIHJldHVybiAwXG4gIGlmICh0YXJnZXQubGVuZ3RoID09PSAwIHx8IHRoaXMubGVuZ3RoID09PSAwKSByZXR1cm4gMFxuXG4gIC8vIEZhdGFsIGVycm9yIGNvbmRpdGlvbnNcbiAgaWYgKHRhcmdldFN0YXJ0IDwgMCkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCd0YXJnZXRTdGFydCBvdXQgb2YgYm91bmRzJylcbiAgfVxuICBpZiAoc3RhcnQgPCAwIHx8IHN0YXJ0ID49IHRoaXMubGVuZ3RoKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignc291cmNlU3RhcnQgb3V0IG9mIGJvdW5kcycpXG4gIGlmIChlbmQgPCAwKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignc291cmNlRW5kIG91dCBvZiBib3VuZHMnKVxuXG4gIC8vIEFyZSB3ZSBvb2I/XG4gIGlmIChlbmQgPiB0aGlzLmxlbmd0aCkgZW5kID0gdGhpcy5sZW5ndGhcbiAgaWYgKHRhcmdldC5sZW5ndGggLSB0YXJnZXRTdGFydCA8IGVuZCAtIHN0YXJ0KSB7XG4gICAgZW5kID0gdGFyZ2V0Lmxlbmd0aCAtIHRhcmdldFN0YXJ0ICsgc3RhcnRcbiAgfVxuXG4gIHZhciBsZW4gPSBlbmQgLSBzdGFydFxuICB2YXIgaVxuXG4gIGlmICh0aGlzID09PSB0YXJnZXQgJiYgc3RhcnQgPCB0YXJnZXRTdGFydCAmJiB0YXJnZXRTdGFydCA8IGVuZCkge1xuICAgIC8vIGRlc2NlbmRpbmcgY29weSBmcm9tIGVuZFxuICAgIGZvciAoaSA9IGxlbiAtIDE7IGkgPj0gMDsgLS1pKSB7XG4gICAgICB0YXJnZXRbaSArIHRhcmdldFN0YXJ0XSA9IHRoaXNbaSArIHN0YXJ0XVxuICAgIH1cbiAgfSBlbHNlIGlmIChsZW4gPCAxMDAwIHx8ICFCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIC8vIGFzY2VuZGluZyBjb3B5IGZyb20gc3RhcnRcbiAgICBmb3IgKGkgPSAwOyBpIDwgbGVuOyArK2kpIHtcbiAgICAgIHRhcmdldFtpICsgdGFyZ2V0U3RhcnRdID0gdGhpc1tpICsgc3RhcnRdXG4gICAgfVxuICB9IGVsc2Uge1xuICAgIFVpbnQ4QXJyYXkucHJvdG90eXBlLnNldC5jYWxsKFxuICAgICAgdGFyZ2V0LFxuICAgICAgdGhpcy5zdWJhcnJheShzdGFydCwgc3RhcnQgKyBsZW4pLFxuICAgICAgdGFyZ2V0U3RhcnRcbiAgICApXG4gIH1cblxuICByZXR1cm4gbGVuXG59XG5cbi8vIFVzYWdlOlxuLy8gICAgYnVmZmVyLmZpbGwobnVtYmVyWywgb2Zmc2V0WywgZW5kXV0pXG4vLyAgICBidWZmZXIuZmlsbChidWZmZXJbLCBvZmZzZXRbLCBlbmRdXSlcbi8vICAgIGJ1ZmZlci5maWxsKHN0cmluZ1ssIG9mZnNldFssIGVuZF1dWywgZW5jb2RpbmddKVxuQnVmZmVyLnByb3RvdHlwZS5maWxsID0gZnVuY3Rpb24gZmlsbCAodmFsLCBzdGFydCwgZW5kLCBlbmNvZGluZykge1xuICAvLyBIYW5kbGUgc3RyaW5nIGNhc2VzOlxuICBpZiAodHlwZW9mIHZhbCA9PT0gJ3N0cmluZycpIHtcbiAgICBpZiAodHlwZW9mIHN0YXJ0ID09PSAnc3RyaW5nJykge1xuICAgICAgZW5jb2RpbmcgPSBzdGFydFxuICAgICAgc3RhcnQgPSAwXG4gICAgICBlbmQgPSB0aGlzLmxlbmd0aFxuICAgIH0gZWxzZSBpZiAodHlwZW9mIGVuZCA9PT0gJ3N0cmluZycpIHtcbiAgICAgIGVuY29kaW5nID0gZW5kXG4gICAgICBlbmQgPSB0aGlzLmxlbmd0aFxuICAgIH1cbiAgICBpZiAodmFsLmxlbmd0aCA9PT0gMSkge1xuICAgICAgdmFyIGNvZGUgPSB2YWwuY2hhckNvZGVBdCgwKVxuICAgICAgaWYgKGNvZGUgPCAyNTYpIHtcbiAgICAgICAgdmFsID0gY29kZVxuICAgICAgfVxuICAgIH1cbiAgICBpZiAoZW5jb2RpbmcgIT09IHVuZGVmaW5lZCAmJiB0eXBlb2YgZW5jb2RpbmcgIT09ICdzdHJpbmcnKSB7XG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdlbmNvZGluZyBtdXN0IGJlIGEgc3RyaW5nJylcbiAgICB9XG4gICAgaWYgKHR5cGVvZiBlbmNvZGluZyA9PT0gJ3N0cmluZycgJiYgIUJ1ZmZlci5pc0VuY29kaW5nKGVuY29kaW5nKSkge1xuICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignVW5rbm93biBlbmNvZGluZzogJyArIGVuY29kaW5nKVxuICAgIH1cbiAgfSBlbHNlIGlmICh0eXBlb2YgdmFsID09PSAnbnVtYmVyJykge1xuICAgIHZhbCA9IHZhbCAmIDI1NVxuICB9XG5cbiAgLy8gSW52YWxpZCByYW5nZXMgYXJlIG5vdCBzZXQgdG8gYSBkZWZhdWx0LCBzbyBjYW4gcmFuZ2UgY2hlY2sgZWFybHkuXG4gIGlmIChzdGFydCA8IDAgfHwgdGhpcy5sZW5ndGggPCBzdGFydCB8fCB0aGlzLmxlbmd0aCA8IGVuZCkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCdPdXQgb2YgcmFuZ2UgaW5kZXgnKVxuICB9XG5cbiAgaWYgKGVuZCA8PSBzdGFydCkge1xuICAgIHJldHVybiB0aGlzXG4gIH1cblxuICBzdGFydCA9IHN0YXJ0ID4+PiAwXG4gIGVuZCA9IGVuZCA9PT0gdW5kZWZpbmVkID8gdGhpcy5sZW5ndGggOiBlbmQgPj4+IDBcblxuICBpZiAoIXZhbCkgdmFsID0gMFxuXG4gIHZhciBpXG4gIGlmICh0eXBlb2YgdmFsID09PSAnbnVtYmVyJykge1xuICAgIGZvciAoaSA9IHN0YXJ0OyBpIDwgZW5kOyArK2kpIHtcbiAgICAgIHRoaXNbaV0gPSB2YWxcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgdmFyIGJ5dGVzID0gQnVmZmVyLmlzQnVmZmVyKHZhbClcbiAgICAgID8gdmFsXG4gICAgICA6IHV0ZjhUb0J5dGVzKG5ldyBCdWZmZXIodmFsLCBlbmNvZGluZykudG9TdHJpbmcoKSlcbiAgICB2YXIgbGVuID0gYnl0ZXMubGVuZ3RoXG4gICAgZm9yIChpID0gMDsgaSA8IGVuZCAtIHN0YXJ0OyArK2kpIHtcbiAgICAgIHRoaXNbaSArIHN0YXJ0XSA9IGJ5dGVzW2kgJSBsZW5dXG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHRoaXNcbn1cblxuLy8gSEVMUEVSIEZVTkNUSU9OU1xuLy8gPT09PT09PT09PT09PT09PVxuXG52YXIgSU5WQUxJRF9CQVNFNjRfUkUgPSAvW14rXFwvMC05QS1aYS16LV9dL2dcblxuZnVuY3Rpb24gYmFzZTY0Y2xlYW4gKHN0cikge1xuICAvLyBOb2RlIHN0cmlwcyBvdXQgaW52YWxpZCBjaGFyYWN0ZXJzIGxpa2UgXFxuIGFuZCBcXHQgZnJvbSB0aGUgc3RyaW5nLCBiYXNlNjQtanMgZG9lcyBub3RcbiAgc3RyID0gc3RyaW5ndHJpbShzdHIpLnJlcGxhY2UoSU5WQUxJRF9CQVNFNjRfUkUsICcnKVxuICAvLyBOb2RlIGNvbnZlcnRzIHN0cmluZ3Mgd2l0aCBsZW5ndGggPCAyIHRvICcnXG4gIGlmIChzdHIubGVuZ3RoIDwgMikgcmV0dXJuICcnXG4gIC8vIE5vZGUgYWxsb3dzIGZvciBub24tcGFkZGVkIGJhc2U2NCBzdHJpbmdzIChtaXNzaW5nIHRyYWlsaW5nID09PSksIGJhc2U2NC1qcyBkb2VzIG5vdFxuICB3aGlsZSAoc3RyLmxlbmd0aCAlIDQgIT09IDApIHtcbiAgICBzdHIgPSBzdHIgKyAnPSdcbiAgfVxuICByZXR1cm4gc3RyXG59XG5cbmZ1bmN0aW9uIHN0cmluZ3RyaW0gKHN0cikge1xuICBpZiAoc3RyLnRyaW0pIHJldHVybiBzdHIudHJpbSgpXG4gIHJldHVybiBzdHIucmVwbGFjZSgvXlxccyt8XFxzKyQvZywgJycpXG59XG5cbmZ1bmN0aW9uIHRvSGV4IChuKSB7XG4gIGlmIChuIDwgMTYpIHJldHVybiAnMCcgKyBuLnRvU3RyaW5nKDE2KVxuICByZXR1cm4gbi50b1N0cmluZygxNilcbn1cblxuZnVuY3Rpb24gdXRmOFRvQnl0ZXMgKHN0cmluZywgdW5pdHMpIHtcbiAgdW5pdHMgPSB1bml0cyB8fCBJbmZpbml0eVxuICB2YXIgY29kZVBvaW50XG4gIHZhciBsZW5ndGggPSBzdHJpbmcubGVuZ3RoXG4gIHZhciBsZWFkU3Vycm9nYXRlID0gbnVsbFxuICB2YXIgYnl0ZXMgPSBbXVxuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyArK2kpIHtcbiAgICBjb2RlUG9pbnQgPSBzdHJpbmcuY2hhckNvZGVBdChpKVxuXG4gICAgLy8gaXMgc3Vycm9nYXRlIGNvbXBvbmVudFxuICAgIGlmIChjb2RlUG9pbnQgPiAweEQ3RkYgJiYgY29kZVBvaW50IDwgMHhFMDAwKSB7XG4gICAgICAvLyBsYXN0IGNoYXIgd2FzIGEgbGVhZFxuICAgICAgaWYgKCFsZWFkU3Vycm9nYXRlKSB7XG4gICAgICAgIC8vIG5vIGxlYWQgeWV0XG4gICAgICAgIGlmIChjb2RlUG9pbnQgPiAweERCRkYpIHtcbiAgICAgICAgICAvLyB1bmV4cGVjdGVkIHRyYWlsXG4gICAgICAgICAgaWYgKCh1bml0cyAtPSAzKSA+IC0xKSBieXRlcy5wdXNoKDB4RUYsIDB4QkYsIDB4QkQpXG4gICAgICAgICAgY29udGludWVcbiAgICAgICAgfSBlbHNlIGlmIChpICsgMSA9PT0gbGVuZ3RoKSB7XG4gICAgICAgICAgLy8gdW5wYWlyZWQgbGVhZFxuICAgICAgICAgIGlmICgodW5pdHMgLT0gMykgPiAtMSkgYnl0ZXMucHVzaCgweEVGLCAweEJGLCAweEJEKVxuICAgICAgICAgIGNvbnRpbnVlXG4gICAgICAgIH1cblxuICAgICAgICAvLyB2YWxpZCBsZWFkXG4gICAgICAgIGxlYWRTdXJyb2dhdGUgPSBjb2RlUG9pbnRcblxuICAgICAgICBjb250aW51ZVxuICAgICAgfVxuXG4gICAgICAvLyAyIGxlYWRzIGluIGEgcm93XG4gICAgICBpZiAoY29kZVBvaW50IDwgMHhEQzAwKSB7XG4gICAgICAgIGlmICgodW5pdHMgLT0gMykgPiAtMSkgYnl0ZXMucHVzaCgweEVGLCAweEJGLCAweEJEKVxuICAgICAgICBsZWFkU3Vycm9nYXRlID0gY29kZVBvaW50XG4gICAgICAgIGNvbnRpbnVlXG4gICAgICB9XG5cbiAgICAgIC8vIHZhbGlkIHN1cnJvZ2F0ZSBwYWlyXG4gICAgICBjb2RlUG9pbnQgPSAobGVhZFN1cnJvZ2F0ZSAtIDB4RDgwMCA8PCAxMCB8IGNvZGVQb2ludCAtIDB4REMwMCkgKyAweDEwMDAwXG4gICAgfSBlbHNlIGlmIChsZWFkU3Vycm9nYXRlKSB7XG4gICAgICAvLyB2YWxpZCBibXAgY2hhciwgYnV0IGxhc3QgY2hhciB3YXMgYSBsZWFkXG4gICAgICBpZiAoKHVuaXRzIC09IDMpID4gLTEpIGJ5dGVzLnB1c2goMHhFRiwgMHhCRiwgMHhCRClcbiAgICB9XG5cbiAgICBsZWFkU3Vycm9nYXRlID0gbnVsbFxuXG4gICAgLy8gZW5jb2RlIHV0ZjhcbiAgICBpZiAoY29kZVBvaW50IDwgMHg4MCkge1xuICAgICAgaWYgKCh1bml0cyAtPSAxKSA8IDApIGJyZWFrXG4gICAgICBieXRlcy5wdXNoKGNvZGVQb2ludClcbiAgICB9IGVsc2UgaWYgKGNvZGVQb2ludCA8IDB4ODAwKSB7XG4gICAgICBpZiAoKHVuaXRzIC09IDIpIDwgMCkgYnJlYWtcbiAgICAgIGJ5dGVzLnB1c2goXG4gICAgICAgIGNvZGVQb2ludCA+PiAweDYgfCAweEMwLFxuICAgICAgICBjb2RlUG9pbnQgJiAweDNGIHwgMHg4MFxuICAgICAgKVxuICAgIH0gZWxzZSBpZiAoY29kZVBvaW50IDwgMHgxMDAwMCkge1xuICAgICAgaWYgKCh1bml0cyAtPSAzKSA8IDApIGJyZWFrXG4gICAgICBieXRlcy5wdXNoKFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHhDIHwgMHhFMCxcbiAgICAgICAgY29kZVBvaW50ID4+IDB4NiAmIDB4M0YgfCAweDgwLFxuICAgICAgICBjb2RlUG9pbnQgJiAweDNGIHwgMHg4MFxuICAgICAgKVxuICAgIH0gZWxzZSBpZiAoY29kZVBvaW50IDwgMHgxMTAwMDApIHtcbiAgICAgIGlmICgodW5pdHMgLT0gNCkgPCAwKSBicmVha1xuICAgICAgYnl0ZXMucHVzaChcbiAgICAgICAgY29kZVBvaW50ID4+IDB4MTIgfCAweEYwLFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHhDICYgMHgzRiB8IDB4ODAsXG4gICAgICAgIGNvZGVQb2ludCA+PiAweDYgJiAweDNGIHwgMHg4MCxcbiAgICAgICAgY29kZVBvaW50ICYgMHgzRiB8IDB4ODBcbiAgICAgIClcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGNvZGUgcG9pbnQnKVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiBieXRlc1xufVxuXG5mdW5jdGlvbiBhc2NpaVRvQnl0ZXMgKHN0cikge1xuICB2YXIgYnl0ZUFycmF5ID0gW11cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBzdHIubGVuZ3RoOyArK2kpIHtcbiAgICAvLyBOb2RlJ3MgY29kZSBzZWVtcyB0byBiZSBkb2luZyB0aGlzIGFuZCBub3QgJiAweDdGLi5cbiAgICBieXRlQXJyYXkucHVzaChzdHIuY2hhckNvZGVBdChpKSAmIDB4RkYpXG4gIH1cbiAgcmV0dXJuIGJ5dGVBcnJheVxufVxuXG5mdW5jdGlvbiB1dGYxNmxlVG9CeXRlcyAoc3RyLCB1bml0cykge1xuICB2YXIgYywgaGksIGxvXG4gIHZhciBieXRlQXJyYXkgPSBbXVxuICBmb3IgKHZhciBpID0gMDsgaSA8IHN0ci5sZW5ndGg7ICsraSkge1xuICAgIGlmICgodW5pdHMgLT0gMikgPCAwKSBicmVha1xuXG4gICAgYyA9IHN0ci5jaGFyQ29kZUF0KGkpXG4gICAgaGkgPSBjID4+IDhcbiAgICBsbyA9IGMgJSAyNTZcbiAgICBieXRlQXJyYXkucHVzaChsbylcbiAgICBieXRlQXJyYXkucHVzaChoaSlcbiAgfVxuXG4gIHJldHVybiBieXRlQXJyYXlcbn1cblxuZnVuY3Rpb24gYmFzZTY0VG9CeXRlcyAoc3RyKSB7XG4gIHJldHVybiBiYXNlNjQudG9CeXRlQXJyYXkoYmFzZTY0Y2xlYW4oc3RyKSlcbn1cblxuZnVuY3Rpb24gYmxpdEJ1ZmZlciAoc3JjLCBkc3QsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyArK2kpIHtcbiAgICBpZiAoKGkgKyBvZmZzZXQgPj0gZHN0Lmxlbmd0aCkgfHwgKGkgPj0gc3JjLmxlbmd0aCkpIGJyZWFrXG4gICAgZHN0W2kgKyBvZmZzZXRdID0gc3JjW2ldXG4gIH1cbiAgcmV0dXJuIGlcbn1cblxuZnVuY3Rpb24gaXNuYW4gKHZhbCkge1xuICByZXR1cm4gdmFsICE9PSB2YWwgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby1zZWxmLWNvbXBhcmVcbn1cbiIsIm1vZHVsZS5leHBvcnRzID0gcmVxdWlyZSgnLi9saWIvY2hhaScpO1xuIiwiLyohXG4gKiBjaGFpXG4gKiBDb3B5cmlnaHQoYykgMjAxMS0yMDE0IEpha2UgTHVlciA8amFrZUBhbG9naWNhbHBhcmFkb3guY29tPlxuICogTUlUIExpY2Vuc2VkXG4gKi9cblxudmFyIHVzZWQgPSBbXVxuICAsIGV4cG9ydHMgPSBtb2R1bGUuZXhwb3J0cyA9IHt9O1xuXG4vKiFcbiAqIENoYWkgdmVyc2lvblxuICovXG5cbmV4cG9ydHMudmVyc2lvbiA9ICczLjUuMCc7XG5cbi8qIVxuICogQXNzZXJ0aW9uIEVycm9yXG4gKi9cblxuZXhwb3J0cy5Bc3NlcnRpb25FcnJvciA9IHJlcXVpcmUoJ2Fzc2VydGlvbi1lcnJvcicpO1xuXG4vKiFcbiAqIFV0aWxzIGZvciBwbHVnaW5zIChub3QgZXhwb3J0ZWQpXG4gKi9cblxudmFyIHV0aWwgPSByZXF1aXJlKCcuL2NoYWkvdXRpbHMnKTtcblxuLyoqXG4gKiAjIC51c2UoZnVuY3Rpb24pXG4gKlxuICogUHJvdmlkZXMgYSB3YXkgdG8gZXh0ZW5kIHRoZSBpbnRlcm5hbHMgb2YgQ2hhaVxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb259XG4gKiBAcmV0dXJucyB7dGhpc30gZm9yIGNoYWluaW5nXG4gKiBAYXBpIHB1YmxpY1xuICovXG5cbmV4cG9ydHMudXNlID0gZnVuY3Rpb24gKGZuKSB7XG4gIGlmICghfnVzZWQuaW5kZXhPZihmbikpIHtcbiAgICBmbih0aGlzLCB1dGlsKTtcbiAgICB1c2VkLnB1c2goZm4pO1xuICB9XG5cbiAgcmV0dXJuIHRoaXM7XG59O1xuXG4vKiFcbiAqIFV0aWxpdHkgRnVuY3Rpb25zXG4gKi9cblxuZXhwb3J0cy51dGlsID0gdXRpbDtcblxuLyohXG4gKiBDb25maWd1cmF0aW9uXG4gKi9cblxudmFyIGNvbmZpZyA9IHJlcXVpcmUoJy4vY2hhaS9jb25maWcnKTtcbmV4cG9ydHMuY29uZmlnID0gY29uZmlnO1xuXG4vKiFcbiAqIFByaW1hcnkgYEFzc2VydGlvbmAgcHJvdG90eXBlXG4gKi9cblxudmFyIGFzc2VydGlvbiA9IHJlcXVpcmUoJy4vY2hhaS9hc3NlcnRpb24nKTtcbmV4cG9ydHMudXNlKGFzc2VydGlvbik7XG5cbi8qIVxuICogQ29yZSBBc3NlcnRpb25zXG4gKi9cblxudmFyIGNvcmUgPSByZXF1aXJlKCcuL2NoYWkvY29yZS9hc3NlcnRpb25zJyk7XG5leHBvcnRzLnVzZShjb3JlKTtcblxuLyohXG4gKiBFeHBlY3QgaW50ZXJmYWNlXG4gKi9cblxudmFyIGV4cGVjdCA9IHJlcXVpcmUoJy4vY2hhaS9pbnRlcmZhY2UvZXhwZWN0Jyk7XG5leHBvcnRzLnVzZShleHBlY3QpO1xuXG4vKiFcbiAqIFNob3VsZCBpbnRlcmZhY2VcbiAqL1xuXG52YXIgc2hvdWxkID0gcmVxdWlyZSgnLi9jaGFpL2ludGVyZmFjZS9zaG91bGQnKTtcbmV4cG9ydHMudXNlKHNob3VsZCk7XG5cbi8qIVxuICogQXNzZXJ0IGludGVyZmFjZVxuICovXG5cbnZhciBhc3NlcnQgPSByZXF1aXJlKCcuL2NoYWkvaW50ZXJmYWNlL2Fzc2VydCcpO1xuZXhwb3J0cy51c2UoYXNzZXJ0KTtcbiIsIi8qIVxuICogY2hhaVxuICogaHR0cDovL2NoYWlqcy5jb21cbiAqIENvcHlyaWdodChjKSAyMDExLTIwMTQgSmFrZSBMdWVyIDxqYWtlQGFsb2dpY2FscGFyYWRveC5jb20+XG4gKiBNSVQgTGljZW5zZWRcbiAqL1xuXG52YXIgY29uZmlnID0gcmVxdWlyZSgnLi9jb25maWcnKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoX2NoYWksIHV0aWwpIHtcbiAgLyohXG4gICAqIE1vZHVsZSBkZXBlbmRlbmNpZXMuXG4gICAqL1xuXG4gIHZhciBBc3NlcnRpb25FcnJvciA9IF9jaGFpLkFzc2VydGlvbkVycm9yXG4gICAgLCBmbGFnID0gdXRpbC5mbGFnO1xuXG4gIC8qIVxuICAgKiBNb2R1bGUgZXhwb3J0LlxuICAgKi9cblxuICBfY2hhaS5Bc3NlcnRpb24gPSBBc3NlcnRpb247XG5cbiAgLyohXG4gICAqIEFzc2VydGlvbiBDb25zdHJ1Y3RvclxuICAgKlxuICAgKiBDcmVhdGVzIG9iamVjdCBmb3IgY2hhaW5pbmcuXG4gICAqXG4gICAqIEBhcGkgcHJpdmF0ZVxuICAgKi9cblxuICBmdW5jdGlvbiBBc3NlcnRpb24gKG9iaiwgbXNnLCBzdGFjaykge1xuICAgIGZsYWcodGhpcywgJ3NzZmknLCBzdGFjayB8fCBhcmd1bWVudHMuY2FsbGVlKTtcbiAgICBmbGFnKHRoaXMsICdvYmplY3QnLCBvYmopO1xuICAgIGZsYWcodGhpcywgJ21lc3NhZ2UnLCBtc2cpO1xuICB9XG5cbiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KEFzc2VydGlvbiwgJ2luY2x1ZGVTdGFjaycsIHtcbiAgICBnZXQ6IGZ1bmN0aW9uKCkge1xuICAgICAgY29uc29sZS53YXJuKCdBc3NlcnRpb24uaW5jbHVkZVN0YWNrIGlzIGRlcHJlY2F0ZWQsIHVzZSBjaGFpLmNvbmZpZy5pbmNsdWRlU3RhY2sgaW5zdGVhZC4nKTtcbiAgICAgIHJldHVybiBjb25maWcuaW5jbHVkZVN0YWNrO1xuICAgIH0sXG4gICAgc2V0OiBmdW5jdGlvbih2YWx1ZSkge1xuICAgICAgY29uc29sZS53YXJuKCdBc3NlcnRpb24uaW5jbHVkZVN0YWNrIGlzIGRlcHJlY2F0ZWQsIHVzZSBjaGFpLmNvbmZpZy5pbmNsdWRlU3RhY2sgaW5zdGVhZC4nKTtcbiAgICAgIGNvbmZpZy5pbmNsdWRlU3RhY2sgPSB2YWx1ZTtcbiAgICB9XG4gIH0pO1xuXG4gIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShBc3NlcnRpb24sICdzaG93RGlmZicsIHtcbiAgICBnZXQ6IGZ1bmN0aW9uKCkge1xuICAgICAgY29uc29sZS53YXJuKCdBc3NlcnRpb24uc2hvd0RpZmYgaXMgZGVwcmVjYXRlZCwgdXNlIGNoYWkuY29uZmlnLnNob3dEaWZmIGluc3RlYWQuJyk7XG4gICAgICByZXR1cm4gY29uZmlnLnNob3dEaWZmO1xuICAgIH0sXG4gICAgc2V0OiBmdW5jdGlvbih2YWx1ZSkge1xuICAgICAgY29uc29sZS53YXJuKCdBc3NlcnRpb24uc2hvd0RpZmYgaXMgZGVwcmVjYXRlZCwgdXNlIGNoYWkuY29uZmlnLnNob3dEaWZmIGluc3RlYWQuJyk7XG4gICAgICBjb25maWcuc2hvd0RpZmYgPSB2YWx1ZTtcbiAgICB9XG4gIH0pO1xuXG4gIEFzc2VydGlvbi5hZGRQcm9wZXJ0eSA9IGZ1bmN0aW9uIChuYW1lLCBmbikge1xuICAgIHV0aWwuYWRkUHJvcGVydHkodGhpcy5wcm90b3R5cGUsIG5hbWUsIGZuKTtcbiAgfTtcblxuICBBc3NlcnRpb24uYWRkTWV0aG9kID0gZnVuY3Rpb24gKG5hbWUsIGZuKSB7XG4gICAgdXRpbC5hZGRNZXRob2QodGhpcy5wcm90b3R5cGUsIG5hbWUsIGZuKTtcbiAgfTtcblxuICBBc3NlcnRpb24uYWRkQ2hhaW5hYmxlTWV0aG9kID0gZnVuY3Rpb24gKG5hbWUsIGZuLCBjaGFpbmluZ0JlaGF2aW9yKSB7XG4gICAgdXRpbC5hZGRDaGFpbmFibGVNZXRob2QodGhpcy5wcm90b3R5cGUsIG5hbWUsIGZuLCBjaGFpbmluZ0JlaGF2aW9yKTtcbiAgfTtcblxuICBBc3NlcnRpb24ub3ZlcndyaXRlUHJvcGVydHkgPSBmdW5jdGlvbiAobmFtZSwgZm4pIHtcbiAgICB1dGlsLm92ZXJ3cml0ZVByb3BlcnR5KHRoaXMucHJvdG90eXBlLCBuYW1lLCBmbik7XG4gIH07XG5cbiAgQXNzZXJ0aW9uLm92ZXJ3cml0ZU1ldGhvZCA9IGZ1bmN0aW9uIChuYW1lLCBmbikge1xuICAgIHV0aWwub3ZlcndyaXRlTWV0aG9kKHRoaXMucHJvdG90eXBlLCBuYW1lLCBmbik7XG4gIH07XG5cbiAgQXNzZXJ0aW9uLm92ZXJ3cml0ZUNoYWluYWJsZU1ldGhvZCA9IGZ1bmN0aW9uIChuYW1lLCBmbiwgY2hhaW5pbmdCZWhhdmlvcikge1xuICAgIHV0aWwub3ZlcndyaXRlQ2hhaW5hYmxlTWV0aG9kKHRoaXMucHJvdG90eXBlLCBuYW1lLCBmbiwgY2hhaW5pbmdCZWhhdmlvcik7XG4gIH07XG5cbiAgLyoqXG4gICAqICMjIyAuYXNzZXJ0KGV4cHJlc3Npb24sIG1lc3NhZ2UsIG5lZ2F0ZU1lc3NhZ2UsIGV4cGVjdGVkLCBhY3R1YWwsIHNob3dEaWZmKVxuICAgKlxuICAgKiBFeGVjdXRlcyBhbiBleHByZXNzaW9uIGFuZCBjaGVjayBleHBlY3RhdGlvbnMuIFRocm93cyBBc3NlcnRpb25FcnJvciBmb3IgcmVwb3J0aW5nIGlmIHRlc3QgZG9lc24ndCBwYXNzLlxuICAgKlxuICAgKiBAbmFtZSBhc3NlcnRcbiAgICogQHBhcmFtIHtQaGlsb3NvcGhpY2FsfSBleHByZXNzaW9uIHRvIGJlIHRlc3RlZFxuICAgKiBAcGFyYW0ge1N0cmluZ3xGdW5jdGlvbn0gbWVzc2FnZSBvciBmdW5jdGlvbiB0aGF0IHJldHVybnMgbWVzc2FnZSB0byBkaXNwbGF5IGlmIGV4cHJlc3Npb24gZmFpbHNcbiAgICogQHBhcmFtIHtTdHJpbmd8RnVuY3Rpb259IG5lZ2F0ZWRNZXNzYWdlIG9yIGZ1bmN0aW9uIHRoYXQgcmV0dXJucyBuZWdhdGVkTWVzc2FnZSB0byBkaXNwbGF5IGlmIG5lZ2F0ZWQgZXhwcmVzc2lvbiBmYWlsc1xuICAgKiBAcGFyYW0ge01peGVkfSBleHBlY3RlZCB2YWx1ZSAocmVtZW1iZXIgdG8gY2hlY2sgZm9yIG5lZ2F0aW9uKVxuICAgKiBAcGFyYW0ge01peGVkfSBhY3R1YWwgKG9wdGlvbmFsKSB3aWxsIGRlZmF1bHQgdG8gYHRoaXMub2JqYFxuICAgKiBAcGFyYW0ge0Jvb2xlYW59IHNob3dEaWZmIChvcHRpb25hbCkgd2hlbiBzZXQgdG8gYHRydWVgLCBhc3NlcnQgd2lsbCBkaXNwbGF5IGEgZGlmZiBpbiBhZGRpdGlvbiB0byB0aGUgbWVzc2FnZSBpZiBleHByZXNzaW9uIGZhaWxzXG4gICAqIEBhcGkgcHJpdmF0ZVxuICAgKi9cblxuICBBc3NlcnRpb24ucHJvdG90eXBlLmFzc2VydCA9IGZ1bmN0aW9uIChleHByLCBtc2csIG5lZ2F0ZU1zZywgZXhwZWN0ZWQsIF9hY3R1YWwsIHNob3dEaWZmKSB7XG4gICAgdmFyIG9rID0gdXRpbC50ZXN0KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgaWYgKHRydWUgIT09IHNob3dEaWZmKSBzaG93RGlmZiA9IGZhbHNlO1xuICAgIGlmICh0cnVlICE9PSBjb25maWcuc2hvd0RpZmYpIHNob3dEaWZmID0gZmFsc2U7XG5cbiAgICBpZiAoIW9rKSB7XG4gICAgICB2YXIgbXNnID0gdXRpbC5nZXRNZXNzYWdlKHRoaXMsIGFyZ3VtZW50cylcbiAgICAgICAgLCBhY3R1YWwgPSB1dGlsLmdldEFjdHVhbCh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgdGhyb3cgbmV3IEFzc2VydGlvbkVycm9yKG1zZywge1xuICAgICAgICAgIGFjdHVhbDogYWN0dWFsXG4gICAgICAgICwgZXhwZWN0ZWQ6IGV4cGVjdGVkXG4gICAgICAgICwgc2hvd0RpZmY6IHNob3dEaWZmXG4gICAgICB9LCAoY29uZmlnLmluY2x1ZGVTdGFjaykgPyB0aGlzLmFzc2VydCA6IGZsYWcodGhpcywgJ3NzZmknKSk7XG4gICAgfVxuICB9O1xuXG4gIC8qIVxuICAgKiAjIyMgLl9vYmpcbiAgICpcbiAgICogUXVpY2sgcmVmZXJlbmNlIHRvIHN0b3JlZCBgYWN0dWFsYCB2YWx1ZSBmb3IgcGx1Z2luIGRldmVsb3BlcnMuXG4gICAqXG4gICAqIEBhcGkgcHJpdmF0ZVxuICAgKi9cblxuICBPYmplY3QuZGVmaW5lUHJvcGVydHkoQXNzZXJ0aW9uLnByb3RvdHlwZSwgJ19vYmonLFxuICAgIHsgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBmbGFnKHRoaXMsICdvYmplY3QnKTtcbiAgICAgIH1cbiAgICAsIHNldDogZnVuY3Rpb24gKHZhbCkge1xuICAgICAgICBmbGFnKHRoaXMsICdvYmplY3QnLCB2YWwpO1xuICAgICAgfVxuICB9KTtcbn07XG4iLCJtb2R1bGUuZXhwb3J0cyA9IHtcblxuICAvKipcbiAgICogIyMjIGNvbmZpZy5pbmNsdWRlU3RhY2tcbiAgICpcbiAgICogVXNlciBjb25maWd1cmFibGUgcHJvcGVydHksIGluZmx1ZW5jZXMgd2hldGhlciBzdGFjayB0cmFjZVxuICAgKiBpcyBpbmNsdWRlZCBpbiBBc3NlcnRpb24gZXJyb3IgbWVzc2FnZS4gRGVmYXVsdCBvZiBmYWxzZVxuICAgKiBzdXBwcmVzc2VzIHN0YWNrIHRyYWNlIGluIHRoZSBlcnJvciBtZXNzYWdlLlxuICAgKlxuICAgKiAgICAgY2hhaS5jb25maWcuaW5jbHVkZVN0YWNrID0gdHJ1ZTsgIC8vIGVuYWJsZSBzdGFjayBvbiBlcnJvclxuICAgKlxuICAgKiBAcGFyYW0ge0Jvb2xlYW59XG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gICBpbmNsdWRlU3RhY2s6IGZhbHNlLFxuXG4gIC8qKlxuICAgKiAjIyMgY29uZmlnLnNob3dEaWZmXG4gICAqXG4gICAqIFVzZXIgY29uZmlndXJhYmxlIHByb3BlcnR5LCBpbmZsdWVuY2VzIHdoZXRoZXIgb3Igbm90XG4gICAqIHRoZSBgc2hvd0RpZmZgIGZsYWcgc2hvdWxkIGJlIGluY2x1ZGVkIGluIHRoZSB0aHJvd25cbiAgICogQXNzZXJ0aW9uRXJyb3JzLiBgZmFsc2VgIHdpbGwgYWx3YXlzIGJlIGBmYWxzZWA7IGB0cnVlYFxuICAgKiB3aWxsIGJlIHRydWUgd2hlbiB0aGUgYXNzZXJ0aW9uIGhhcyByZXF1ZXN0ZWQgYSBkaWZmXG4gICAqIGJlIHNob3duLlxuICAgKlxuICAgKiBAcGFyYW0ge0Jvb2xlYW59XG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIHNob3dEaWZmOiB0cnVlLFxuXG4gIC8qKlxuICAgKiAjIyMgY29uZmlnLnRydW5jYXRlVGhyZXNob2xkXG4gICAqXG4gICAqIFVzZXIgY29uZmlndXJhYmxlIHByb3BlcnR5LCBzZXRzIGxlbmd0aCB0aHJlc2hvbGQgZm9yIGFjdHVhbCBhbmRcbiAgICogZXhwZWN0ZWQgdmFsdWVzIGluIGFzc2VydGlvbiBlcnJvcnMuIElmIHRoaXMgdGhyZXNob2xkIGlzIGV4Y2VlZGVkLCBmb3JcbiAgICogZXhhbXBsZSBmb3IgbGFyZ2UgZGF0YSBzdHJ1Y3R1cmVzLCB0aGUgdmFsdWUgaXMgcmVwbGFjZWQgd2l0aCBzb21ldGhpbmdcbiAgICogbGlrZSBgWyBBcnJheSgzKSBdYCBvciBgeyBPYmplY3QgKHByb3AxLCBwcm9wMikgfWAuXG4gICAqXG4gICAqIFNldCBpdCB0byB6ZXJvIGlmIHlvdSB3YW50IHRvIGRpc2FibGUgdHJ1bmNhdGluZyBhbHRvZ2V0aGVyLlxuICAgKlxuICAgKiBUaGlzIGlzIGVzcGVjaWFsbHkgdXNlcmZ1bCB3aGVuIGRvaW5nIGFzc2VydGlvbnMgb24gYXJyYXlzOiBoYXZpbmcgdGhpc1xuICAgKiBzZXQgdG8gYSByZWFzb25hYmxlIGxhcmdlIHZhbHVlIG1ha2VzIHRoZSBmYWlsdXJlIG1lc3NhZ2VzIHJlYWRpbHlcbiAgICogaW5zcGVjdGFibGUuXG4gICAqXG4gICAqICAgICBjaGFpLmNvbmZpZy50cnVuY2F0ZVRocmVzaG9sZCA9IDA7ICAvLyBkaXNhYmxlIHRydW5jYXRpbmdcbiAgICpcbiAgICogQHBhcmFtIHtOdW1iZXJ9XG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIHRydW5jYXRlVGhyZXNob2xkOiA0MFxuXG59O1xuIiwiLyohXG4gKiBjaGFpXG4gKiBodHRwOi8vY2hhaWpzLmNvbVxuICogQ29weXJpZ2h0KGMpIDIwMTEtMjAxNCBKYWtlIEx1ZXIgPGpha2VAYWxvZ2ljYWxwYXJhZG94LmNvbT5cbiAqIE1JVCBMaWNlbnNlZFxuICovXG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNoYWksIF8pIHtcbiAgdmFyIEFzc2VydGlvbiA9IGNoYWkuQXNzZXJ0aW9uXG4gICAgLCB0b1N0cmluZyA9IE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmdcbiAgICAsIGZsYWcgPSBfLmZsYWc7XG5cbiAgLyoqXG4gICAqICMjIyBMYW5ndWFnZSBDaGFpbnNcbiAgICpcbiAgICogVGhlIGZvbGxvd2luZyBhcmUgcHJvdmlkZWQgYXMgY2hhaW5hYmxlIGdldHRlcnMgdG9cbiAgICogaW1wcm92ZSB0aGUgcmVhZGFiaWxpdHkgb2YgeW91ciBhc3NlcnRpb25zLiBUaGV5XG4gICAqIGRvIG5vdCBwcm92aWRlIHRlc3RpbmcgY2FwYWJpbGl0aWVzIHVubGVzcyB0aGV5XG4gICAqIGhhdmUgYmVlbiBvdmVyd3JpdHRlbiBieSBhIHBsdWdpbi5cbiAgICpcbiAgICogKipDaGFpbnMqKlxuICAgKlxuICAgKiAtIHRvXG4gICAqIC0gYmVcbiAgICogLSBiZWVuXG4gICAqIC0gaXNcbiAgICogLSB0aGF0XG4gICAqIC0gd2hpY2hcbiAgICogLSBhbmRcbiAgICogLSBoYXNcbiAgICogLSBoYXZlXG4gICAqIC0gd2l0aFxuICAgKiAtIGF0XG4gICAqIC0gb2ZcbiAgICogLSBzYW1lXG4gICAqXG4gICAqIEBuYW1lIGxhbmd1YWdlIGNoYWluc1xuICAgKiBAbmFtZXNwYWNlIEJERFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBbICd0bycsICdiZScsICdiZWVuJ1xuICAsICdpcycsICdhbmQnLCAnaGFzJywgJ2hhdmUnXG4gICwgJ3dpdGgnLCAndGhhdCcsICd3aGljaCcsICdhdCdcbiAgLCAnb2YnLCAnc2FtZScgXS5mb3JFYWNoKGZ1bmN0aW9uIChjaGFpbikge1xuICAgIEFzc2VydGlvbi5hZGRQcm9wZXJ0eShjaGFpbiwgZnVuY3Rpb24gKCkge1xuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSk7XG4gIH0pO1xuXG4gIC8qKlxuICAgKiAjIyMgLm5vdFxuICAgKlxuICAgKiBOZWdhdGVzIGFueSBvZiBhc3NlcnRpb25zIGZvbGxvd2luZyBpbiB0aGUgY2hhaW4uXG4gICAqXG4gICAqICAgICBleHBlY3QoZm9vKS50by5ub3QuZXF1YWwoJ2JhcicpO1xuICAgKiAgICAgZXhwZWN0KGdvb2RGbikudG8ubm90LnRocm93KEVycm9yKTtcbiAgICogICAgIGV4cGVjdCh7IGZvbzogJ2JheicgfSkudG8uaGF2ZS5wcm9wZXJ0eSgnZm9vJylcbiAgICogICAgICAgLmFuZC5ub3QuZXF1YWwoJ2JhcicpO1xuICAgKlxuICAgKiBAbmFtZSBub3RcbiAgICogQG5hbWVzcGFjZSBCRERcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgQXNzZXJ0aW9uLmFkZFByb3BlcnR5KCdub3QnLCBmdW5jdGlvbiAoKSB7XG4gICAgZmxhZyh0aGlzLCAnbmVnYXRlJywgdHJ1ZSk7XG4gIH0pO1xuXG4gIC8qKlxuICAgKiAjIyMgLmRlZXBcbiAgICpcbiAgICogU2V0cyB0aGUgYGRlZXBgIGZsYWcsIGxhdGVyIHVzZWQgYnkgdGhlIGBlcXVhbGAgYW5kXG4gICAqIGBwcm9wZXJ0eWAgYXNzZXJ0aW9ucy5cbiAgICpcbiAgICogICAgIGV4cGVjdChmb28pLnRvLmRlZXAuZXF1YWwoeyBiYXI6ICdiYXonIH0pO1xuICAgKiAgICAgZXhwZWN0KHsgZm9vOiB7IGJhcjogeyBiYXo6ICdxdXV4JyB9IH0gfSlcbiAgICogICAgICAgLnRvLmhhdmUuZGVlcC5wcm9wZXJ0eSgnZm9vLmJhci5iYXonLCAncXV1eCcpO1xuICAgKlxuICAgKiBgLmRlZXAucHJvcGVydHlgIHNwZWNpYWwgY2hhcmFjdGVycyBjYW4gYmUgZXNjYXBlZFxuICAgKiBieSBhZGRpbmcgdHdvIHNsYXNoZXMgYmVmb3JlIHRoZSBgLmAgb3IgYFtdYC5cbiAgICpcbiAgICogICAgIHZhciBkZWVwQ3NzID0geyAnLmxpbmsnOiB7ICdbdGFyZ2V0XSc6IDQyIH19O1xuICAgKiAgICAgZXhwZWN0KGRlZXBDc3MpLnRvLmhhdmUuZGVlcC5wcm9wZXJ0eSgnXFxcXC5saW5rLlxcXFxbdGFyZ2V0XFxcXF0nLCA0Mik7XG4gICAqXG4gICAqIEBuYW1lIGRlZXBcbiAgICogQG5hbWVzcGFjZSBCRERcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgQXNzZXJ0aW9uLmFkZFByb3BlcnR5KCdkZWVwJywgZnVuY3Rpb24gKCkge1xuICAgIGZsYWcodGhpcywgJ2RlZXAnLCB0cnVlKTtcbiAgfSk7XG5cbiAgLyoqXG4gICAqICMjIyAuYW55XG4gICAqXG4gICAqIFNldHMgdGhlIGBhbnlgIGZsYWcsIChvcHBvc2l0ZSBvZiB0aGUgYGFsbGAgZmxhZylcbiAgICogbGF0ZXIgdXNlZCBpbiB0aGUgYGtleXNgIGFzc2VydGlvbi5cbiAgICpcbiAgICogICAgIGV4cGVjdChmb28pLnRvLmhhdmUuYW55LmtleXMoJ2JhcicsICdiYXonKTtcbiAgICpcbiAgICogQG5hbWUgYW55XG4gICAqIEBuYW1lc3BhY2UgQkREXG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIEFzc2VydGlvbi5hZGRQcm9wZXJ0eSgnYW55JywgZnVuY3Rpb24gKCkge1xuICAgIGZsYWcodGhpcywgJ2FueScsIHRydWUpO1xuICAgIGZsYWcodGhpcywgJ2FsbCcsIGZhbHNlKVxuICB9KTtcblxuXG4gIC8qKlxuICAgKiAjIyMgLmFsbFxuICAgKlxuICAgKiBTZXRzIHRoZSBgYWxsYCBmbGFnIChvcHBvc2l0ZSBvZiB0aGUgYGFueWAgZmxhZylcbiAgICogbGF0ZXIgdXNlZCBieSB0aGUgYGtleXNgIGFzc2VydGlvbi5cbiAgICpcbiAgICogICAgIGV4cGVjdChmb28pLnRvLmhhdmUuYWxsLmtleXMoJ2JhcicsICdiYXonKTtcbiAgICpcbiAgICogQG5hbWUgYWxsXG4gICAqIEBuYW1lc3BhY2UgQkREXG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIEFzc2VydGlvbi5hZGRQcm9wZXJ0eSgnYWxsJywgZnVuY3Rpb24gKCkge1xuICAgIGZsYWcodGhpcywgJ2FsbCcsIHRydWUpO1xuICAgIGZsYWcodGhpcywgJ2FueScsIGZhbHNlKTtcbiAgfSk7XG5cbiAgLyoqXG4gICAqICMjIyAuYSh0eXBlKVxuICAgKlxuICAgKiBUaGUgYGFgIGFuZCBgYW5gIGFzc2VydGlvbnMgYXJlIGFsaWFzZXMgdGhhdCBjYW4gYmVcbiAgICogdXNlZCBlaXRoZXIgYXMgbGFuZ3VhZ2UgY2hhaW5zIG9yIHRvIGFzc2VydCBhIHZhbHVlJ3NcbiAgICogdHlwZS5cbiAgICpcbiAgICogICAgIC8vIHR5cGVvZlxuICAgKiAgICAgZXhwZWN0KCd0ZXN0JykudG8uYmUuYSgnc3RyaW5nJyk7XG4gICAqICAgICBleHBlY3QoeyBmb286ICdiYXInIH0pLnRvLmJlLmFuKCdvYmplY3QnKTtcbiAgICogICAgIGV4cGVjdChudWxsKS50by5iZS5hKCdudWxsJyk7XG4gICAqICAgICBleHBlY3QodW5kZWZpbmVkKS50by5iZS5hbigndW5kZWZpbmVkJyk7XG4gICAqICAgICBleHBlY3QobmV3IEVycm9yKS50by5iZS5hbignZXJyb3InKTtcbiAgICogICAgIGV4cGVjdChuZXcgUHJvbWlzZSkudG8uYmUuYSgncHJvbWlzZScpO1xuICAgKiAgICAgZXhwZWN0KG5ldyBGbG9hdDMyQXJyYXkoKSkudG8uYmUuYSgnZmxvYXQzMmFycmF5Jyk7XG4gICAqICAgICBleHBlY3QoU3ltYm9sKCkpLnRvLmJlLmEoJ3N5bWJvbCcpO1xuICAgKlxuICAgKiAgICAgLy8gZXM2IG92ZXJyaWRlc1xuICAgKiAgICAgZXhwZWN0KHtbU3ltYm9sLnRvU3RyaW5nVGFnXTooKT0+J2Zvbyd9KS50by5iZS5hKCdmb28nKTtcbiAgICpcbiAgICogICAgIC8vIGxhbmd1YWdlIGNoYWluXG4gICAqICAgICBleHBlY3QoZm9vKS50by5iZS5hbi5pbnN0YW5jZW9mKEZvbyk7XG4gICAqXG4gICAqIEBuYW1lIGFcbiAgICogQGFsaWFzIGFuXG4gICAqIEBwYXJhbSB7U3RyaW5nfSB0eXBlXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlIF9vcHRpb25hbF9cbiAgICogQG5hbWVzcGFjZSBCRERcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgZnVuY3Rpb24gYW4gKHR5cGUsIG1zZykge1xuICAgIGlmIChtc2cpIGZsYWcodGhpcywgJ21lc3NhZ2UnLCBtc2cpO1xuICAgIHR5cGUgPSB0eXBlLnRvTG93ZXJDYXNlKCk7XG4gICAgdmFyIG9iaiA9IGZsYWcodGhpcywgJ29iamVjdCcpXG4gICAgICAsIGFydGljbGUgPSB+WyAnYScsICdlJywgJ2knLCAnbycsICd1JyBdLmluZGV4T2YodHlwZS5jaGFyQXQoMCkpID8gJ2FuICcgOiAnYSAnO1xuXG4gICAgdGhpcy5hc3NlcnQoXG4gICAgICAgIHR5cGUgPT09IF8udHlwZShvYmopXG4gICAgICAsICdleHBlY3RlZCAje3RoaXN9IHRvIGJlICcgKyBhcnRpY2xlICsgdHlwZVxuICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSBub3QgdG8gYmUgJyArIGFydGljbGUgKyB0eXBlXG4gICAgKTtcbiAgfVxuXG4gIEFzc2VydGlvbi5hZGRDaGFpbmFibGVNZXRob2QoJ2FuJywgYW4pO1xuICBBc3NlcnRpb24uYWRkQ2hhaW5hYmxlTWV0aG9kKCdhJywgYW4pO1xuXG4gIC8qKlxuICAgKiAjIyMgLmluY2x1ZGUodmFsdWUpXG4gICAqXG4gICAqIFRoZSBgaW5jbHVkZWAgYW5kIGBjb250YWluYCBhc3NlcnRpb25zIGNhbiBiZSB1c2VkIGFzIGVpdGhlciBwcm9wZXJ0eVxuICAgKiBiYXNlZCBsYW5ndWFnZSBjaGFpbnMgb3IgYXMgbWV0aG9kcyB0byBhc3NlcnQgdGhlIGluY2x1c2lvbiBvZiBhbiBvYmplY3RcbiAgICogaW4gYW4gYXJyYXkgb3IgYSBzdWJzdHJpbmcgaW4gYSBzdHJpbmcuIFdoZW4gdXNlZCBhcyBsYW5ndWFnZSBjaGFpbnMsXG4gICAqIHRoZXkgdG9nZ2xlIHRoZSBgY29udGFpbnNgIGZsYWcgZm9yIHRoZSBga2V5c2AgYXNzZXJ0aW9uLlxuICAgKlxuICAgKiAgICAgZXhwZWN0KFsxLDIsM10pLnRvLmluY2x1ZGUoMik7XG4gICAqICAgICBleHBlY3QoJ2Zvb2JhcicpLnRvLmNvbnRhaW4oJ2ZvbycpO1xuICAgKiAgICAgZXhwZWN0KHsgZm9vOiAnYmFyJywgaGVsbG86ICd1bml2ZXJzZScgfSkudG8uaW5jbHVkZS5rZXlzKCdmb28nKTtcbiAgICpcbiAgICogQG5hbWUgaW5jbHVkZVxuICAgKiBAYWxpYXMgY29udGFpblxuICAgKiBAYWxpYXMgaW5jbHVkZXNcbiAgICogQGFsaWFzIGNvbnRhaW5zXG4gICAqIEBwYXJhbSB7T2JqZWN0fFN0cmluZ3xOdW1iZXJ9IG9ialxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZSBfb3B0aW9uYWxfXG4gICAqIEBuYW1lc3BhY2UgQkREXG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIGZ1bmN0aW9uIGluY2x1ZGVDaGFpbmluZ0JlaGF2aW9yICgpIHtcbiAgICBmbGFnKHRoaXMsICdjb250YWlucycsIHRydWUpO1xuICB9XG5cbiAgZnVuY3Rpb24gaW5jbHVkZSAodmFsLCBtc2cpIHtcbiAgICBfLmV4cGVjdFR5cGVzKHRoaXMsIFsnYXJyYXknLCAnb2JqZWN0JywgJ3N0cmluZyddKTtcblxuICAgIGlmIChtc2cpIGZsYWcodGhpcywgJ21lc3NhZ2UnLCBtc2cpO1xuICAgIHZhciBvYmogPSBmbGFnKHRoaXMsICdvYmplY3QnKTtcbiAgICB2YXIgZXhwZWN0ZWQgPSBmYWxzZTtcblxuICAgIGlmIChfLnR5cGUob2JqKSA9PT0gJ2FycmF5JyAmJiBfLnR5cGUodmFsKSA9PT0gJ29iamVjdCcpIHtcbiAgICAgIGZvciAodmFyIGkgaW4gb2JqKSB7XG4gICAgICAgIGlmIChfLmVxbChvYmpbaV0sIHZhbCkpIHtcbiAgICAgICAgICBleHBlY3RlZCA9IHRydWU7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKF8udHlwZSh2YWwpID09PSAnb2JqZWN0Jykge1xuICAgICAgaWYgKCFmbGFnKHRoaXMsICduZWdhdGUnKSkge1xuICAgICAgICBmb3IgKHZhciBrIGluIHZhbCkgbmV3IEFzc2VydGlvbihvYmopLnByb3BlcnR5KGssIHZhbFtrXSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIHZhciBzdWJzZXQgPSB7fTtcbiAgICAgIGZvciAodmFyIGsgaW4gdmFsKSBzdWJzZXRba10gPSBvYmpba107XG4gICAgICBleHBlY3RlZCA9IF8uZXFsKHN1YnNldCwgdmFsKTtcbiAgICB9IGVsc2Uge1xuICAgICAgZXhwZWN0ZWQgPSAob2JqICE9IHVuZGVmaW5lZCkgJiYgfm9iai5pbmRleE9mKHZhbCk7XG4gICAgfVxuICAgIHRoaXMuYXNzZXJ0KFxuICAgICAgICBleHBlY3RlZFxuICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byBpbmNsdWRlICcgKyBfLmluc3BlY3QodmFsKVxuICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byBub3QgaW5jbHVkZSAnICsgXy5pbnNwZWN0KHZhbCkpO1xuICB9XG5cbiAgQXNzZXJ0aW9uLmFkZENoYWluYWJsZU1ldGhvZCgnaW5jbHVkZScsIGluY2x1ZGUsIGluY2x1ZGVDaGFpbmluZ0JlaGF2aW9yKTtcbiAgQXNzZXJ0aW9uLmFkZENoYWluYWJsZU1ldGhvZCgnY29udGFpbicsIGluY2x1ZGUsIGluY2x1ZGVDaGFpbmluZ0JlaGF2aW9yKTtcbiAgQXNzZXJ0aW9uLmFkZENoYWluYWJsZU1ldGhvZCgnY29udGFpbnMnLCBpbmNsdWRlLCBpbmNsdWRlQ2hhaW5pbmdCZWhhdmlvcik7XG4gIEFzc2VydGlvbi5hZGRDaGFpbmFibGVNZXRob2QoJ2luY2x1ZGVzJywgaW5jbHVkZSwgaW5jbHVkZUNoYWluaW5nQmVoYXZpb3IpO1xuXG4gIC8qKlxuICAgKiAjIyMgLm9rXG4gICAqXG4gICAqIEFzc2VydHMgdGhhdCB0aGUgdGFyZ2V0IGlzIHRydXRoeS5cbiAgICpcbiAgICogICAgIGV4cGVjdCgnZXZlcnl0aGluZycpLnRvLmJlLm9rO1xuICAgKiAgICAgZXhwZWN0KDEpLnRvLmJlLm9rO1xuICAgKiAgICAgZXhwZWN0KGZhbHNlKS50by5ub3QuYmUub2s7XG4gICAqICAgICBleHBlY3QodW5kZWZpbmVkKS50by5ub3QuYmUub2s7XG4gICAqICAgICBleHBlY3QobnVsbCkudG8ubm90LmJlLm9rO1xuICAgKlxuICAgKiBAbmFtZSBva1xuICAgKiBAbmFtZXNwYWNlIEJERFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBBc3NlcnRpb24uYWRkUHJvcGVydHkoJ29rJywgZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuYXNzZXJ0KFxuICAgICAgICBmbGFnKHRoaXMsICdvYmplY3QnKVxuICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byBiZSB0cnV0aHknXG4gICAgICAsICdleHBlY3RlZCAje3RoaXN9IHRvIGJlIGZhbHN5Jyk7XG4gIH0pO1xuXG4gIC8qKlxuICAgKiAjIyMgLnRydWVcbiAgICpcbiAgICogQXNzZXJ0cyB0aGF0IHRoZSB0YXJnZXQgaXMgYHRydWVgLlxuICAgKlxuICAgKiAgICAgZXhwZWN0KHRydWUpLnRvLmJlLnRydWU7XG4gICAqICAgICBleHBlY3QoMSkudG8ubm90LmJlLnRydWU7XG4gICAqXG4gICAqIEBuYW1lIHRydWVcbiAgICogQG5hbWVzcGFjZSBCRERcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgQXNzZXJ0aW9uLmFkZFByb3BlcnR5KCd0cnVlJywgZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuYXNzZXJ0KFxuICAgICAgICB0cnVlID09PSBmbGFnKHRoaXMsICdvYmplY3QnKVxuICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byBiZSB0cnVlJ1xuICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byBiZSBmYWxzZSdcbiAgICAgICwgdGhpcy5uZWdhdGUgPyBmYWxzZSA6IHRydWVcbiAgICApO1xuICB9KTtcblxuICAvKipcbiAgICogIyMjIC5mYWxzZVxuICAgKlxuICAgKiBBc3NlcnRzIHRoYXQgdGhlIHRhcmdldCBpcyBgZmFsc2VgLlxuICAgKlxuICAgKiAgICAgZXhwZWN0KGZhbHNlKS50by5iZS5mYWxzZTtcbiAgICogICAgIGV4cGVjdCgwKS50by5ub3QuYmUuZmFsc2U7XG4gICAqXG4gICAqIEBuYW1lIGZhbHNlXG4gICAqIEBuYW1lc3BhY2UgQkREXG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIEFzc2VydGlvbi5hZGRQcm9wZXJ0eSgnZmFsc2UnLCBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5hc3NlcnQoXG4gICAgICAgIGZhbHNlID09PSBmbGFnKHRoaXMsICdvYmplY3QnKVxuICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byBiZSBmYWxzZSdcbiAgICAgICwgJ2V4cGVjdGVkICN7dGhpc30gdG8gYmUgdHJ1ZSdcbiAgICAgICwgdGhpcy5uZWdhdGUgPyB0cnVlIDogZmFsc2VcbiAgICApO1xuICB9KTtcblxuICAvKipcbiAgICogIyMjIC5udWxsXG4gICAqXG4gICAqIEFzc2VydHMgdGhhdCB0aGUgdGFyZ2V0IGlzIGBudWxsYC5cbiAgICpcbiAgICogICAgIGV4cGVjdChudWxsKS50by5iZS5udWxsO1xuICAgKiAgICAgZXhwZWN0KHVuZGVmaW5lZCkudG8ubm90LmJlLm51bGw7XG4gICAqXG4gICAqIEBuYW1lIG51bGxcbiAgICogQG5hbWVzcGFjZSBCRERcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgQXNzZXJ0aW9uLmFkZFByb3BlcnR5KCdudWxsJywgZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuYXNzZXJ0KFxuICAgICAgICBudWxsID09PSBmbGFnKHRoaXMsICdvYmplY3QnKVxuICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byBiZSBudWxsJ1xuICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSBub3QgdG8gYmUgbnVsbCdcbiAgICApO1xuICB9KTtcblxuICAvKipcbiAgICogIyMjIC51bmRlZmluZWRcbiAgICpcbiAgICogQXNzZXJ0cyB0aGF0IHRoZSB0YXJnZXQgaXMgYHVuZGVmaW5lZGAuXG4gICAqXG4gICAqICAgICBleHBlY3QodW5kZWZpbmVkKS50by5iZS51bmRlZmluZWQ7XG4gICAqICAgICBleHBlY3QobnVsbCkudG8ubm90LmJlLnVuZGVmaW5lZDtcbiAgICpcbiAgICogQG5hbWUgdW5kZWZpbmVkXG4gICAqIEBuYW1lc3BhY2UgQkREXG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIEFzc2VydGlvbi5hZGRQcm9wZXJ0eSgndW5kZWZpbmVkJywgZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuYXNzZXJ0KFxuICAgICAgICB1bmRlZmluZWQgPT09IGZsYWcodGhpcywgJ29iamVjdCcpXG4gICAgICAsICdleHBlY3RlZCAje3RoaXN9IHRvIGJlIHVuZGVmaW5lZCdcbiAgICAgICwgJ2V4cGVjdGVkICN7dGhpc30gbm90IHRvIGJlIHVuZGVmaW5lZCdcbiAgICApO1xuICB9KTtcblxuICAvKipcbiAgICogIyMjIC5OYU5cbiAgICogQXNzZXJ0cyB0aGF0IHRoZSB0YXJnZXQgaXMgYE5hTmAuXG4gICAqXG4gICAqICAgICBleHBlY3QoJ2ZvbycpLnRvLmJlLk5hTjtcbiAgICogICAgIGV4cGVjdCg0KS5ub3QudG8uYmUuTmFOO1xuICAgKlxuICAgKiBAbmFtZSBOYU5cbiAgICogQG5hbWVzcGFjZSBCRERcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgQXNzZXJ0aW9uLmFkZFByb3BlcnR5KCdOYU4nLCBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5hc3NlcnQoXG4gICAgICAgIGlzTmFOKGZsYWcodGhpcywgJ29iamVjdCcpKVxuICAgICAgICAsICdleHBlY3RlZCAje3RoaXN9IHRvIGJlIE5hTidcbiAgICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSBub3QgdG8gYmUgTmFOJ1xuICAgICk7XG4gIH0pO1xuXG4gIC8qKlxuICAgKiAjIyMgLmV4aXN0XG4gICAqXG4gICAqIEFzc2VydHMgdGhhdCB0aGUgdGFyZ2V0IGlzIG5laXRoZXIgYG51bGxgIG5vciBgdW5kZWZpbmVkYC5cbiAgICpcbiAgICogICAgIHZhciBmb28gPSAnaGknXG4gICAqICAgICAgICwgYmFyID0gbnVsbFxuICAgKiAgICAgICAsIGJhejtcbiAgICpcbiAgICogICAgIGV4cGVjdChmb28pLnRvLmV4aXN0O1xuICAgKiAgICAgZXhwZWN0KGJhcikudG8ubm90LmV4aXN0O1xuICAgKiAgICAgZXhwZWN0KGJheikudG8ubm90LmV4aXN0O1xuICAgKlxuICAgKiBAbmFtZSBleGlzdFxuICAgKiBAbmFtZXNwYWNlIEJERFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBBc3NlcnRpb24uYWRkUHJvcGVydHkoJ2V4aXN0JywgZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuYXNzZXJ0KFxuICAgICAgICBudWxsICE9IGZsYWcodGhpcywgJ29iamVjdCcpXG4gICAgICAsICdleHBlY3RlZCAje3RoaXN9IHRvIGV4aXN0J1xuICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byBub3QgZXhpc3QnXG4gICAgKTtcbiAgfSk7XG5cblxuICAvKipcbiAgICogIyMjIC5lbXB0eVxuICAgKlxuICAgKiBBc3NlcnRzIHRoYXQgdGhlIHRhcmdldCdzIGxlbmd0aCBpcyBgMGAuIEZvciBhcnJheXMgYW5kIHN0cmluZ3MsIGl0IGNoZWNrc1xuICAgKiB0aGUgYGxlbmd0aGAgcHJvcGVydHkuIEZvciBvYmplY3RzLCBpdCBnZXRzIHRoZSBjb3VudCBvZlxuICAgKiBlbnVtZXJhYmxlIGtleXMuXG4gICAqXG4gICAqICAgICBleHBlY3QoW10pLnRvLmJlLmVtcHR5O1xuICAgKiAgICAgZXhwZWN0KCcnKS50by5iZS5lbXB0eTtcbiAgICogICAgIGV4cGVjdCh7fSkudG8uYmUuZW1wdHk7XG4gICAqXG4gICAqIEBuYW1lIGVtcHR5XG4gICAqIEBuYW1lc3BhY2UgQkREXG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIEFzc2VydGlvbi5hZGRQcm9wZXJ0eSgnZW1wdHknLCBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIG9iaiA9IGZsYWcodGhpcywgJ29iamVjdCcpXG4gICAgICAsIGV4cGVjdGVkID0gb2JqO1xuXG4gICAgaWYgKEFycmF5LmlzQXJyYXkob2JqKSB8fCAnc3RyaW5nJyA9PT0gdHlwZW9mIG9iamVjdCkge1xuICAgICAgZXhwZWN0ZWQgPSBvYmoubGVuZ3RoO1xuICAgIH0gZWxzZSBpZiAodHlwZW9mIG9iaiA9PT0gJ29iamVjdCcpIHtcbiAgICAgIGV4cGVjdGVkID0gT2JqZWN0LmtleXMob2JqKS5sZW5ndGg7XG4gICAgfVxuXG4gICAgdGhpcy5hc3NlcnQoXG4gICAgICAgICFleHBlY3RlZFxuICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byBiZSBlbXB0eSdcbiAgICAgICwgJ2V4cGVjdGVkICN7dGhpc30gbm90IHRvIGJlIGVtcHR5J1xuICAgICk7XG4gIH0pO1xuXG4gIC8qKlxuICAgKiAjIyMgLmFyZ3VtZW50c1xuICAgKlxuICAgKiBBc3NlcnRzIHRoYXQgdGhlIHRhcmdldCBpcyBhbiBhcmd1bWVudHMgb2JqZWN0LlxuICAgKlxuICAgKiAgICAgZnVuY3Rpb24gdGVzdCAoKSB7XG4gICAqICAgICAgIGV4cGVjdChhcmd1bWVudHMpLnRvLmJlLmFyZ3VtZW50cztcbiAgICogICAgIH1cbiAgICpcbiAgICogQG5hbWUgYXJndW1lbnRzXG4gICAqIEBhbGlhcyBBcmd1bWVudHNcbiAgICogQG5hbWVzcGFjZSBCRERcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgZnVuY3Rpb24gY2hlY2tBcmd1bWVudHMgKCkge1xuICAgIHZhciBvYmogPSBmbGFnKHRoaXMsICdvYmplY3QnKVxuICAgICAgLCB0eXBlID0gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKG9iaik7XG4gICAgdGhpcy5hc3NlcnQoXG4gICAgICAgICdbb2JqZWN0IEFyZ3VtZW50c10nID09PSB0eXBlXG4gICAgICAsICdleHBlY3RlZCAje3RoaXN9IHRvIGJlIGFyZ3VtZW50cyBidXQgZ290ICcgKyB0eXBlXG4gICAgICAsICdleHBlY3RlZCAje3RoaXN9IHRvIG5vdCBiZSBhcmd1bWVudHMnXG4gICAgKTtcbiAgfVxuXG4gIEFzc2VydGlvbi5hZGRQcm9wZXJ0eSgnYXJndW1lbnRzJywgY2hlY2tBcmd1bWVudHMpO1xuICBBc3NlcnRpb24uYWRkUHJvcGVydHkoJ0FyZ3VtZW50cycsIGNoZWNrQXJndW1lbnRzKTtcblxuICAvKipcbiAgICogIyMjIC5lcXVhbCh2YWx1ZSlcbiAgICpcbiAgICogQXNzZXJ0cyB0aGF0IHRoZSB0YXJnZXQgaXMgc3RyaWN0bHkgZXF1YWwgKGA9PT1gKSB0byBgdmFsdWVgLlxuICAgKiBBbHRlcm5hdGVseSwgaWYgdGhlIGBkZWVwYCBmbGFnIGlzIHNldCwgYXNzZXJ0cyB0aGF0XG4gICAqIHRoZSB0YXJnZXQgaXMgZGVlcGx5IGVxdWFsIHRvIGB2YWx1ZWAuXG4gICAqXG4gICAqICAgICBleHBlY3QoJ2hlbGxvJykudG8uZXF1YWwoJ2hlbGxvJyk7XG4gICAqICAgICBleHBlY3QoNDIpLnRvLmVxdWFsKDQyKTtcbiAgICogICAgIGV4cGVjdCgxKS50by5ub3QuZXF1YWwodHJ1ZSk7XG4gICAqICAgICBleHBlY3QoeyBmb286ICdiYXInIH0pLnRvLm5vdC5lcXVhbCh7IGZvbzogJ2JhcicgfSk7XG4gICAqICAgICBleHBlY3QoeyBmb286ICdiYXInIH0pLnRvLmRlZXAuZXF1YWwoeyBmb286ICdiYXInIH0pO1xuICAgKlxuICAgKiBAbmFtZSBlcXVhbFxuICAgKiBAYWxpYXMgZXF1YWxzXG4gICAqIEBhbGlhcyBlcVxuICAgKiBAYWxpYXMgZGVlcC5lcXVhbFxuICAgKiBAcGFyYW0ge01peGVkfSB2YWx1ZVxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZSBfb3B0aW9uYWxfXG4gICAqIEBuYW1lc3BhY2UgQkREXG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIGZ1bmN0aW9uIGFzc2VydEVxdWFsICh2YWwsIG1zZykge1xuICAgIGlmIChtc2cpIGZsYWcodGhpcywgJ21lc3NhZ2UnLCBtc2cpO1xuICAgIHZhciBvYmogPSBmbGFnKHRoaXMsICdvYmplY3QnKTtcbiAgICBpZiAoZmxhZyh0aGlzLCAnZGVlcCcpKSB7XG4gICAgICByZXR1cm4gdGhpcy5lcWwodmFsKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5hc3NlcnQoXG4gICAgICAgICAgdmFsID09PSBvYmpcbiAgICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byBlcXVhbCAje2V4cH0nXG4gICAgICAgICwgJ2V4cGVjdGVkICN7dGhpc30gdG8gbm90IGVxdWFsICN7ZXhwfSdcbiAgICAgICAgLCB2YWxcbiAgICAgICAgLCB0aGlzLl9vYmpcbiAgICAgICAgLCB0cnVlXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIEFzc2VydGlvbi5hZGRNZXRob2QoJ2VxdWFsJywgYXNzZXJ0RXF1YWwpO1xuICBBc3NlcnRpb24uYWRkTWV0aG9kKCdlcXVhbHMnLCBhc3NlcnRFcXVhbCk7XG4gIEFzc2VydGlvbi5hZGRNZXRob2QoJ2VxJywgYXNzZXJ0RXF1YWwpO1xuXG4gIC8qKlxuICAgKiAjIyMgLmVxbCh2YWx1ZSlcbiAgICpcbiAgICogQXNzZXJ0cyB0aGF0IHRoZSB0YXJnZXQgaXMgZGVlcGx5IGVxdWFsIHRvIGB2YWx1ZWAuXG4gICAqXG4gICAqICAgICBleHBlY3QoeyBmb286ICdiYXInIH0pLnRvLmVxbCh7IGZvbzogJ2JhcicgfSk7XG4gICAqICAgICBleHBlY3QoWyAxLCAyLCAzIF0pLnRvLmVxbChbIDEsIDIsIDMgXSk7XG4gICAqXG4gICAqIEBuYW1lIGVxbFxuICAgKiBAYWxpYXMgZXFsc1xuICAgKiBAcGFyYW0ge01peGVkfSB2YWx1ZVxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZSBfb3B0aW9uYWxfXG4gICAqIEBuYW1lc3BhY2UgQkREXG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIGZ1bmN0aW9uIGFzc2VydEVxbChvYmosIG1zZykge1xuICAgIGlmIChtc2cpIGZsYWcodGhpcywgJ21lc3NhZ2UnLCBtc2cpO1xuICAgIHRoaXMuYXNzZXJ0KFxuICAgICAgICBfLmVxbChvYmosIGZsYWcodGhpcywgJ29iamVjdCcpKVxuICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byBkZWVwbHkgZXF1YWwgI3tleHB9J1xuICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byBub3QgZGVlcGx5IGVxdWFsICN7ZXhwfSdcbiAgICAgICwgb2JqXG4gICAgICAsIHRoaXMuX29ialxuICAgICAgLCB0cnVlXG4gICAgKTtcbiAgfVxuXG4gIEFzc2VydGlvbi5hZGRNZXRob2QoJ2VxbCcsIGFzc2VydEVxbCk7XG4gIEFzc2VydGlvbi5hZGRNZXRob2QoJ2VxbHMnLCBhc3NlcnRFcWwpO1xuXG4gIC8qKlxuICAgKiAjIyMgLmFib3ZlKHZhbHVlKVxuICAgKlxuICAgKiBBc3NlcnRzIHRoYXQgdGhlIHRhcmdldCBpcyBncmVhdGVyIHRoYW4gYHZhbHVlYC5cbiAgICpcbiAgICogICAgIGV4cGVjdCgxMCkudG8uYmUuYWJvdmUoNSk7XG4gICAqXG4gICAqIENhbiBhbHNvIGJlIHVzZWQgaW4gY29uanVuY3Rpb24gd2l0aCBgbGVuZ3RoYCB0b1xuICAgKiBhc3NlcnQgYSBtaW5pbXVtIGxlbmd0aC4gVGhlIGJlbmVmaXQgYmVpbmcgYVxuICAgKiBtb3JlIGluZm9ybWF0aXZlIGVycm9yIG1lc3NhZ2UgdGhhbiBpZiB0aGUgbGVuZ3RoXG4gICAqIHdhcyBzdXBwbGllZCBkaXJlY3RseS5cbiAgICpcbiAgICogICAgIGV4cGVjdCgnZm9vJykudG8uaGF2ZS5sZW5ndGguYWJvdmUoMik7XG4gICAqICAgICBleHBlY3QoWyAxLCAyLCAzIF0pLnRvLmhhdmUubGVuZ3RoLmFib3ZlKDIpO1xuICAgKlxuICAgKiBAbmFtZSBhYm92ZVxuICAgKiBAYWxpYXMgZ3RcbiAgICogQGFsaWFzIGdyZWF0ZXJUaGFuXG4gICAqIEBwYXJhbSB7TnVtYmVyfSB2YWx1ZVxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZSBfb3B0aW9uYWxfXG4gICAqIEBuYW1lc3BhY2UgQkREXG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIGZ1bmN0aW9uIGFzc2VydEFib3ZlIChuLCBtc2cpIHtcbiAgICBpZiAobXNnKSBmbGFnKHRoaXMsICdtZXNzYWdlJywgbXNnKTtcbiAgICB2YXIgb2JqID0gZmxhZyh0aGlzLCAnb2JqZWN0Jyk7XG4gICAgaWYgKGZsYWcodGhpcywgJ2RvTGVuZ3RoJykpIHtcbiAgICAgIG5ldyBBc3NlcnRpb24ob2JqLCBtc2cpLnRvLmhhdmUucHJvcGVydHkoJ2xlbmd0aCcpO1xuICAgICAgdmFyIGxlbiA9IG9iai5sZW5ndGg7XG4gICAgICB0aGlzLmFzc2VydChcbiAgICAgICAgICBsZW4gPiBuXG4gICAgICAgICwgJ2V4cGVjdGVkICN7dGhpc30gdG8gaGF2ZSBhIGxlbmd0aCBhYm92ZSAje2V4cH0gYnV0IGdvdCAje2FjdH0nXG4gICAgICAgICwgJ2V4cGVjdGVkICN7dGhpc30gdG8gbm90IGhhdmUgYSBsZW5ndGggYWJvdmUgI3tleHB9J1xuICAgICAgICAsIG5cbiAgICAgICAgLCBsZW5cbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuYXNzZXJ0KFxuICAgICAgICAgIG9iaiA+IG5cbiAgICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byBiZSBhYm92ZSAnICsgblxuICAgICAgICAsICdleHBlY3RlZCAje3RoaXN9IHRvIGJlIGF0IG1vc3QgJyArIG5cbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgQXNzZXJ0aW9uLmFkZE1ldGhvZCgnYWJvdmUnLCBhc3NlcnRBYm92ZSk7XG4gIEFzc2VydGlvbi5hZGRNZXRob2QoJ2d0JywgYXNzZXJ0QWJvdmUpO1xuICBBc3NlcnRpb24uYWRkTWV0aG9kKCdncmVhdGVyVGhhbicsIGFzc2VydEFib3ZlKTtcblxuICAvKipcbiAgICogIyMjIC5sZWFzdCh2YWx1ZSlcbiAgICpcbiAgICogQXNzZXJ0cyB0aGF0IHRoZSB0YXJnZXQgaXMgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvIGB2YWx1ZWAuXG4gICAqXG4gICAqICAgICBleHBlY3QoMTApLnRvLmJlLmF0LmxlYXN0KDEwKTtcbiAgICpcbiAgICogQ2FuIGFsc28gYmUgdXNlZCBpbiBjb25qdW5jdGlvbiB3aXRoIGBsZW5ndGhgIHRvXG4gICAqIGFzc2VydCBhIG1pbmltdW0gbGVuZ3RoLiBUaGUgYmVuZWZpdCBiZWluZyBhXG4gICAqIG1vcmUgaW5mb3JtYXRpdmUgZXJyb3IgbWVzc2FnZSB0aGFuIGlmIHRoZSBsZW5ndGhcbiAgICogd2FzIHN1cHBsaWVkIGRpcmVjdGx5LlxuICAgKlxuICAgKiAgICAgZXhwZWN0KCdmb28nKS50by5oYXZlLmxlbmd0aC5vZi5hdC5sZWFzdCgyKTtcbiAgICogICAgIGV4cGVjdChbIDEsIDIsIDMgXSkudG8uaGF2ZS5sZW5ndGgub2YuYXQubGVhc3QoMyk7XG4gICAqXG4gICAqIEBuYW1lIGxlYXN0XG4gICAqIEBhbGlhcyBndGVcbiAgICogQHBhcmFtIHtOdW1iZXJ9IHZhbHVlXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlIF9vcHRpb25hbF9cbiAgICogQG5hbWVzcGFjZSBCRERcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgZnVuY3Rpb24gYXNzZXJ0TGVhc3QgKG4sIG1zZykge1xuICAgIGlmIChtc2cpIGZsYWcodGhpcywgJ21lc3NhZ2UnLCBtc2cpO1xuICAgIHZhciBvYmogPSBmbGFnKHRoaXMsICdvYmplY3QnKTtcbiAgICBpZiAoZmxhZyh0aGlzLCAnZG9MZW5ndGgnKSkge1xuICAgICAgbmV3IEFzc2VydGlvbihvYmosIG1zZykudG8uaGF2ZS5wcm9wZXJ0eSgnbGVuZ3RoJyk7XG4gICAgICB2YXIgbGVuID0gb2JqLmxlbmd0aDtcbiAgICAgIHRoaXMuYXNzZXJ0KFxuICAgICAgICAgIGxlbiA+PSBuXG4gICAgICAgICwgJ2V4cGVjdGVkICN7dGhpc30gdG8gaGF2ZSBhIGxlbmd0aCBhdCBsZWFzdCAje2V4cH0gYnV0IGdvdCAje2FjdH0nXG4gICAgICAgICwgJ2V4cGVjdGVkICN7dGhpc30gdG8gaGF2ZSBhIGxlbmd0aCBiZWxvdyAje2V4cH0nXG4gICAgICAgICwgblxuICAgICAgICAsIGxlblxuICAgICAgKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5hc3NlcnQoXG4gICAgICAgICAgb2JqID49IG5cbiAgICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byBiZSBhdCBsZWFzdCAnICsgblxuICAgICAgICAsICdleHBlY3RlZCAje3RoaXN9IHRvIGJlIGJlbG93ICcgKyBuXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIEFzc2VydGlvbi5hZGRNZXRob2QoJ2xlYXN0JywgYXNzZXJ0TGVhc3QpO1xuICBBc3NlcnRpb24uYWRkTWV0aG9kKCdndGUnLCBhc3NlcnRMZWFzdCk7XG5cbiAgLyoqXG4gICAqICMjIyAuYmVsb3codmFsdWUpXG4gICAqXG4gICAqIEFzc2VydHMgdGhhdCB0aGUgdGFyZ2V0IGlzIGxlc3MgdGhhbiBgdmFsdWVgLlxuICAgKlxuICAgKiAgICAgZXhwZWN0KDUpLnRvLmJlLmJlbG93KDEwKTtcbiAgICpcbiAgICogQ2FuIGFsc28gYmUgdXNlZCBpbiBjb25qdW5jdGlvbiB3aXRoIGBsZW5ndGhgIHRvXG4gICAqIGFzc2VydCBhIG1heGltdW0gbGVuZ3RoLiBUaGUgYmVuZWZpdCBiZWluZyBhXG4gICAqIG1vcmUgaW5mb3JtYXRpdmUgZXJyb3IgbWVzc2FnZSB0aGFuIGlmIHRoZSBsZW5ndGhcbiAgICogd2FzIHN1cHBsaWVkIGRpcmVjdGx5LlxuICAgKlxuICAgKiAgICAgZXhwZWN0KCdmb28nKS50by5oYXZlLmxlbmd0aC5iZWxvdyg0KTtcbiAgICogICAgIGV4cGVjdChbIDEsIDIsIDMgXSkudG8uaGF2ZS5sZW5ndGguYmVsb3coNCk7XG4gICAqXG4gICAqIEBuYW1lIGJlbG93XG4gICAqIEBhbGlhcyBsdFxuICAgKiBAYWxpYXMgbGVzc1RoYW5cbiAgICogQHBhcmFtIHtOdW1iZXJ9IHZhbHVlXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlIF9vcHRpb25hbF9cbiAgICogQG5hbWVzcGFjZSBCRERcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgZnVuY3Rpb24gYXNzZXJ0QmVsb3cgKG4sIG1zZykge1xuICAgIGlmIChtc2cpIGZsYWcodGhpcywgJ21lc3NhZ2UnLCBtc2cpO1xuICAgIHZhciBvYmogPSBmbGFnKHRoaXMsICdvYmplY3QnKTtcbiAgICBpZiAoZmxhZyh0aGlzLCAnZG9MZW5ndGgnKSkge1xuICAgICAgbmV3IEFzc2VydGlvbihvYmosIG1zZykudG8uaGF2ZS5wcm9wZXJ0eSgnbGVuZ3RoJyk7XG4gICAgICB2YXIgbGVuID0gb2JqLmxlbmd0aDtcbiAgICAgIHRoaXMuYXNzZXJ0KFxuICAgICAgICAgIGxlbiA8IG5cbiAgICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byBoYXZlIGEgbGVuZ3RoIGJlbG93ICN7ZXhwfSBidXQgZ290ICN7YWN0fSdcbiAgICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byBub3QgaGF2ZSBhIGxlbmd0aCBiZWxvdyAje2V4cH0nXG4gICAgICAgICwgblxuICAgICAgICAsIGxlblxuICAgICAgKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5hc3NlcnQoXG4gICAgICAgICAgb2JqIDwgblxuICAgICAgICAsICdleHBlY3RlZCAje3RoaXN9IHRvIGJlIGJlbG93ICcgKyBuXG4gICAgICAgICwgJ2V4cGVjdGVkICN7dGhpc30gdG8gYmUgYXQgbGVhc3QgJyArIG5cbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgQXNzZXJ0aW9uLmFkZE1ldGhvZCgnYmVsb3cnLCBhc3NlcnRCZWxvdyk7XG4gIEFzc2VydGlvbi5hZGRNZXRob2QoJ2x0JywgYXNzZXJ0QmVsb3cpO1xuICBBc3NlcnRpb24uYWRkTWV0aG9kKCdsZXNzVGhhbicsIGFzc2VydEJlbG93KTtcblxuICAvKipcbiAgICogIyMjIC5tb3N0KHZhbHVlKVxuICAgKlxuICAgKiBBc3NlcnRzIHRoYXQgdGhlIHRhcmdldCBpcyBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gYHZhbHVlYC5cbiAgICpcbiAgICogICAgIGV4cGVjdCg1KS50by5iZS5hdC5tb3N0KDUpO1xuICAgKlxuICAgKiBDYW4gYWxzbyBiZSB1c2VkIGluIGNvbmp1bmN0aW9uIHdpdGggYGxlbmd0aGAgdG9cbiAgICogYXNzZXJ0IGEgbWF4aW11bSBsZW5ndGguIFRoZSBiZW5lZml0IGJlaW5nIGFcbiAgICogbW9yZSBpbmZvcm1hdGl2ZSBlcnJvciBtZXNzYWdlIHRoYW4gaWYgdGhlIGxlbmd0aFxuICAgKiB3YXMgc3VwcGxpZWQgZGlyZWN0bHkuXG4gICAqXG4gICAqICAgICBleHBlY3QoJ2ZvbycpLnRvLmhhdmUubGVuZ3RoLm9mLmF0Lm1vc3QoNCk7XG4gICAqICAgICBleHBlY3QoWyAxLCAyLCAzIF0pLnRvLmhhdmUubGVuZ3RoLm9mLmF0Lm1vc3QoMyk7XG4gICAqXG4gICAqIEBuYW1lIG1vc3RcbiAgICogQGFsaWFzIGx0ZVxuICAgKiBAcGFyYW0ge051bWJlcn0gdmFsdWVcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2UgX29wdGlvbmFsX1xuICAgKiBAbmFtZXNwYWNlIEJERFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBmdW5jdGlvbiBhc3NlcnRNb3N0IChuLCBtc2cpIHtcbiAgICBpZiAobXNnKSBmbGFnKHRoaXMsICdtZXNzYWdlJywgbXNnKTtcbiAgICB2YXIgb2JqID0gZmxhZyh0aGlzLCAnb2JqZWN0Jyk7XG4gICAgaWYgKGZsYWcodGhpcywgJ2RvTGVuZ3RoJykpIHtcbiAgICAgIG5ldyBBc3NlcnRpb24ob2JqLCBtc2cpLnRvLmhhdmUucHJvcGVydHkoJ2xlbmd0aCcpO1xuICAgICAgdmFyIGxlbiA9IG9iai5sZW5ndGg7XG4gICAgICB0aGlzLmFzc2VydChcbiAgICAgICAgICBsZW4gPD0gblxuICAgICAgICAsICdleHBlY3RlZCAje3RoaXN9IHRvIGhhdmUgYSBsZW5ndGggYXQgbW9zdCAje2V4cH0gYnV0IGdvdCAje2FjdH0nXG4gICAgICAgICwgJ2V4cGVjdGVkICN7dGhpc30gdG8gaGF2ZSBhIGxlbmd0aCBhYm92ZSAje2V4cH0nXG4gICAgICAgICwgblxuICAgICAgICAsIGxlblxuICAgICAgKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5hc3NlcnQoXG4gICAgICAgICAgb2JqIDw9IG5cbiAgICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byBiZSBhdCBtb3N0ICcgKyBuXG4gICAgICAgICwgJ2V4cGVjdGVkICN7dGhpc30gdG8gYmUgYWJvdmUgJyArIG5cbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgQXNzZXJ0aW9uLmFkZE1ldGhvZCgnbW9zdCcsIGFzc2VydE1vc3QpO1xuICBBc3NlcnRpb24uYWRkTWV0aG9kKCdsdGUnLCBhc3NlcnRNb3N0KTtcblxuICAvKipcbiAgICogIyMjIC53aXRoaW4oc3RhcnQsIGZpbmlzaClcbiAgICpcbiAgICogQXNzZXJ0cyB0aGF0IHRoZSB0YXJnZXQgaXMgd2l0aGluIGEgcmFuZ2UuXG4gICAqXG4gICAqICAgICBleHBlY3QoNykudG8uYmUud2l0aGluKDUsMTApO1xuICAgKlxuICAgKiBDYW4gYWxzbyBiZSB1c2VkIGluIGNvbmp1bmN0aW9uIHdpdGggYGxlbmd0aGAgdG9cbiAgICogYXNzZXJ0IGEgbGVuZ3RoIHJhbmdlLiBUaGUgYmVuZWZpdCBiZWluZyBhXG4gICAqIG1vcmUgaW5mb3JtYXRpdmUgZXJyb3IgbWVzc2FnZSB0aGFuIGlmIHRoZSBsZW5ndGhcbiAgICogd2FzIHN1cHBsaWVkIGRpcmVjdGx5LlxuICAgKlxuICAgKiAgICAgZXhwZWN0KCdmb28nKS50by5oYXZlLmxlbmd0aC53aXRoaW4oMiw0KTtcbiAgICogICAgIGV4cGVjdChbIDEsIDIsIDMgXSkudG8uaGF2ZS5sZW5ndGgud2l0aGluKDIsNCk7XG4gICAqXG4gICAqIEBuYW1lIHdpdGhpblxuICAgKiBAcGFyYW0ge051bWJlcn0gc3RhcnQgbG93ZXJib3VuZCBpbmNsdXNpdmVcbiAgICogQHBhcmFtIHtOdW1iZXJ9IGZpbmlzaCB1cHBlcmJvdW5kIGluY2x1c2l2ZVxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZSBfb3B0aW9uYWxfXG4gICAqIEBuYW1lc3BhY2UgQkREXG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIEFzc2VydGlvbi5hZGRNZXRob2QoJ3dpdGhpbicsIGZ1bmN0aW9uIChzdGFydCwgZmluaXNoLCBtc2cpIHtcbiAgICBpZiAobXNnKSBmbGFnKHRoaXMsICdtZXNzYWdlJywgbXNnKTtcbiAgICB2YXIgb2JqID0gZmxhZyh0aGlzLCAnb2JqZWN0JylcbiAgICAgICwgcmFuZ2UgPSBzdGFydCArICcuLicgKyBmaW5pc2g7XG4gICAgaWYgKGZsYWcodGhpcywgJ2RvTGVuZ3RoJykpIHtcbiAgICAgIG5ldyBBc3NlcnRpb24ob2JqLCBtc2cpLnRvLmhhdmUucHJvcGVydHkoJ2xlbmd0aCcpO1xuICAgICAgdmFyIGxlbiA9IG9iai5sZW5ndGg7XG4gICAgICB0aGlzLmFzc2VydChcbiAgICAgICAgICBsZW4gPj0gc3RhcnQgJiYgbGVuIDw9IGZpbmlzaFxuICAgICAgICAsICdleHBlY3RlZCAje3RoaXN9IHRvIGhhdmUgYSBsZW5ndGggd2l0aGluICcgKyByYW5nZVxuICAgICAgICAsICdleHBlY3RlZCAje3RoaXN9IHRvIG5vdCBoYXZlIGEgbGVuZ3RoIHdpdGhpbiAnICsgcmFuZ2VcbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuYXNzZXJ0KFxuICAgICAgICAgIG9iaiA+PSBzdGFydCAmJiBvYmogPD0gZmluaXNoXG4gICAgICAgICwgJ2V4cGVjdGVkICN7dGhpc30gdG8gYmUgd2l0aGluICcgKyByYW5nZVxuICAgICAgICAsICdleHBlY3RlZCAje3RoaXN9IHRvIG5vdCBiZSB3aXRoaW4gJyArIHJhbmdlXG4gICAgICApO1xuICAgIH1cbiAgfSk7XG5cbiAgLyoqXG4gICAqICMjIyAuaW5zdGFuY2VvZihjb25zdHJ1Y3RvcilcbiAgICpcbiAgICogQXNzZXJ0cyB0aGF0IHRoZSB0YXJnZXQgaXMgYW4gaW5zdGFuY2Ugb2YgYGNvbnN0cnVjdG9yYC5cbiAgICpcbiAgICogICAgIHZhciBUZWEgPSBmdW5jdGlvbiAobmFtZSkgeyB0aGlzLm5hbWUgPSBuYW1lOyB9XG4gICAqICAgICAgICwgQ2hhaSA9IG5ldyBUZWEoJ2NoYWknKTtcbiAgICpcbiAgICogICAgIGV4cGVjdChDaGFpKS50by5iZS5hbi5pbnN0YW5jZW9mKFRlYSk7XG4gICAqICAgICBleHBlY3QoWyAxLCAyLCAzIF0pLnRvLmJlLmluc3RhbmNlb2YoQXJyYXkpO1xuICAgKlxuICAgKiBAbmFtZSBpbnN0YW5jZW9mXG4gICAqIEBwYXJhbSB7Q29uc3RydWN0b3J9IGNvbnN0cnVjdG9yXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlIF9vcHRpb25hbF9cbiAgICogQGFsaWFzIGluc3RhbmNlT2ZcbiAgICogQG5hbWVzcGFjZSBCRERcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgZnVuY3Rpb24gYXNzZXJ0SW5zdGFuY2VPZiAoY29uc3RydWN0b3IsIG1zZykge1xuICAgIGlmIChtc2cpIGZsYWcodGhpcywgJ21lc3NhZ2UnLCBtc2cpO1xuICAgIHZhciBuYW1lID0gXy5nZXROYW1lKGNvbnN0cnVjdG9yKTtcbiAgICB0aGlzLmFzc2VydChcbiAgICAgICAgZmxhZyh0aGlzLCAnb2JqZWN0JykgaW5zdGFuY2VvZiBjb25zdHJ1Y3RvclxuICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byBiZSBhbiBpbnN0YW5jZSBvZiAnICsgbmFtZVxuICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byBub3QgYmUgYW4gaW5zdGFuY2Ugb2YgJyArIG5hbWVcbiAgICApO1xuICB9O1xuXG4gIEFzc2VydGlvbi5hZGRNZXRob2QoJ2luc3RhbmNlb2YnLCBhc3NlcnRJbnN0YW5jZU9mKTtcbiAgQXNzZXJ0aW9uLmFkZE1ldGhvZCgnaW5zdGFuY2VPZicsIGFzc2VydEluc3RhbmNlT2YpO1xuXG4gIC8qKlxuICAgKiAjIyMgLnByb3BlcnR5KG5hbWUsIFt2YWx1ZV0pXG4gICAqXG4gICAqIEFzc2VydHMgdGhhdCB0aGUgdGFyZ2V0IGhhcyBhIHByb3BlcnR5IGBuYW1lYCwgb3B0aW9uYWxseSBhc3NlcnRpbmcgdGhhdFxuICAgKiB0aGUgdmFsdWUgb2YgdGhhdCBwcm9wZXJ0eSBpcyBzdHJpY3RseSBlcXVhbCB0byAgYHZhbHVlYC5cbiAgICogSWYgdGhlIGBkZWVwYCBmbGFnIGlzIHNldCwgeW91IGNhbiB1c2UgZG90LSBhbmQgYnJhY2tldC1ub3RhdGlvbiBmb3IgZGVlcFxuICAgKiByZWZlcmVuY2VzIGludG8gb2JqZWN0cyBhbmQgYXJyYXlzLlxuICAgKlxuICAgKiAgICAgLy8gc2ltcGxlIHJlZmVyZW5jaW5nXG4gICAqICAgICB2YXIgb2JqID0geyBmb286ICdiYXInIH07XG4gICAqICAgICBleHBlY3Qob2JqKS50by5oYXZlLnByb3BlcnR5KCdmb28nKTtcbiAgICogICAgIGV4cGVjdChvYmopLnRvLmhhdmUucHJvcGVydHkoJ2ZvbycsICdiYXInKTtcbiAgICpcbiAgICogICAgIC8vIGRlZXAgcmVmZXJlbmNpbmdcbiAgICogICAgIHZhciBkZWVwT2JqID0ge1xuICAgKiAgICAgICAgIGdyZWVuOiB7IHRlYTogJ21hdGNoYScgfVxuICAgKiAgICAgICAsIHRlYXM6IFsgJ2NoYWknLCAnbWF0Y2hhJywgeyB0ZWE6ICdrb25hY2hhJyB9IF1cbiAgICogICAgIH07XG4gICAqXG4gICAqICAgICBleHBlY3QoZGVlcE9iaikudG8uaGF2ZS5kZWVwLnByb3BlcnR5KCdncmVlbi50ZWEnLCAnbWF0Y2hhJyk7XG4gICAqICAgICBleHBlY3QoZGVlcE9iaikudG8uaGF2ZS5kZWVwLnByb3BlcnR5KCd0ZWFzWzFdJywgJ21hdGNoYScpO1xuICAgKiAgICAgZXhwZWN0KGRlZXBPYmopLnRvLmhhdmUuZGVlcC5wcm9wZXJ0eSgndGVhc1syXS50ZWEnLCAna29uYWNoYScpO1xuICAgKlxuICAgKiBZb3UgY2FuIGFsc28gdXNlIGFuIGFycmF5IGFzIHRoZSBzdGFydGluZyBwb2ludCBvZiBhIGBkZWVwLnByb3BlcnR5YFxuICAgKiBhc3NlcnRpb24sIG9yIHRyYXZlcnNlIG5lc3RlZCBhcnJheXMuXG4gICAqXG4gICAqICAgICB2YXIgYXJyID0gW1xuICAgKiAgICAgICAgIFsgJ2NoYWknLCAnbWF0Y2hhJywgJ2tvbmFjaGEnIF1cbiAgICogICAgICAgLCBbIHsgdGVhOiAnY2hhaScgfVxuICAgKiAgICAgICAgICwgeyB0ZWE6ICdtYXRjaGEnIH1cbiAgICogICAgICAgICAsIHsgdGVhOiAna29uYWNoYScgfSBdXG4gICAqICAgICBdO1xuICAgKlxuICAgKiAgICAgZXhwZWN0KGFycikudG8uaGF2ZS5kZWVwLnByb3BlcnR5KCdbMF1bMV0nLCAnbWF0Y2hhJyk7XG4gICAqICAgICBleHBlY3QoYXJyKS50by5oYXZlLmRlZXAucHJvcGVydHkoJ1sxXVsyXS50ZWEnLCAna29uYWNoYScpO1xuICAgKlxuICAgKiBGdXJ0aGVybW9yZSwgYHByb3BlcnR5YCBjaGFuZ2VzIHRoZSBzdWJqZWN0IG9mIHRoZSBhc3NlcnRpb25cbiAgICogdG8gYmUgdGhlIHZhbHVlIG9mIHRoYXQgcHJvcGVydHkgZnJvbSB0aGUgb3JpZ2luYWwgb2JqZWN0LiBUaGlzXG4gICAqIHBlcm1pdHMgZm9yIGZ1cnRoZXIgY2hhaW5hYmxlIGFzc2VydGlvbnMgb24gdGhhdCBwcm9wZXJ0eS5cbiAgICpcbiAgICogICAgIGV4cGVjdChvYmopLnRvLmhhdmUucHJvcGVydHkoJ2ZvbycpXG4gICAqICAgICAgIC50aGF0LmlzLmEoJ3N0cmluZycpO1xuICAgKiAgICAgZXhwZWN0KGRlZXBPYmopLnRvLmhhdmUucHJvcGVydHkoJ2dyZWVuJylcbiAgICogICAgICAgLnRoYXQuaXMuYW4oJ29iamVjdCcpXG4gICAqICAgICAgIC50aGF0LmRlZXAuZXF1YWxzKHsgdGVhOiAnbWF0Y2hhJyB9KTtcbiAgICogICAgIGV4cGVjdChkZWVwT2JqKS50by5oYXZlLnByb3BlcnR5KCd0ZWFzJylcbiAgICogICAgICAgLnRoYXQuaXMuYW4oJ2FycmF5JylcbiAgICogICAgICAgLndpdGguZGVlcC5wcm9wZXJ0eSgnWzJdJylcbiAgICogICAgICAgICAudGhhdC5kZWVwLmVxdWFscyh7IHRlYTogJ2tvbmFjaGEnIH0pO1xuICAgKlxuICAgKiBOb3RlIHRoYXQgZG90cyBhbmQgYnJhY2tldCBpbiBgbmFtZWAgbXVzdCBiZSBiYWNrc2xhc2gtZXNjYXBlZCB3aGVuXG4gICAqIHRoZSBgZGVlcGAgZmxhZyBpcyBzZXQsIHdoaWxlIHRoZXkgbXVzdCBOT1QgYmUgZXNjYXBlZCB3aGVuIHRoZSBgZGVlcGBcbiAgICogZmxhZyBpcyBub3Qgc2V0LlxuICAgKlxuICAgKiAgICAgLy8gc2ltcGxlIHJlZmVyZW5jaW5nXG4gICAqICAgICB2YXIgY3NzID0geyAnLmxpbmtbdGFyZ2V0XSc6IDQyIH07XG4gICAqICAgICBleHBlY3QoY3NzKS50by5oYXZlLnByb3BlcnR5KCcubGlua1t0YXJnZXRdJywgNDIpO1xuICAgKlxuICAgKiAgICAgLy8gZGVlcCByZWZlcmVuY2luZ1xuICAgKiAgICAgdmFyIGRlZXBDc3MgPSB7ICcubGluayc6IHsgJ1t0YXJnZXRdJzogNDIgfX07XG4gICAqICAgICBleHBlY3QoZGVlcENzcykudG8uaGF2ZS5kZWVwLnByb3BlcnR5KCdcXFxcLmxpbmsuXFxcXFt0YXJnZXRcXFxcXScsIDQyKTtcbiAgICpcbiAgICogQG5hbWUgcHJvcGVydHlcbiAgICogQGFsaWFzIGRlZXAucHJvcGVydHlcbiAgICogQHBhcmFtIHtTdHJpbmd9IG5hbWVcbiAgICogQHBhcmFtIHtNaXhlZH0gdmFsdWUgKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZSBfb3B0aW9uYWxfXG4gICAqIEByZXR1cm5zIHZhbHVlIG9mIHByb3BlcnR5IGZvciBjaGFpbmluZ1xuICAgKiBAbmFtZXNwYWNlIEJERFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBBc3NlcnRpb24uYWRkTWV0aG9kKCdwcm9wZXJ0eScsIGZ1bmN0aW9uIChuYW1lLCB2YWwsIG1zZykge1xuICAgIGlmIChtc2cpIGZsYWcodGhpcywgJ21lc3NhZ2UnLCBtc2cpO1xuXG4gICAgdmFyIGlzRGVlcCA9ICEhZmxhZyh0aGlzLCAnZGVlcCcpXG4gICAgICAsIGRlc2NyaXB0b3IgPSBpc0RlZXAgPyAnZGVlcCBwcm9wZXJ0eSAnIDogJ3Byb3BlcnR5ICdcbiAgICAgICwgbmVnYXRlID0gZmxhZyh0aGlzLCAnbmVnYXRlJylcbiAgICAgICwgb2JqID0gZmxhZyh0aGlzLCAnb2JqZWN0JylcbiAgICAgICwgcGF0aEluZm8gPSBpc0RlZXAgPyBfLmdldFBhdGhJbmZvKG5hbWUsIG9iaikgOiBudWxsXG4gICAgICAsIGhhc1Byb3BlcnR5ID0gaXNEZWVwXG4gICAgICAgID8gcGF0aEluZm8uZXhpc3RzXG4gICAgICAgIDogXy5oYXNQcm9wZXJ0eShuYW1lLCBvYmopXG4gICAgICAsIHZhbHVlID0gaXNEZWVwXG4gICAgICAgID8gcGF0aEluZm8udmFsdWVcbiAgICAgICAgOiBvYmpbbmFtZV07XG5cbiAgICBpZiAobmVnYXRlICYmIGFyZ3VtZW50cy5sZW5ndGggPiAxKSB7XG4gICAgICBpZiAodW5kZWZpbmVkID09PSB2YWx1ZSkge1xuICAgICAgICBtc2cgPSAobXNnICE9IG51bGwpID8gbXNnICsgJzogJyA6ICcnO1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IobXNnICsgXy5pbnNwZWN0KG9iaikgKyAnIGhhcyBubyAnICsgZGVzY3JpcHRvciArIF8uaW5zcGVjdChuYW1lKSk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuYXNzZXJ0KFxuICAgICAgICAgIGhhc1Byb3BlcnR5XG4gICAgICAgICwgJ2V4cGVjdGVkICN7dGhpc30gdG8gaGF2ZSBhICcgKyBkZXNjcmlwdG9yICsgXy5pbnNwZWN0KG5hbWUpXG4gICAgICAgICwgJ2V4cGVjdGVkICN7dGhpc30gdG8gbm90IGhhdmUgJyArIGRlc2NyaXB0b3IgKyBfLmluc3BlY3QobmFtZSkpO1xuICAgIH1cblxuICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID4gMSkge1xuICAgICAgdGhpcy5hc3NlcnQoXG4gICAgICAgICAgdmFsID09PSB2YWx1ZVxuICAgICAgICAsICdleHBlY3RlZCAje3RoaXN9IHRvIGhhdmUgYSAnICsgZGVzY3JpcHRvciArIF8uaW5zcGVjdChuYW1lKSArICcgb2YgI3tleHB9LCBidXQgZ290ICN7YWN0fSdcbiAgICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byBub3QgaGF2ZSBhICcgKyBkZXNjcmlwdG9yICsgXy5pbnNwZWN0KG5hbWUpICsgJyBvZiAje2FjdH0nXG4gICAgICAgICwgdmFsXG4gICAgICAgICwgdmFsdWVcbiAgICAgICk7XG4gICAgfVxuXG4gICAgZmxhZyh0aGlzLCAnb2JqZWN0JywgdmFsdWUpO1xuICB9KTtcblxuXG4gIC8qKlxuICAgKiAjIyMgLm93blByb3BlcnR5KG5hbWUpXG4gICAqXG4gICAqIEFzc2VydHMgdGhhdCB0aGUgdGFyZ2V0IGhhcyBhbiBvd24gcHJvcGVydHkgYG5hbWVgLlxuICAgKlxuICAgKiAgICAgZXhwZWN0KCd0ZXN0JykudG8uaGF2ZS5vd25Qcm9wZXJ0eSgnbGVuZ3RoJyk7XG4gICAqXG4gICAqIEBuYW1lIG93blByb3BlcnR5XG4gICAqIEBhbGlhcyBoYXZlT3duUHJvcGVydHlcbiAgICogQHBhcmFtIHtTdHJpbmd9IG5hbWVcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2UgX29wdGlvbmFsX1xuICAgKiBAbmFtZXNwYWNlIEJERFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBmdW5jdGlvbiBhc3NlcnRPd25Qcm9wZXJ0eSAobmFtZSwgbXNnKSB7XG4gICAgaWYgKG1zZykgZmxhZyh0aGlzLCAnbWVzc2FnZScsIG1zZyk7XG4gICAgdmFyIG9iaiA9IGZsYWcodGhpcywgJ29iamVjdCcpO1xuICAgIHRoaXMuYXNzZXJ0KFxuICAgICAgICBvYmouaGFzT3duUHJvcGVydHkobmFtZSlcbiAgICAgICwgJ2V4cGVjdGVkICN7dGhpc30gdG8gaGF2ZSBvd24gcHJvcGVydHkgJyArIF8uaW5zcGVjdChuYW1lKVxuICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byBub3QgaGF2ZSBvd24gcHJvcGVydHkgJyArIF8uaW5zcGVjdChuYW1lKVxuICAgICk7XG4gIH1cblxuICBBc3NlcnRpb24uYWRkTWV0aG9kKCdvd25Qcm9wZXJ0eScsIGFzc2VydE93blByb3BlcnR5KTtcbiAgQXNzZXJ0aW9uLmFkZE1ldGhvZCgnaGF2ZU93blByb3BlcnR5JywgYXNzZXJ0T3duUHJvcGVydHkpO1xuXG4gIC8qKlxuICAgKiAjIyMgLm93blByb3BlcnR5RGVzY3JpcHRvcihuYW1lWywgZGVzY3JpcHRvclssIG1lc3NhZ2VdXSlcbiAgICpcbiAgICogQXNzZXJ0cyB0aGF0IHRoZSB0YXJnZXQgaGFzIGFuIG93biBwcm9wZXJ0eSBkZXNjcmlwdG9yIGBuYW1lYCwgdGhhdCBvcHRpb25hbGx5IG1hdGNoZXMgYGRlc2NyaXB0b3JgLlxuICAgKlxuICAgKiAgICAgZXhwZWN0KCd0ZXN0JykudG8uaGF2ZS5vd25Qcm9wZXJ0eURlc2NyaXB0b3IoJ2xlbmd0aCcpO1xuICAgKiAgICAgZXhwZWN0KCd0ZXN0JykudG8uaGF2ZS5vd25Qcm9wZXJ0eURlc2NyaXB0b3IoJ2xlbmd0aCcsIHsgZW51bWVyYWJsZTogZmFsc2UsIGNvbmZpZ3VyYWJsZTogZmFsc2UsIHdyaXRhYmxlOiBmYWxzZSwgdmFsdWU6IDQgfSk7XG4gICAqICAgICBleHBlY3QoJ3Rlc3QnKS5ub3QudG8uaGF2ZS5vd25Qcm9wZXJ0eURlc2NyaXB0b3IoJ2xlbmd0aCcsIHsgZW51bWVyYWJsZTogZmFsc2UsIGNvbmZpZ3VyYWJsZTogZmFsc2UsIHdyaXRhYmxlOiBmYWxzZSwgdmFsdWU6IDMgfSk7XG4gICAqICAgICBleHBlY3QoJ3Rlc3QnKS5vd25Qcm9wZXJ0eURlc2NyaXB0b3IoJ2xlbmd0aCcpLnRvLmhhdmUucHJvcGVydHkoJ2VudW1lcmFibGUnLCBmYWxzZSk7XG4gICAqICAgICBleHBlY3QoJ3Rlc3QnKS5vd25Qcm9wZXJ0eURlc2NyaXB0b3IoJ2xlbmd0aCcpLnRvLmhhdmUua2V5cygndmFsdWUnKTtcbiAgICpcbiAgICogQG5hbWUgb3duUHJvcGVydHlEZXNjcmlwdG9yXG4gICAqIEBhbGlhcyBoYXZlT3duUHJvcGVydHlEZXNjcmlwdG9yXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBuYW1lXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBkZXNjcmlwdG9yIF9vcHRpb25hbF9cbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2UgX29wdGlvbmFsX1xuICAgKiBAbmFtZXNwYWNlIEJERFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBmdW5jdGlvbiBhc3NlcnRPd25Qcm9wZXJ0eURlc2NyaXB0b3IgKG5hbWUsIGRlc2NyaXB0b3IsIG1zZykge1xuICAgIGlmICh0eXBlb2YgZGVzY3JpcHRvciA9PT0gJ3N0cmluZycpIHtcbiAgICAgIG1zZyA9IGRlc2NyaXB0b3I7XG4gICAgICBkZXNjcmlwdG9yID0gbnVsbDtcbiAgICB9XG4gICAgaWYgKG1zZykgZmxhZyh0aGlzLCAnbWVzc2FnZScsIG1zZyk7XG4gICAgdmFyIG9iaiA9IGZsYWcodGhpcywgJ29iamVjdCcpO1xuICAgIHZhciBhY3R1YWxEZXNjcmlwdG9yID0gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihPYmplY3Qob2JqKSwgbmFtZSk7XG4gICAgaWYgKGFjdHVhbERlc2NyaXB0b3IgJiYgZGVzY3JpcHRvcikge1xuICAgICAgdGhpcy5hc3NlcnQoXG4gICAgICAgICAgXy5lcWwoZGVzY3JpcHRvciwgYWN0dWFsRGVzY3JpcHRvcilcbiAgICAgICAgLCAnZXhwZWN0ZWQgdGhlIG93biBwcm9wZXJ0eSBkZXNjcmlwdG9yIGZvciAnICsgXy5pbnNwZWN0KG5hbWUpICsgJyBvbiAje3RoaXN9IHRvIG1hdGNoICcgKyBfLmluc3BlY3QoZGVzY3JpcHRvcikgKyAnLCBnb3QgJyArIF8uaW5zcGVjdChhY3R1YWxEZXNjcmlwdG9yKVxuICAgICAgICAsICdleHBlY3RlZCB0aGUgb3duIHByb3BlcnR5IGRlc2NyaXB0b3IgZm9yICcgKyBfLmluc3BlY3QobmFtZSkgKyAnIG9uICN7dGhpc30gdG8gbm90IG1hdGNoICcgKyBfLmluc3BlY3QoZGVzY3JpcHRvcilcbiAgICAgICAgLCBkZXNjcmlwdG9yXG4gICAgICAgICwgYWN0dWFsRGVzY3JpcHRvclxuICAgICAgICAsIHRydWVcbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuYXNzZXJ0KFxuICAgICAgICAgIGFjdHVhbERlc2NyaXB0b3JcbiAgICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byBoYXZlIGFuIG93biBwcm9wZXJ0eSBkZXNjcmlwdG9yIGZvciAnICsgXy5pbnNwZWN0KG5hbWUpXG4gICAgICAgICwgJ2V4cGVjdGVkICN7dGhpc30gdG8gbm90IGhhdmUgYW4gb3duIHByb3BlcnR5IGRlc2NyaXB0b3IgZm9yICcgKyBfLmluc3BlY3QobmFtZSlcbiAgICAgICk7XG4gICAgfVxuICAgIGZsYWcodGhpcywgJ29iamVjdCcsIGFjdHVhbERlc2NyaXB0b3IpO1xuICB9XG5cbiAgQXNzZXJ0aW9uLmFkZE1ldGhvZCgnb3duUHJvcGVydHlEZXNjcmlwdG9yJywgYXNzZXJ0T3duUHJvcGVydHlEZXNjcmlwdG9yKTtcbiAgQXNzZXJ0aW9uLmFkZE1ldGhvZCgnaGF2ZU93blByb3BlcnR5RGVzY3JpcHRvcicsIGFzc2VydE93blByb3BlcnR5RGVzY3JpcHRvcik7XG5cbiAgLyoqXG4gICAqICMjIyAubGVuZ3RoXG4gICAqXG4gICAqIFNldHMgdGhlIGBkb0xlbmd0aGAgZmxhZyBsYXRlciB1c2VkIGFzIGEgY2hhaW4gcHJlY3Vyc29yIHRvIGEgdmFsdWVcbiAgICogY29tcGFyaXNvbiBmb3IgdGhlIGBsZW5ndGhgIHByb3BlcnR5LlxuICAgKlxuICAgKiAgICAgZXhwZWN0KCdmb28nKS50by5oYXZlLmxlbmd0aC5hYm92ZSgyKTtcbiAgICogICAgIGV4cGVjdChbIDEsIDIsIDMgXSkudG8uaGF2ZS5sZW5ndGguYWJvdmUoMik7XG4gICAqICAgICBleHBlY3QoJ2ZvbycpLnRvLmhhdmUubGVuZ3RoLmJlbG93KDQpO1xuICAgKiAgICAgZXhwZWN0KFsgMSwgMiwgMyBdKS50by5oYXZlLmxlbmd0aC5iZWxvdyg0KTtcbiAgICogICAgIGV4cGVjdCgnZm9vJykudG8uaGF2ZS5sZW5ndGgud2l0aGluKDIsNCk7XG4gICAqICAgICBleHBlY3QoWyAxLCAyLCAzIF0pLnRvLmhhdmUubGVuZ3RoLndpdGhpbigyLDQpO1xuICAgKlxuICAgKiAqRGVwcmVjYXRpb24gbm90aWNlOiogVXNpbmcgYGxlbmd0aGAgYXMgYW4gYXNzZXJ0aW9uIHdpbGwgYmUgZGVwcmVjYXRlZFxuICAgKiBpbiB2ZXJzaW9uIDIuNC4wIGFuZCByZW1vdmVkIGluIDMuMC4wLiBDb2RlIHVzaW5nIHRoZSBvbGQgc3R5bGUgb2ZcbiAgICogYXNzZXJ0aW5nIGZvciBgbGVuZ3RoYCBwcm9wZXJ0eSB2YWx1ZSB1c2luZyBgbGVuZ3RoKHZhbHVlKWAgc2hvdWxkIGJlXG4gICAqIHN3aXRjaGVkIHRvIHVzZSBgbGVuZ3RoT2YodmFsdWUpYCBpbnN0ZWFkLlxuICAgKlxuICAgKiBAbmFtZSBsZW5ndGhcbiAgICogQG5hbWVzcGFjZSBCRERcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgLyoqXG4gICAqICMjIyAubGVuZ3RoT2YodmFsdWVbLCBtZXNzYWdlXSlcbiAgICpcbiAgICogQXNzZXJ0cyB0aGF0IHRoZSB0YXJnZXQncyBgbGVuZ3RoYCBwcm9wZXJ0eSBoYXNcbiAgICogdGhlIGV4cGVjdGVkIHZhbHVlLlxuICAgKlxuICAgKiAgICAgZXhwZWN0KFsgMSwgMiwgM10pLnRvLmhhdmUubGVuZ3RoT2YoMyk7XG4gICAqICAgICBleHBlY3QoJ2Zvb2JhcicpLnRvLmhhdmUubGVuZ3RoT2YoNik7XG4gICAqXG4gICAqIEBuYW1lIGxlbmd0aE9mXG4gICAqIEBwYXJhbSB7TnVtYmVyfSBsZW5ndGhcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2UgX29wdGlvbmFsX1xuICAgKiBAbmFtZXNwYWNlIEJERFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBmdW5jdGlvbiBhc3NlcnRMZW5ndGhDaGFpbiAoKSB7XG4gICAgZmxhZyh0aGlzLCAnZG9MZW5ndGgnLCB0cnVlKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIGFzc2VydExlbmd0aCAobiwgbXNnKSB7XG4gICAgaWYgKG1zZykgZmxhZyh0aGlzLCAnbWVzc2FnZScsIG1zZyk7XG4gICAgdmFyIG9iaiA9IGZsYWcodGhpcywgJ29iamVjdCcpO1xuICAgIG5ldyBBc3NlcnRpb24ob2JqLCBtc2cpLnRvLmhhdmUucHJvcGVydHkoJ2xlbmd0aCcpO1xuICAgIHZhciBsZW4gPSBvYmoubGVuZ3RoO1xuXG4gICAgdGhpcy5hc3NlcnQoXG4gICAgICAgIGxlbiA9PSBuXG4gICAgICAsICdleHBlY3RlZCAje3RoaXN9IHRvIGhhdmUgYSBsZW5ndGggb2YgI3tleHB9IGJ1dCBnb3QgI3thY3R9J1xuICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byBub3QgaGF2ZSBhIGxlbmd0aCBvZiAje2FjdH0nXG4gICAgICAsIG5cbiAgICAgICwgbGVuXG4gICAgKTtcbiAgfVxuXG4gIEFzc2VydGlvbi5hZGRDaGFpbmFibGVNZXRob2QoJ2xlbmd0aCcsIGFzc2VydExlbmd0aCwgYXNzZXJ0TGVuZ3RoQ2hhaW4pO1xuICBBc3NlcnRpb24uYWRkTWV0aG9kKCdsZW5ndGhPZicsIGFzc2VydExlbmd0aCk7XG5cbiAgLyoqXG4gICAqICMjIyAubWF0Y2gocmVnZXhwKVxuICAgKlxuICAgKiBBc3NlcnRzIHRoYXQgdGhlIHRhcmdldCBtYXRjaGVzIGEgcmVndWxhciBleHByZXNzaW9uLlxuICAgKlxuICAgKiAgICAgZXhwZWN0KCdmb29iYXInKS50by5tYXRjaCgvXmZvby8pO1xuICAgKlxuICAgKiBAbmFtZSBtYXRjaFxuICAgKiBAYWxpYXMgbWF0Y2hlc1xuICAgKiBAcGFyYW0ge1JlZ0V4cH0gUmVndWxhckV4cHJlc3Npb25cbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2UgX29wdGlvbmFsX1xuICAgKiBAbmFtZXNwYWNlIEJERFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cbiAgZnVuY3Rpb24gYXNzZXJ0TWF0Y2gocmUsIG1zZykge1xuICAgIGlmIChtc2cpIGZsYWcodGhpcywgJ21lc3NhZ2UnLCBtc2cpO1xuICAgIHZhciBvYmogPSBmbGFnKHRoaXMsICdvYmplY3QnKTtcbiAgICB0aGlzLmFzc2VydChcbiAgICAgICAgcmUuZXhlYyhvYmopXG4gICAgICAsICdleHBlY3RlZCAje3RoaXN9IHRvIG1hdGNoICcgKyByZVxuICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSBub3QgdG8gbWF0Y2ggJyArIHJlXG4gICAgKTtcbiAgfVxuXG4gIEFzc2VydGlvbi5hZGRNZXRob2QoJ21hdGNoJywgYXNzZXJ0TWF0Y2gpO1xuICBBc3NlcnRpb24uYWRkTWV0aG9kKCdtYXRjaGVzJywgYXNzZXJ0TWF0Y2gpO1xuXG4gIC8qKlxuICAgKiAjIyMgLnN0cmluZyhzdHJpbmcpXG4gICAqXG4gICAqIEFzc2VydHMgdGhhdCB0aGUgc3RyaW5nIHRhcmdldCBjb250YWlucyBhbm90aGVyIHN0cmluZy5cbiAgICpcbiAgICogICAgIGV4cGVjdCgnZm9vYmFyJykudG8uaGF2ZS5zdHJpbmcoJ2JhcicpO1xuICAgKlxuICAgKiBAbmFtZSBzdHJpbmdcbiAgICogQHBhcmFtIHtTdHJpbmd9IHN0cmluZ1xuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZSBfb3B0aW9uYWxfXG4gICAqIEBuYW1lc3BhY2UgQkREXG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIEFzc2VydGlvbi5hZGRNZXRob2QoJ3N0cmluZycsIGZ1bmN0aW9uIChzdHIsIG1zZykge1xuICAgIGlmIChtc2cpIGZsYWcodGhpcywgJ21lc3NhZ2UnLCBtc2cpO1xuICAgIHZhciBvYmogPSBmbGFnKHRoaXMsICdvYmplY3QnKTtcbiAgICBuZXcgQXNzZXJ0aW9uKG9iaiwgbXNnKS5pcy5hKCdzdHJpbmcnKTtcblxuICAgIHRoaXMuYXNzZXJ0KFxuICAgICAgICB+b2JqLmluZGV4T2Yoc3RyKVxuICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byBjb250YWluICcgKyBfLmluc3BlY3Qoc3RyKVxuICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byBub3QgY29udGFpbiAnICsgXy5pbnNwZWN0KHN0cilcbiAgICApO1xuICB9KTtcblxuXG4gIC8qKlxuICAgKiAjIyMgLmtleXMoa2V5MSwgW2tleTJdLCBbLi4uXSlcbiAgICpcbiAgICogQXNzZXJ0cyB0aGF0IHRoZSB0YXJnZXQgY29udGFpbnMgYW55IG9yIGFsbCBvZiB0aGUgcGFzc2VkLWluIGtleXMuXG4gICAqIFVzZSBpbiBjb21iaW5hdGlvbiB3aXRoIGBhbnlgLCBgYWxsYCwgYGNvbnRhaW5zYCwgb3IgYGhhdmVgIHdpbGwgYWZmZWN0XG4gICAqIHdoYXQgd2lsbCBwYXNzLlxuICAgKlxuICAgKiBXaGVuIHVzZWQgaW4gY29uanVuY3Rpb24gd2l0aCBgYW55YCwgYXQgbGVhc3Qgb25lIGtleSB0aGF0IGlzIHBhc3NlZFxuICAgKiBpbiBtdXN0IGV4aXN0IGluIHRoZSB0YXJnZXQgb2JqZWN0LiBUaGlzIGlzIHJlZ2FyZGxlc3Mgd2hldGhlciBvciBub3RcbiAgICogdGhlIGBoYXZlYCBvciBgY29udGFpbmAgcXVhbGlmaWVycyBhcmUgdXNlZC4gTm90ZSwgZWl0aGVyIGBhbnlgIG9yIGBhbGxgXG4gICAqIHNob3VsZCBiZSB1c2VkIGluIHRoZSBhc3NlcnRpb24uIElmIG5laXRoZXIgYXJlIHVzZWQsIHRoZSBhc3NlcnRpb24gaXNcbiAgICogZGVmYXVsdGVkIHRvIGBhbGxgLlxuICAgKlxuICAgKiBXaGVuIGJvdGggYGFsbGAgYW5kIGBjb250YWluYCBhcmUgdXNlZCwgdGhlIHRhcmdldCBvYmplY3QgbXVzdCBoYXZlIGF0XG4gICAqIGxlYXN0IGFsbCBvZiB0aGUgcGFzc2VkLWluIGtleXMgYnV0IG1heSBoYXZlIG1vcmUga2V5cyBub3QgbGlzdGVkLlxuICAgKlxuICAgKiBXaGVuIGJvdGggYGFsbGAgYW5kIGBoYXZlYCBhcmUgdXNlZCwgdGhlIHRhcmdldCBvYmplY3QgbXVzdCBib3RoIGNvbnRhaW5cbiAgICogYWxsIG9mIHRoZSBwYXNzZWQtaW4ga2V5cyBBTkQgdGhlIG51bWJlciBvZiBrZXlzIGluIHRoZSB0YXJnZXQgb2JqZWN0IG11c3RcbiAgICogbWF0Y2ggdGhlIG51bWJlciBvZiBrZXlzIHBhc3NlZCBpbiAoaW4gb3RoZXIgd29yZHMsIGEgdGFyZ2V0IG9iamVjdCBtdXN0XG4gICAqIGhhdmUgYWxsIGFuZCBvbmx5IGFsbCBvZiB0aGUgcGFzc2VkLWluIGtleXMpLlxuICAgKlxuICAgKiAgICAgZXhwZWN0KHsgZm9vOiAxLCBiYXI6IDIgfSkudG8uaGF2ZS5hbnkua2V5cygnZm9vJywgJ2JheicpO1xuICAgKiAgICAgZXhwZWN0KHsgZm9vOiAxLCBiYXI6IDIgfSkudG8uaGF2ZS5hbnkua2V5cygnZm9vJyk7XG4gICAqICAgICBleHBlY3QoeyBmb286IDEsIGJhcjogMiB9KS50by5jb250YWluLmFueS5rZXlzKCdiYXInLCAnYmF6Jyk7XG4gICAqICAgICBleHBlY3QoeyBmb286IDEsIGJhcjogMiB9KS50by5jb250YWluLmFueS5rZXlzKFsnZm9vJ10pO1xuICAgKiAgICAgZXhwZWN0KHsgZm9vOiAxLCBiYXI6IDIgfSkudG8uY29udGFpbi5hbnkua2V5cyh7J2Zvbyc6IDZ9KTtcbiAgICogICAgIGV4cGVjdCh7IGZvbzogMSwgYmFyOiAyIH0pLnRvLmhhdmUuYWxsLmtleXMoWydiYXInLCAnZm9vJ10pO1xuICAgKiAgICAgZXhwZWN0KHsgZm9vOiAxLCBiYXI6IDIgfSkudG8uaGF2ZS5hbGwua2V5cyh7J2Jhcic6IDYsICdmb28nOiA3fSk7XG4gICAqICAgICBleHBlY3QoeyBmb286IDEsIGJhcjogMiwgYmF6OiAzIH0pLnRvLmNvbnRhaW4uYWxsLmtleXMoWydiYXInLCAnZm9vJ10pO1xuICAgKiAgICAgZXhwZWN0KHsgZm9vOiAxLCBiYXI6IDIsIGJhejogMyB9KS50by5jb250YWluLmFsbC5rZXlzKHsnYmFyJzogNn0pO1xuICAgKlxuICAgKlxuICAgKiBAbmFtZSBrZXlzXG4gICAqIEBhbGlhcyBrZXlcbiAgICogQHBhcmFtIHsuLi5TdHJpbmd8QXJyYXl8T2JqZWN0fSBrZXlzXG4gICAqIEBuYW1lc3BhY2UgQkREXG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIGZ1bmN0aW9uIGFzc2VydEtleXMgKGtleXMpIHtcbiAgICB2YXIgb2JqID0gZmxhZyh0aGlzLCAnb2JqZWN0JylcbiAgICAgICwgc3RyXG4gICAgICAsIG9rID0gdHJ1ZVxuICAgICAgLCBtaXhlZEFyZ3NNc2cgPSAna2V5cyBtdXN0IGJlIGdpdmVuIHNpbmdsZSBhcmd1bWVudCBvZiBBcnJheXxPYmplY3R8U3RyaW5nLCBvciBtdWx0aXBsZSBTdHJpbmcgYXJndW1lbnRzJztcblxuICAgIHN3aXRjaCAoXy50eXBlKGtleXMpKSB7XG4gICAgICBjYXNlIFwiYXJyYXlcIjpcbiAgICAgICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPiAxKSB0aHJvdyAobmV3IEVycm9yKG1peGVkQXJnc01zZykpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgXCJvYmplY3RcIjpcbiAgICAgICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPiAxKSB0aHJvdyAobmV3IEVycm9yKG1peGVkQXJnc01zZykpO1xuICAgICAgICBrZXlzID0gT2JqZWN0LmtleXMoa2V5cyk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAga2V5cyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cyk7XG4gICAgfVxuXG4gICAgaWYgKCFrZXlzLmxlbmd0aCkgdGhyb3cgbmV3IEVycm9yKCdrZXlzIHJlcXVpcmVkJyk7XG5cbiAgICB2YXIgYWN0dWFsID0gT2JqZWN0LmtleXMob2JqKVxuICAgICAgLCBleHBlY3RlZCA9IGtleXNcbiAgICAgICwgbGVuID0ga2V5cy5sZW5ndGhcbiAgICAgICwgYW55ID0gZmxhZyh0aGlzLCAnYW55JylcbiAgICAgICwgYWxsID0gZmxhZyh0aGlzLCAnYWxsJyk7XG5cbiAgICBpZiAoIWFueSAmJiAhYWxsKSB7XG4gICAgICBhbGwgPSB0cnVlO1xuICAgIH1cblxuICAgIC8vIEhhcyBhbnlcbiAgICBpZiAoYW55KSB7XG4gICAgICB2YXIgaW50ZXJzZWN0aW9uID0gZXhwZWN0ZWQuZmlsdGVyKGZ1bmN0aW9uKGtleSkge1xuICAgICAgICByZXR1cm4gfmFjdHVhbC5pbmRleE9mKGtleSk7XG4gICAgICB9KTtcbiAgICAgIG9rID0gaW50ZXJzZWN0aW9uLmxlbmd0aCA+IDA7XG4gICAgfVxuXG4gICAgLy8gSGFzIGFsbFxuICAgIGlmIChhbGwpIHtcbiAgICAgIG9rID0ga2V5cy5ldmVyeShmdW5jdGlvbihrZXkpe1xuICAgICAgICByZXR1cm4gfmFjdHVhbC5pbmRleE9mKGtleSk7XG4gICAgICB9KTtcbiAgICAgIGlmICghZmxhZyh0aGlzLCAnbmVnYXRlJykgJiYgIWZsYWcodGhpcywgJ2NvbnRhaW5zJykpIHtcbiAgICAgICAgb2sgPSBvayAmJiBrZXlzLmxlbmd0aCA9PSBhY3R1YWwubGVuZ3RoO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEtleSBzdHJpbmdcbiAgICBpZiAobGVuID4gMSkge1xuICAgICAga2V5cyA9IGtleXMubWFwKGZ1bmN0aW9uKGtleSl7XG4gICAgICAgIHJldHVybiBfLmluc3BlY3Qoa2V5KTtcbiAgICAgIH0pO1xuICAgICAgdmFyIGxhc3QgPSBrZXlzLnBvcCgpO1xuICAgICAgaWYgKGFsbCkge1xuICAgICAgICBzdHIgPSBrZXlzLmpvaW4oJywgJykgKyAnLCBhbmQgJyArIGxhc3Q7XG4gICAgICB9XG4gICAgICBpZiAoYW55KSB7XG4gICAgICAgIHN0ciA9IGtleXMuam9pbignLCAnKSArICcsIG9yICcgKyBsYXN0O1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBzdHIgPSBfLmluc3BlY3Qoa2V5c1swXSk7XG4gICAgfVxuXG4gICAgLy8gRm9ybVxuICAgIHN0ciA9IChsZW4gPiAxID8gJ2tleXMgJyA6ICdrZXkgJykgKyBzdHI7XG5cbiAgICAvLyBIYXZlIC8gaW5jbHVkZVxuICAgIHN0ciA9IChmbGFnKHRoaXMsICdjb250YWlucycpID8gJ2NvbnRhaW4gJyA6ICdoYXZlICcpICsgc3RyO1xuXG4gICAgLy8gQXNzZXJ0aW9uXG4gICAgdGhpcy5hc3NlcnQoXG4gICAgICAgIG9rXG4gICAgICAsICdleHBlY3RlZCAje3RoaXN9IHRvICcgKyBzdHJcbiAgICAgICwgJ2V4cGVjdGVkICN7dGhpc30gdG8gbm90ICcgKyBzdHJcbiAgICAgICwgZXhwZWN0ZWQuc2xpY2UoMCkuc29ydCgpXG4gICAgICAsIGFjdHVhbC5zb3J0KClcbiAgICAgICwgdHJ1ZVxuICAgICk7XG4gIH1cblxuICBBc3NlcnRpb24uYWRkTWV0aG9kKCdrZXlzJywgYXNzZXJ0S2V5cyk7XG4gIEFzc2VydGlvbi5hZGRNZXRob2QoJ2tleScsIGFzc2VydEtleXMpO1xuXG4gIC8qKlxuICAgKiAjIyMgLnRocm93KGNvbnN0cnVjdG9yKVxuICAgKlxuICAgKiBBc3NlcnRzIHRoYXQgdGhlIGZ1bmN0aW9uIHRhcmdldCB3aWxsIHRocm93IGEgc3BlY2lmaWMgZXJyb3IsIG9yIHNwZWNpZmljIHR5cGUgb2YgZXJyb3JcbiAgICogKGFzIGRldGVybWluZWQgdXNpbmcgYGluc3RhbmNlb2ZgKSwgb3B0aW9uYWxseSB3aXRoIGEgUmVnRXhwIG9yIHN0cmluZyBpbmNsdXNpb24gdGVzdFxuICAgKiBmb3IgdGhlIGVycm9yJ3MgbWVzc2FnZS5cbiAgICpcbiAgICogICAgIHZhciBlcnIgPSBuZXcgUmVmZXJlbmNlRXJyb3IoJ1RoaXMgaXMgYSBiYWQgZnVuY3Rpb24uJyk7XG4gICAqICAgICB2YXIgZm4gPSBmdW5jdGlvbiAoKSB7IHRocm93IGVycjsgfVxuICAgKiAgICAgZXhwZWN0KGZuKS50by50aHJvdyhSZWZlcmVuY2VFcnJvcik7XG4gICAqICAgICBleHBlY3QoZm4pLnRvLnRocm93KEVycm9yKTtcbiAgICogICAgIGV4cGVjdChmbikudG8udGhyb3coL2JhZCBmdW5jdGlvbi8pO1xuICAgKiAgICAgZXhwZWN0KGZuKS50by5ub3QudGhyb3coJ2dvb2QgZnVuY3Rpb24nKTtcbiAgICogICAgIGV4cGVjdChmbikudG8udGhyb3coUmVmZXJlbmNlRXJyb3IsIC9iYWQgZnVuY3Rpb24vKTtcbiAgICogICAgIGV4cGVjdChmbikudG8udGhyb3coZXJyKTtcbiAgICpcbiAgICogUGxlYXNlIG5vdGUgdGhhdCB3aGVuIGEgdGhyb3cgZXhwZWN0YXRpb24gaXMgbmVnYXRlZCwgaXQgd2lsbCBjaGVjayBlYWNoXG4gICAqIHBhcmFtZXRlciBpbmRlcGVuZGVudGx5LCBzdGFydGluZyB3aXRoIGVycm9yIGNvbnN0cnVjdG9yIHR5cGUuIFRoZSBhcHByb3ByaWF0ZSB3YXlcbiAgICogdG8gY2hlY2sgZm9yIHRoZSBleGlzdGVuY2Ugb2YgYSB0eXBlIG9mIGVycm9yIGJ1dCBmb3IgYSBtZXNzYWdlIHRoYXQgZG9lcyBub3QgbWF0Y2hcbiAgICogaXMgdG8gdXNlIGBhbmRgLlxuICAgKlxuICAgKiAgICAgZXhwZWN0KGZuKS50by50aHJvdyhSZWZlcmVuY2VFcnJvcilcbiAgICogICAgICAgIC5hbmQubm90LnRocm93KC9nb29kIGZ1bmN0aW9uLyk7XG4gICAqXG4gICAqIEBuYW1lIHRocm93XG4gICAqIEBhbGlhcyB0aHJvd3NcbiAgICogQGFsaWFzIFRocm93XG4gICAqIEBwYXJhbSB7RXJyb3JDb25zdHJ1Y3Rvcn0gY29uc3RydWN0b3JcbiAgICogQHBhcmFtIHtTdHJpbmd8UmVnRXhwfSBleHBlY3RlZCBlcnJvciBtZXNzYWdlXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlIF9vcHRpb25hbF9cbiAgICogQHNlZSBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9HbG9iYWxfT2JqZWN0cy9FcnJvciNFcnJvcl90eXBlc1xuICAgKiBAcmV0dXJucyBlcnJvciBmb3IgY2hhaW5pbmcgKG51bGwgaWYgbm8gZXJyb3IpXG4gICAqIEBuYW1lc3BhY2UgQkREXG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIGZ1bmN0aW9uIGFzc2VydFRocm93cyAoY29uc3RydWN0b3IsIGVyck1zZywgbXNnKSB7XG4gICAgaWYgKG1zZykgZmxhZyh0aGlzLCAnbWVzc2FnZScsIG1zZyk7XG4gICAgdmFyIG9iaiA9IGZsYWcodGhpcywgJ29iamVjdCcpO1xuICAgIG5ldyBBc3NlcnRpb24ob2JqLCBtc2cpLmlzLmEoJ2Z1bmN0aW9uJyk7XG5cbiAgICB2YXIgdGhyb3duID0gZmFsc2VcbiAgICAgICwgZGVzaXJlZEVycm9yID0gbnVsbFxuICAgICAgLCBuYW1lID0gbnVsbFxuICAgICAgLCB0aHJvd25FcnJvciA9IG51bGw7XG5cbiAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgZXJyTXNnID0gbnVsbDtcbiAgICAgIGNvbnN0cnVjdG9yID0gbnVsbDtcbiAgICB9IGVsc2UgaWYgKGNvbnN0cnVjdG9yICYmIChjb25zdHJ1Y3RvciBpbnN0YW5jZW9mIFJlZ0V4cCB8fCAnc3RyaW5nJyA9PT0gdHlwZW9mIGNvbnN0cnVjdG9yKSkge1xuICAgICAgZXJyTXNnID0gY29uc3RydWN0b3I7XG4gICAgICBjb25zdHJ1Y3RvciA9IG51bGw7XG4gICAgfSBlbHNlIGlmIChjb25zdHJ1Y3RvciAmJiBjb25zdHJ1Y3RvciBpbnN0YW5jZW9mIEVycm9yKSB7XG4gICAgICBkZXNpcmVkRXJyb3IgPSBjb25zdHJ1Y3RvcjtcbiAgICAgIGNvbnN0cnVjdG9yID0gbnVsbDtcbiAgICAgIGVyck1zZyA9IG51bGw7XG4gICAgfSBlbHNlIGlmICh0eXBlb2YgY29uc3RydWN0b3IgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgIG5hbWUgPSBjb25zdHJ1Y3Rvci5wcm90b3R5cGUubmFtZTtcbiAgICAgIGlmICghbmFtZSB8fCAobmFtZSA9PT0gJ0Vycm9yJyAmJiBjb25zdHJ1Y3RvciAhPT0gRXJyb3IpKSB7XG4gICAgICAgIG5hbWUgPSBjb25zdHJ1Y3Rvci5uYW1lIHx8IChuZXcgY29uc3RydWN0b3IoKSkubmFtZTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3RydWN0b3IgPSBudWxsO1xuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICBvYmooKTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIC8vIGZpcnN0LCBjaGVjayBkZXNpcmVkIGVycm9yXG4gICAgICBpZiAoZGVzaXJlZEVycm9yKSB7XG4gICAgICAgIHRoaXMuYXNzZXJ0KFxuICAgICAgICAgICAgZXJyID09PSBkZXNpcmVkRXJyb3JcbiAgICAgICAgICAsICdleHBlY3RlZCAje3RoaXN9IHRvIHRocm93ICN7ZXhwfSBidXQgI3thY3R9IHdhcyB0aHJvd24nXG4gICAgICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byBub3QgdGhyb3cgI3tleHB9J1xuICAgICAgICAgICwgKGRlc2lyZWRFcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZGVzaXJlZEVycm9yLnRvU3RyaW5nKCkgOiBkZXNpcmVkRXJyb3IpXG4gICAgICAgICAgLCAoZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIudG9TdHJpbmcoKSA6IGVycilcbiAgICAgICAgKTtcblxuICAgICAgICBmbGFnKHRoaXMsICdvYmplY3QnLCBlcnIpO1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgIH1cblxuICAgICAgLy8gbmV4dCwgY2hlY2sgY29uc3RydWN0b3JcbiAgICAgIGlmIChjb25zdHJ1Y3Rvcikge1xuICAgICAgICB0aGlzLmFzc2VydChcbiAgICAgICAgICAgIGVyciBpbnN0YW5jZW9mIGNvbnN0cnVjdG9yXG4gICAgICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byB0aHJvdyAje2V4cH0gYnV0ICN7YWN0fSB3YXMgdGhyb3duJ1xuICAgICAgICAgICwgJ2V4cGVjdGVkICN7dGhpc30gdG8gbm90IHRocm93ICN7ZXhwfSBidXQgI3thY3R9IHdhcyB0aHJvd24nXG4gICAgICAgICAgLCBuYW1lXG4gICAgICAgICAgLCAoZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIudG9TdHJpbmcoKSA6IGVycilcbiAgICAgICAgKTtcblxuICAgICAgICBpZiAoIWVyck1zZykge1xuICAgICAgICAgIGZsYWcodGhpcywgJ29iamVjdCcsIGVycik7XG4gICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gbmV4dCwgY2hlY2sgbWVzc2FnZVxuICAgICAgdmFyIG1lc3NhZ2UgPSAnZXJyb3InID09PSBfLnR5cGUoZXJyKSAmJiBcIm1lc3NhZ2VcIiBpbiBlcnJcbiAgICAgICAgPyBlcnIubWVzc2FnZVxuICAgICAgICA6ICcnICsgZXJyO1xuXG4gICAgICBpZiAoKG1lc3NhZ2UgIT0gbnVsbCkgJiYgZXJyTXNnICYmIGVyck1zZyBpbnN0YW5jZW9mIFJlZ0V4cCkge1xuICAgICAgICB0aGlzLmFzc2VydChcbiAgICAgICAgICAgIGVyck1zZy5leGVjKG1lc3NhZ2UpXG4gICAgICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byB0aHJvdyBlcnJvciBtYXRjaGluZyAje2V4cH0gYnV0IGdvdCAje2FjdH0nXG4gICAgICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byB0aHJvdyBlcnJvciBub3QgbWF0Y2hpbmcgI3tleHB9J1xuICAgICAgICAgICwgZXJyTXNnXG4gICAgICAgICAgLCBtZXNzYWdlXG4gICAgICAgICk7XG5cbiAgICAgICAgZmxhZyh0aGlzLCAnb2JqZWN0JywgZXJyKTtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICB9IGVsc2UgaWYgKChtZXNzYWdlICE9IG51bGwpICYmIGVyck1zZyAmJiAnc3RyaW5nJyA9PT0gdHlwZW9mIGVyck1zZykge1xuICAgICAgICB0aGlzLmFzc2VydChcbiAgICAgICAgICAgIH5tZXNzYWdlLmluZGV4T2YoZXJyTXNnKVxuICAgICAgICAgICwgJ2V4cGVjdGVkICN7dGhpc30gdG8gdGhyb3cgZXJyb3IgaW5jbHVkaW5nICN7ZXhwfSBidXQgZ290ICN7YWN0fSdcbiAgICAgICAgICAsICdleHBlY3RlZCAje3RoaXN9IHRvIHRocm93IGVycm9yIG5vdCBpbmNsdWRpbmcgI3thY3R9J1xuICAgICAgICAgICwgZXJyTXNnXG4gICAgICAgICAgLCBtZXNzYWdlXG4gICAgICAgICk7XG5cbiAgICAgICAgZmxhZyh0aGlzLCAnb2JqZWN0JywgZXJyKTtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvd24gPSB0cnVlO1xuICAgICAgICB0aHJvd25FcnJvciA9IGVycjtcbiAgICAgIH1cbiAgICB9XG5cbiAgICB2YXIgYWN0dWFsbHlHb3QgPSAnJ1xuICAgICAgLCBleHBlY3RlZFRocm93biA9IG5hbWUgIT09IG51bGxcbiAgICAgICAgPyBuYW1lXG4gICAgICAgIDogZGVzaXJlZEVycm9yXG4gICAgICAgICAgPyAnI3tleHB9JyAvL18uaW5zcGVjdChkZXNpcmVkRXJyb3IpXG4gICAgICAgICAgOiAnYW4gZXJyb3InO1xuXG4gICAgaWYgKHRocm93bikge1xuICAgICAgYWN0dWFsbHlHb3QgPSAnIGJ1dCAje2FjdH0gd2FzIHRocm93bidcbiAgICB9XG5cbiAgICB0aGlzLmFzc2VydChcbiAgICAgICAgdGhyb3duID09PSB0cnVlXG4gICAgICAsICdleHBlY3RlZCAje3RoaXN9IHRvIHRocm93ICcgKyBleHBlY3RlZFRocm93biArIGFjdHVhbGx5R290XG4gICAgICAsICdleHBlY3RlZCAje3RoaXN9IHRvIG5vdCB0aHJvdyAnICsgZXhwZWN0ZWRUaHJvd24gKyBhY3R1YWxseUdvdFxuICAgICAgLCAoZGVzaXJlZEVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBkZXNpcmVkRXJyb3IudG9TdHJpbmcoKSA6IGRlc2lyZWRFcnJvcilcbiAgICAgICwgKHRocm93bkVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyB0aHJvd25FcnJvci50b1N0cmluZygpIDogdGhyb3duRXJyb3IpXG4gICAgKTtcblxuICAgIGZsYWcodGhpcywgJ29iamVjdCcsIHRocm93bkVycm9yKTtcbiAgfTtcblxuICBBc3NlcnRpb24uYWRkTWV0aG9kKCd0aHJvdycsIGFzc2VydFRocm93cyk7XG4gIEFzc2VydGlvbi5hZGRNZXRob2QoJ3Rocm93cycsIGFzc2VydFRocm93cyk7XG4gIEFzc2VydGlvbi5hZGRNZXRob2QoJ1Rocm93JywgYXNzZXJ0VGhyb3dzKTtcblxuICAvKipcbiAgICogIyMjIC5yZXNwb25kVG8obWV0aG9kKVxuICAgKlxuICAgKiBBc3NlcnRzIHRoYXQgdGhlIG9iamVjdCBvciBjbGFzcyB0YXJnZXQgd2lsbCByZXNwb25kIHRvIGEgbWV0aG9kLlxuICAgKlxuICAgKiAgICAgS2xhc3MucHJvdG90eXBlLmJhciA9IGZ1bmN0aW9uKCl7fTtcbiAgICogICAgIGV4cGVjdChLbGFzcykudG8ucmVzcG9uZFRvKCdiYXInKTtcbiAgICogICAgIGV4cGVjdChvYmopLnRvLnJlc3BvbmRUbygnYmFyJyk7XG4gICAqXG4gICAqIFRvIGNoZWNrIGlmIGEgY29uc3RydWN0b3Igd2lsbCByZXNwb25kIHRvIGEgc3RhdGljIGZ1bmN0aW9uLFxuICAgKiBzZXQgdGhlIGBpdHNlbGZgIGZsYWcuXG4gICAqXG4gICAqICAgICBLbGFzcy5iYXogPSBmdW5jdGlvbigpe307XG4gICAqICAgICBleHBlY3QoS2xhc3MpLml0c2VsZi50by5yZXNwb25kVG8oJ2JheicpO1xuICAgKlxuICAgKiBAbmFtZSByZXNwb25kVG9cbiAgICogQGFsaWFzIHJlc3BvbmRzVG9cbiAgICogQHBhcmFtIHtTdHJpbmd9IG1ldGhvZFxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZSBfb3B0aW9uYWxfXG4gICAqIEBuYW1lc3BhY2UgQkREXG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIGZ1bmN0aW9uIHJlc3BvbmRUbyAobWV0aG9kLCBtc2cpIHtcbiAgICBpZiAobXNnKSBmbGFnKHRoaXMsICdtZXNzYWdlJywgbXNnKTtcbiAgICB2YXIgb2JqID0gZmxhZyh0aGlzLCAnb2JqZWN0JylcbiAgICAgICwgaXRzZWxmID0gZmxhZyh0aGlzLCAnaXRzZWxmJylcbiAgICAgICwgY29udGV4dCA9ICgnZnVuY3Rpb24nID09PSBfLnR5cGUob2JqKSAmJiAhaXRzZWxmKVxuICAgICAgICA/IG9iai5wcm90b3R5cGVbbWV0aG9kXVxuICAgICAgICA6IG9ialttZXRob2RdO1xuXG4gICAgdGhpcy5hc3NlcnQoXG4gICAgICAgICdmdW5jdGlvbicgPT09IHR5cGVvZiBjb250ZXh0XG4gICAgICAsICdleHBlY3RlZCAje3RoaXN9IHRvIHJlc3BvbmQgdG8gJyArIF8uaW5zcGVjdChtZXRob2QpXG4gICAgICAsICdleHBlY3RlZCAje3RoaXN9IHRvIG5vdCByZXNwb25kIHRvICcgKyBfLmluc3BlY3QobWV0aG9kKVxuICAgICk7XG4gIH1cblxuICBBc3NlcnRpb24uYWRkTWV0aG9kKCdyZXNwb25kVG8nLCByZXNwb25kVG8pO1xuICBBc3NlcnRpb24uYWRkTWV0aG9kKCdyZXNwb25kc1RvJywgcmVzcG9uZFRvKTtcblxuICAvKipcbiAgICogIyMjIC5pdHNlbGZcbiAgICpcbiAgICogU2V0cyB0aGUgYGl0c2VsZmAgZmxhZywgbGF0ZXIgdXNlZCBieSB0aGUgYHJlc3BvbmRUb2AgYXNzZXJ0aW9uLlxuICAgKlxuICAgKiAgICAgZnVuY3Rpb24gRm9vKCkge31cbiAgICogICAgIEZvby5iYXIgPSBmdW5jdGlvbigpIHt9XG4gICAqICAgICBGb28ucHJvdG90eXBlLmJheiA9IGZ1bmN0aW9uKCkge31cbiAgICpcbiAgICogICAgIGV4cGVjdChGb28pLml0c2VsZi50by5yZXNwb25kVG8oJ2JhcicpO1xuICAgKiAgICAgZXhwZWN0KEZvbykuaXRzZWxmLm5vdC50by5yZXNwb25kVG8oJ2JheicpO1xuICAgKlxuICAgKiBAbmFtZSBpdHNlbGZcbiAgICogQG5hbWVzcGFjZSBCRERcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgQXNzZXJ0aW9uLmFkZFByb3BlcnR5KCdpdHNlbGYnLCBmdW5jdGlvbiAoKSB7XG4gICAgZmxhZyh0aGlzLCAnaXRzZWxmJywgdHJ1ZSk7XG4gIH0pO1xuXG4gIC8qKlxuICAgKiAjIyMgLnNhdGlzZnkobWV0aG9kKVxuICAgKlxuICAgKiBBc3NlcnRzIHRoYXQgdGhlIHRhcmdldCBwYXNzZXMgYSBnaXZlbiB0cnV0aCB0ZXN0LlxuICAgKlxuICAgKiAgICAgZXhwZWN0KDEpLnRvLnNhdGlzZnkoZnVuY3Rpb24obnVtKSB7IHJldHVybiBudW0gPiAwOyB9KTtcbiAgICpcbiAgICogQG5hbWUgc2F0aXNmeVxuICAgKiBAYWxpYXMgc2F0aXNmaWVzXG4gICAqIEBwYXJhbSB7RnVuY3Rpb259IG1hdGNoZXJcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2UgX29wdGlvbmFsX1xuICAgKiBAbmFtZXNwYWNlIEJERFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBmdW5jdGlvbiBzYXRpc2Z5IChtYXRjaGVyLCBtc2cpIHtcbiAgICBpZiAobXNnKSBmbGFnKHRoaXMsICdtZXNzYWdlJywgbXNnKTtcbiAgICB2YXIgb2JqID0gZmxhZyh0aGlzLCAnb2JqZWN0Jyk7XG4gICAgdmFyIHJlc3VsdCA9IG1hdGNoZXIob2JqKTtcbiAgICB0aGlzLmFzc2VydChcbiAgICAgICAgcmVzdWx0XG4gICAgICAsICdleHBlY3RlZCAje3RoaXN9IHRvIHNhdGlzZnkgJyArIF8ub2JqRGlzcGxheShtYXRjaGVyKVxuICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byBub3Qgc2F0aXNmeScgKyBfLm9iakRpc3BsYXkobWF0Y2hlcilcbiAgICAgICwgdGhpcy5uZWdhdGUgPyBmYWxzZSA6IHRydWVcbiAgICAgICwgcmVzdWx0XG4gICAgKTtcbiAgfVxuXG4gIEFzc2VydGlvbi5hZGRNZXRob2QoJ3NhdGlzZnknLCBzYXRpc2Z5KTtcbiAgQXNzZXJ0aW9uLmFkZE1ldGhvZCgnc2F0aXNmaWVzJywgc2F0aXNmeSk7XG5cbiAgLyoqXG4gICAqICMjIyAuY2xvc2VUbyhleHBlY3RlZCwgZGVsdGEpXG4gICAqXG4gICAqIEFzc2VydHMgdGhhdCB0aGUgdGFyZ2V0IGlzIGVxdWFsIGBleHBlY3RlZGAsIHRvIHdpdGhpbiBhICsvLSBgZGVsdGFgIHJhbmdlLlxuICAgKlxuICAgKiAgICAgZXhwZWN0KDEuNSkudG8uYmUuY2xvc2VUbygxLCAwLjUpO1xuICAgKlxuICAgKiBAbmFtZSBjbG9zZVRvXG4gICAqIEBhbGlhcyBhcHByb3hpbWF0ZWx5XG4gICAqIEBwYXJhbSB7TnVtYmVyfSBleHBlY3RlZFxuICAgKiBAcGFyYW0ge051bWJlcn0gZGVsdGFcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2UgX29wdGlvbmFsX1xuICAgKiBAbmFtZXNwYWNlIEJERFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBmdW5jdGlvbiBjbG9zZVRvKGV4cGVjdGVkLCBkZWx0YSwgbXNnKSB7XG4gICAgaWYgKG1zZykgZmxhZyh0aGlzLCAnbWVzc2FnZScsIG1zZyk7XG4gICAgdmFyIG9iaiA9IGZsYWcodGhpcywgJ29iamVjdCcpO1xuXG4gICAgbmV3IEFzc2VydGlvbihvYmosIG1zZykuaXMuYSgnbnVtYmVyJyk7XG4gICAgaWYgKF8udHlwZShleHBlY3RlZCkgIT09ICdudW1iZXInIHx8IF8udHlwZShkZWx0YSkgIT09ICdudW1iZXInKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3RoZSBhcmd1bWVudHMgdG8gY2xvc2VUbyBvciBhcHByb3hpbWF0ZWx5IG11c3QgYmUgbnVtYmVycycpO1xuICAgIH1cblxuICAgIHRoaXMuYXNzZXJ0KFxuICAgICAgICBNYXRoLmFicyhvYmogLSBleHBlY3RlZCkgPD0gZGVsdGFcbiAgICAgICwgJ2V4cGVjdGVkICN7dGhpc30gdG8gYmUgY2xvc2UgdG8gJyArIGV4cGVjdGVkICsgJyArLy0gJyArIGRlbHRhXG4gICAgICAsICdleHBlY3RlZCAje3RoaXN9IG5vdCB0byBiZSBjbG9zZSB0byAnICsgZXhwZWN0ZWQgKyAnICsvLSAnICsgZGVsdGFcbiAgICApO1xuICB9XG5cbiAgQXNzZXJ0aW9uLmFkZE1ldGhvZCgnY2xvc2VUbycsIGNsb3NlVG8pO1xuICBBc3NlcnRpb24uYWRkTWV0aG9kKCdhcHByb3hpbWF0ZWx5JywgY2xvc2VUbyk7XG5cbiAgZnVuY3Rpb24gaXNTdWJzZXRPZihzdWJzZXQsIHN1cGVyc2V0LCBjbXApIHtcbiAgICByZXR1cm4gc3Vic2V0LmV2ZXJ5KGZ1bmN0aW9uKGVsZW0pIHtcbiAgICAgIGlmICghY21wKSByZXR1cm4gc3VwZXJzZXQuaW5kZXhPZihlbGVtKSAhPT0gLTE7XG5cbiAgICAgIHJldHVybiBzdXBlcnNldC5zb21lKGZ1bmN0aW9uKGVsZW0yKSB7XG4gICAgICAgIHJldHVybiBjbXAoZWxlbSwgZWxlbTIpO1xuICAgICAgfSk7XG4gICAgfSlcbiAgfVxuXG4gIC8qKlxuICAgKiAjIyMgLm1lbWJlcnMoc2V0KVxuICAgKlxuICAgKiBBc3NlcnRzIHRoYXQgdGhlIHRhcmdldCBpcyBhIHN1cGVyc2V0IG9mIGBzZXRgLFxuICAgKiBvciB0aGF0IHRoZSB0YXJnZXQgYW5kIGBzZXRgIGhhdmUgdGhlIHNhbWUgc3RyaWN0bHktZXF1YWwgKD09PSkgbWVtYmVycy5cbiAgICogQWx0ZXJuYXRlbHksIGlmIHRoZSBgZGVlcGAgZmxhZyBpcyBzZXQsIHNldCBtZW1iZXJzIGFyZSBjb21wYXJlZCBmb3IgZGVlcFxuICAgKiBlcXVhbGl0eS5cbiAgICpcbiAgICogICAgIGV4cGVjdChbMSwgMiwgM10pLnRvLmluY2x1ZGUubWVtYmVycyhbMywgMl0pO1xuICAgKiAgICAgZXhwZWN0KFsxLCAyLCAzXSkudG8ubm90LmluY2x1ZGUubWVtYmVycyhbMywgMiwgOF0pO1xuICAgKlxuICAgKiAgICAgZXhwZWN0KFs0LCAyXSkudG8uaGF2ZS5tZW1iZXJzKFsyLCA0XSk7XG4gICAqICAgICBleHBlY3QoWzUsIDJdKS50by5ub3QuaGF2ZS5tZW1iZXJzKFs1LCAyLCAxXSk7XG4gICAqXG4gICAqICAgICBleHBlY3QoW3sgaWQ6IDEgfV0pLnRvLmRlZXAuaW5jbHVkZS5tZW1iZXJzKFt7IGlkOiAxIH1dKTtcbiAgICpcbiAgICogQG5hbWUgbWVtYmVyc1xuICAgKiBAcGFyYW0ge0FycmF5fSBzZXRcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2UgX29wdGlvbmFsX1xuICAgKiBAbmFtZXNwYWNlIEJERFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBBc3NlcnRpb24uYWRkTWV0aG9kKCdtZW1iZXJzJywgZnVuY3Rpb24gKHN1YnNldCwgbXNnKSB7XG4gICAgaWYgKG1zZykgZmxhZyh0aGlzLCAnbWVzc2FnZScsIG1zZyk7XG4gICAgdmFyIG9iaiA9IGZsYWcodGhpcywgJ29iamVjdCcpO1xuXG4gICAgbmV3IEFzc2VydGlvbihvYmopLnRvLmJlLmFuKCdhcnJheScpO1xuICAgIG5ldyBBc3NlcnRpb24oc3Vic2V0KS50by5iZS5hbignYXJyYXknKTtcblxuICAgIHZhciBjbXAgPSBmbGFnKHRoaXMsICdkZWVwJykgPyBfLmVxbCA6IHVuZGVmaW5lZDtcblxuICAgIGlmIChmbGFnKHRoaXMsICdjb250YWlucycpKSB7XG4gICAgICByZXR1cm4gdGhpcy5hc3NlcnQoXG4gICAgICAgICAgaXNTdWJzZXRPZihzdWJzZXQsIG9iaiwgY21wKVxuICAgICAgICAsICdleHBlY3RlZCAje3RoaXN9IHRvIGJlIGEgc3VwZXJzZXQgb2YgI3thY3R9J1xuICAgICAgICAsICdleHBlY3RlZCAje3RoaXN9IHRvIG5vdCBiZSBhIHN1cGVyc2V0IG9mICN7YWN0fSdcbiAgICAgICAgLCBvYmpcbiAgICAgICAgLCBzdWJzZXRcbiAgICAgICk7XG4gICAgfVxuXG4gICAgdGhpcy5hc3NlcnQoXG4gICAgICAgIGlzU3Vic2V0T2Yob2JqLCBzdWJzZXQsIGNtcCkgJiYgaXNTdWJzZXRPZihzdWJzZXQsIG9iaiwgY21wKVxuICAgICAgICAsICdleHBlY3RlZCAje3RoaXN9IHRvIGhhdmUgdGhlIHNhbWUgbWVtYmVycyBhcyAje2FjdH0nXG4gICAgICAgICwgJ2V4cGVjdGVkICN7dGhpc30gdG8gbm90IGhhdmUgdGhlIHNhbWUgbWVtYmVycyBhcyAje2FjdH0nXG4gICAgICAgICwgb2JqXG4gICAgICAgICwgc3Vic2V0XG4gICAgKTtcbiAgfSk7XG5cbiAgLyoqXG4gICAqICMjIyAub25lT2YobGlzdClcbiAgICpcbiAgICogQXNzZXJ0IHRoYXQgYSB2YWx1ZSBhcHBlYXJzIHNvbWV3aGVyZSBpbiB0aGUgdG9wIGxldmVsIG9mIGFycmF5IGBsaXN0YC5cbiAgICpcbiAgICogICAgIGV4cGVjdCgnYScpLnRvLmJlLm9uZU9mKFsnYScsICdiJywgJ2MnXSk7XG4gICAqICAgICBleHBlY3QoOSkudG8ubm90LmJlLm9uZU9mKFsneiddKTtcbiAgICogICAgIGV4cGVjdChbM10pLnRvLm5vdC5iZS5vbmVPZihbMSwgMiwgWzNdXSk7XG4gICAqXG4gICAqICAgICB2YXIgdGhyZWUgPSBbM107XG4gICAqICAgICAvLyBmb3Igb2JqZWN0LXR5cGVzLCBjb250ZW50cyBhcmUgbm90IGNvbXBhcmVkXG4gICAqICAgICBleHBlY3QodGhyZWUpLnRvLm5vdC5iZS5vbmVPZihbMSwgMiwgWzNdXSk7XG4gICAqICAgICAvLyBjb21wYXJpbmcgcmVmZXJlbmNlcyB3b3Jrc1xuICAgKiAgICAgZXhwZWN0KHRocmVlKS50by5iZS5vbmVPZihbMSwgMiwgdGhyZWVdKTtcbiAgICpcbiAgICogQG5hbWUgb25lT2ZcbiAgICogQHBhcmFtIHtBcnJheTwqPn0gbGlzdFxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZSBfb3B0aW9uYWxfXG4gICAqIEBuYW1lc3BhY2UgQkREXG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIGZ1bmN0aW9uIG9uZU9mIChsaXN0LCBtc2cpIHtcbiAgICBpZiAobXNnKSBmbGFnKHRoaXMsICdtZXNzYWdlJywgbXNnKTtcbiAgICB2YXIgZXhwZWN0ZWQgPSBmbGFnKHRoaXMsICdvYmplY3QnKTtcbiAgICBuZXcgQXNzZXJ0aW9uKGxpc3QpLnRvLmJlLmFuKCdhcnJheScpO1xuXG4gICAgdGhpcy5hc3NlcnQoXG4gICAgICAgIGxpc3QuaW5kZXhPZihleHBlY3RlZCkgPiAtMVxuICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byBiZSBvbmUgb2YgI3tleHB9J1xuICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byBub3QgYmUgb25lIG9mICN7ZXhwfSdcbiAgICAgICwgbGlzdFxuICAgICAgLCBleHBlY3RlZFxuICAgICk7XG4gIH1cblxuICBBc3NlcnRpb24uYWRkTWV0aG9kKCdvbmVPZicsIG9uZU9mKTtcblxuXG4gIC8qKlxuICAgKiAjIyMgLmNoYW5nZShmdW5jdGlvbilcbiAgICpcbiAgICogQXNzZXJ0cyB0aGF0IGEgZnVuY3Rpb24gY2hhbmdlcyBhbiBvYmplY3QgcHJvcGVydHlcbiAgICpcbiAgICogICAgIHZhciBvYmogPSB7IHZhbDogMTAgfTtcbiAgICogICAgIHZhciBmbiA9IGZ1bmN0aW9uKCkgeyBvYmoudmFsICs9IDMgfTtcbiAgICogICAgIHZhciBub0NoYW5nZUZuID0gZnVuY3Rpb24oKSB7IHJldHVybiAnZm9vJyArICdiYXInOyB9XG4gICAqICAgICBleHBlY3QoZm4pLnRvLmNoYW5nZShvYmosICd2YWwnKTtcbiAgICogICAgIGV4cGVjdChub0NoYW5nZUZuKS50by5ub3QuY2hhbmdlKG9iaiwgJ3ZhbCcpXG4gICAqXG4gICAqIEBuYW1lIGNoYW5nZVxuICAgKiBAYWxpYXMgY2hhbmdlc1xuICAgKiBAYWxpYXMgQ2hhbmdlXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBvYmplY3RcbiAgICogQHBhcmFtIHtTdHJpbmd9IHByb3BlcnR5IG5hbWVcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2UgX29wdGlvbmFsX1xuICAgKiBAbmFtZXNwYWNlIEJERFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBmdW5jdGlvbiBhc3NlcnRDaGFuZ2VzIChvYmplY3QsIHByb3AsIG1zZykge1xuICAgIGlmIChtc2cpIGZsYWcodGhpcywgJ21lc3NhZ2UnLCBtc2cpO1xuICAgIHZhciBmbiA9IGZsYWcodGhpcywgJ29iamVjdCcpO1xuICAgIG5ldyBBc3NlcnRpb24ob2JqZWN0LCBtc2cpLnRvLmhhdmUucHJvcGVydHkocHJvcCk7XG4gICAgbmV3IEFzc2VydGlvbihmbikuaXMuYSgnZnVuY3Rpb24nKTtcblxuICAgIHZhciBpbml0aWFsID0gb2JqZWN0W3Byb3BdO1xuICAgIGZuKCk7XG5cbiAgICB0aGlzLmFzc2VydChcbiAgICAgIGluaXRpYWwgIT09IG9iamVjdFtwcm9wXVxuICAgICAgLCAnZXhwZWN0ZWQgLicgKyBwcm9wICsgJyB0byBjaGFuZ2UnXG4gICAgICAsICdleHBlY3RlZCAuJyArIHByb3AgKyAnIHRvIG5vdCBjaGFuZ2UnXG4gICAgKTtcbiAgfVxuXG4gIEFzc2VydGlvbi5hZGRDaGFpbmFibGVNZXRob2QoJ2NoYW5nZScsIGFzc2VydENoYW5nZXMpO1xuICBBc3NlcnRpb24uYWRkQ2hhaW5hYmxlTWV0aG9kKCdjaGFuZ2VzJywgYXNzZXJ0Q2hhbmdlcyk7XG5cbiAgLyoqXG4gICAqICMjIyAuaW5jcmVhc2UoZnVuY3Rpb24pXG4gICAqXG4gICAqIEFzc2VydHMgdGhhdCBhIGZ1bmN0aW9uIGluY3JlYXNlcyBhbiBvYmplY3QgcHJvcGVydHlcbiAgICpcbiAgICogICAgIHZhciBvYmogPSB7IHZhbDogMTAgfTtcbiAgICogICAgIHZhciBmbiA9IGZ1bmN0aW9uKCkgeyBvYmoudmFsID0gMTUgfTtcbiAgICogICAgIGV4cGVjdChmbikudG8uaW5jcmVhc2Uob2JqLCAndmFsJyk7XG4gICAqXG4gICAqIEBuYW1lIGluY3JlYXNlXG4gICAqIEBhbGlhcyBpbmNyZWFzZXNcbiAgICogQGFsaWFzIEluY3JlYXNlXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBvYmplY3RcbiAgICogQHBhcmFtIHtTdHJpbmd9IHByb3BlcnR5IG5hbWVcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2UgX29wdGlvbmFsX1xuICAgKiBAbmFtZXNwYWNlIEJERFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBmdW5jdGlvbiBhc3NlcnRJbmNyZWFzZXMgKG9iamVjdCwgcHJvcCwgbXNnKSB7XG4gICAgaWYgKG1zZykgZmxhZyh0aGlzLCAnbWVzc2FnZScsIG1zZyk7XG4gICAgdmFyIGZuID0gZmxhZyh0aGlzLCAnb2JqZWN0Jyk7XG4gICAgbmV3IEFzc2VydGlvbihvYmplY3QsIG1zZykudG8uaGF2ZS5wcm9wZXJ0eShwcm9wKTtcbiAgICBuZXcgQXNzZXJ0aW9uKGZuKS5pcy5hKCdmdW5jdGlvbicpO1xuXG4gICAgdmFyIGluaXRpYWwgPSBvYmplY3RbcHJvcF07XG4gICAgZm4oKTtcblxuICAgIHRoaXMuYXNzZXJ0KFxuICAgICAgb2JqZWN0W3Byb3BdIC0gaW5pdGlhbCA+IDBcbiAgICAgICwgJ2V4cGVjdGVkIC4nICsgcHJvcCArICcgdG8gaW5jcmVhc2UnXG4gICAgICAsICdleHBlY3RlZCAuJyArIHByb3AgKyAnIHRvIG5vdCBpbmNyZWFzZSdcbiAgICApO1xuICB9XG5cbiAgQXNzZXJ0aW9uLmFkZENoYWluYWJsZU1ldGhvZCgnaW5jcmVhc2UnLCBhc3NlcnRJbmNyZWFzZXMpO1xuICBBc3NlcnRpb24uYWRkQ2hhaW5hYmxlTWV0aG9kKCdpbmNyZWFzZXMnLCBhc3NlcnRJbmNyZWFzZXMpO1xuXG4gIC8qKlxuICAgKiAjIyMgLmRlY3JlYXNlKGZ1bmN0aW9uKVxuICAgKlxuICAgKiBBc3NlcnRzIHRoYXQgYSBmdW5jdGlvbiBkZWNyZWFzZXMgYW4gb2JqZWN0IHByb3BlcnR5XG4gICAqXG4gICAqICAgICB2YXIgb2JqID0geyB2YWw6IDEwIH07XG4gICAqICAgICB2YXIgZm4gPSBmdW5jdGlvbigpIHsgb2JqLnZhbCA9IDUgfTtcbiAgICogICAgIGV4cGVjdChmbikudG8uZGVjcmVhc2Uob2JqLCAndmFsJyk7XG4gICAqXG4gICAqIEBuYW1lIGRlY3JlYXNlXG4gICAqIEBhbGlhcyBkZWNyZWFzZXNcbiAgICogQGFsaWFzIERlY3JlYXNlXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBvYmplY3RcbiAgICogQHBhcmFtIHtTdHJpbmd9IHByb3BlcnR5IG5hbWVcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2UgX29wdGlvbmFsX1xuICAgKiBAbmFtZXNwYWNlIEJERFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBmdW5jdGlvbiBhc3NlcnREZWNyZWFzZXMgKG9iamVjdCwgcHJvcCwgbXNnKSB7XG4gICAgaWYgKG1zZykgZmxhZyh0aGlzLCAnbWVzc2FnZScsIG1zZyk7XG4gICAgdmFyIGZuID0gZmxhZyh0aGlzLCAnb2JqZWN0Jyk7XG4gICAgbmV3IEFzc2VydGlvbihvYmplY3QsIG1zZykudG8uaGF2ZS5wcm9wZXJ0eShwcm9wKTtcbiAgICBuZXcgQXNzZXJ0aW9uKGZuKS5pcy5hKCdmdW5jdGlvbicpO1xuXG4gICAgdmFyIGluaXRpYWwgPSBvYmplY3RbcHJvcF07XG4gICAgZm4oKTtcblxuICAgIHRoaXMuYXNzZXJ0KFxuICAgICAgb2JqZWN0W3Byb3BdIC0gaW5pdGlhbCA8IDBcbiAgICAgICwgJ2V4cGVjdGVkIC4nICsgcHJvcCArICcgdG8gZGVjcmVhc2UnXG4gICAgICAsICdleHBlY3RlZCAuJyArIHByb3AgKyAnIHRvIG5vdCBkZWNyZWFzZSdcbiAgICApO1xuICB9XG5cbiAgQXNzZXJ0aW9uLmFkZENoYWluYWJsZU1ldGhvZCgnZGVjcmVhc2UnLCBhc3NlcnREZWNyZWFzZXMpO1xuICBBc3NlcnRpb24uYWRkQ2hhaW5hYmxlTWV0aG9kKCdkZWNyZWFzZXMnLCBhc3NlcnREZWNyZWFzZXMpO1xuXG4gIC8qKlxuICAgKiAjIyMgLmV4dGVuc2libGVcbiAgICpcbiAgICogQXNzZXJ0cyB0aGF0IHRoZSB0YXJnZXQgaXMgZXh0ZW5zaWJsZSAoY2FuIGhhdmUgbmV3IHByb3BlcnRpZXMgYWRkZWQgdG9cbiAgICogaXQpLlxuICAgKlxuICAgKiAgICAgdmFyIG5vbkV4dGVuc2libGVPYmplY3QgPSBPYmplY3QucHJldmVudEV4dGVuc2lvbnMoe30pO1xuICAgKiAgICAgdmFyIHNlYWxlZE9iamVjdCA9IE9iamVjdC5zZWFsKHt9KTtcbiAgICogICAgIHZhciBmcm96ZW5PYmplY3QgPSBPYmplY3QuZnJlZXplKHt9KTtcbiAgICpcbiAgICogICAgIGV4cGVjdCh7fSkudG8uYmUuZXh0ZW5zaWJsZTtcbiAgICogICAgIGV4cGVjdChub25FeHRlbnNpYmxlT2JqZWN0KS50by5ub3QuYmUuZXh0ZW5zaWJsZTtcbiAgICogICAgIGV4cGVjdChzZWFsZWRPYmplY3QpLnRvLm5vdC5iZS5leHRlbnNpYmxlO1xuICAgKiAgICAgZXhwZWN0KGZyb3plbk9iamVjdCkudG8ubm90LmJlLmV4dGVuc2libGU7XG4gICAqXG4gICAqIEBuYW1lIGV4dGVuc2libGVcbiAgICogQG5hbWVzcGFjZSBCRERcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgQXNzZXJ0aW9uLmFkZFByb3BlcnR5KCdleHRlbnNpYmxlJywgZnVuY3Rpb24oKSB7XG4gICAgdmFyIG9iaiA9IGZsYWcodGhpcywgJ29iamVjdCcpO1xuXG4gICAgLy8gSW4gRVM1LCBpZiB0aGUgYXJndW1lbnQgdG8gdGhpcyBtZXRob2QgaXMgbm90IGFuIG9iamVjdCAoYSBwcmltaXRpdmUpLCB0aGVuIGl0IHdpbGwgY2F1c2UgYSBUeXBlRXJyb3IuXG4gICAgLy8gSW4gRVM2LCBhIG5vbi1vYmplY3QgYXJndW1lbnQgd2lsbCBiZSB0cmVhdGVkIGFzIGlmIGl0IHdhcyBhIG5vbi1leHRlbnNpYmxlIG9yZGluYXJ5IG9iamVjdCwgc2ltcGx5IHJldHVybiBmYWxzZS5cbiAgICAvLyBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9HbG9iYWxfT2JqZWN0cy9PYmplY3QvaXNFeHRlbnNpYmxlXG4gICAgLy8gVGhlIGZvbGxvd2luZyBwcm92aWRlcyBFUzYgYmVoYXZpb3Igd2hlbiBhIFR5cGVFcnJvciBpcyB0aHJvd24gdW5kZXIgRVM1LlxuXG4gICAgdmFyIGlzRXh0ZW5zaWJsZTtcblxuICAgIHRyeSB7XG4gICAgICBpc0V4dGVuc2libGUgPSBPYmplY3QuaXNFeHRlbnNpYmxlKG9iaik7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBpZiAoZXJyIGluc3RhbmNlb2YgVHlwZUVycm9yKSBpc0V4dGVuc2libGUgPSBmYWxzZTtcbiAgICAgIGVsc2UgdGhyb3cgZXJyO1xuICAgIH1cblxuICAgIHRoaXMuYXNzZXJ0KFxuICAgICAgaXNFeHRlbnNpYmxlXG4gICAgICAsICdleHBlY3RlZCAje3RoaXN9IHRvIGJlIGV4dGVuc2libGUnXG4gICAgICAsICdleHBlY3RlZCAje3RoaXN9IHRvIG5vdCBiZSBleHRlbnNpYmxlJ1xuICAgICk7XG4gIH0pO1xuXG4gIC8qKlxuICAgKiAjIyMgLnNlYWxlZFxuICAgKlxuICAgKiBBc3NlcnRzIHRoYXQgdGhlIHRhcmdldCBpcyBzZWFsZWQgKGNhbm5vdCBoYXZlIG5ldyBwcm9wZXJ0aWVzIGFkZGVkIHRvIGl0XG4gICAqIGFuZCBpdHMgZXhpc3RpbmcgcHJvcGVydGllcyBjYW5ub3QgYmUgcmVtb3ZlZCkuXG4gICAqXG4gICAqICAgICB2YXIgc2VhbGVkT2JqZWN0ID0gT2JqZWN0LnNlYWwoe30pO1xuICAgKiAgICAgdmFyIGZyb3plbk9iamVjdCA9IE9iamVjdC5mcmVlemUoe30pO1xuICAgKlxuICAgKiAgICAgZXhwZWN0KHNlYWxlZE9iamVjdCkudG8uYmUuc2VhbGVkO1xuICAgKiAgICAgZXhwZWN0KGZyb3plbk9iamVjdCkudG8uYmUuc2VhbGVkO1xuICAgKiAgICAgZXhwZWN0KHt9KS50by5ub3QuYmUuc2VhbGVkO1xuICAgKlxuICAgKiBAbmFtZSBzZWFsZWRcbiAgICogQG5hbWVzcGFjZSBCRERcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgQXNzZXJ0aW9uLmFkZFByb3BlcnR5KCdzZWFsZWQnLCBmdW5jdGlvbigpIHtcbiAgICB2YXIgb2JqID0gZmxhZyh0aGlzLCAnb2JqZWN0Jyk7XG5cbiAgICAvLyBJbiBFUzUsIGlmIHRoZSBhcmd1bWVudCB0byB0aGlzIG1ldGhvZCBpcyBub3QgYW4gb2JqZWN0IChhIHByaW1pdGl2ZSksIHRoZW4gaXQgd2lsbCBjYXVzZSBhIFR5cGVFcnJvci5cbiAgICAvLyBJbiBFUzYsIGEgbm9uLW9iamVjdCBhcmd1bWVudCB3aWxsIGJlIHRyZWF0ZWQgYXMgaWYgaXQgd2FzIGEgc2VhbGVkIG9yZGluYXJ5IG9iamVjdCwgc2ltcGx5IHJldHVybiB0cnVlLlxuICAgIC8vIFNlZSBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9HbG9iYWxfT2JqZWN0cy9PYmplY3QvaXNTZWFsZWRcbiAgICAvLyBUaGUgZm9sbG93aW5nIHByb3ZpZGVzIEVTNiBiZWhhdmlvciB3aGVuIGEgVHlwZUVycm9yIGlzIHRocm93biB1bmRlciBFUzUuXG5cbiAgICB2YXIgaXNTZWFsZWQ7XG5cbiAgICB0cnkge1xuICAgICAgaXNTZWFsZWQgPSBPYmplY3QuaXNTZWFsZWQob2JqKTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGlmIChlcnIgaW5zdGFuY2VvZiBUeXBlRXJyb3IpIGlzU2VhbGVkID0gdHJ1ZTtcbiAgICAgIGVsc2UgdGhyb3cgZXJyO1xuICAgIH1cblxuICAgIHRoaXMuYXNzZXJ0KFxuICAgICAgaXNTZWFsZWRcbiAgICAgICwgJ2V4cGVjdGVkICN7dGhpc30gdG8gYmUgc2VhbGVkJ1xuICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byBub3QgYmUgc2VhbGVkJ1xuICAgICk7XG4gIH0pO1xuXG4gIC8qKlxuICAgKiAjIyMgLmZyb3plblxuICAgKlxuICAgKiBBc3NlcnRzIHRoYXQgdGhlIHRhcmdldCBpcyBmcm96ZW4gKGNhbm5vdCBoYXZlIG5ldyBwcm9wZXJ0aWVzIGFkZGVkIHRvIGl0XG4gICAqIGFuZCBpdHMgZXhpc3RpbmcgcHJvcGVydGllcyBjYW5ub3QgYmUgbW9kaWZpZWQpLlxuICAgKlxuICAgKiAgICAgdmFyIGZyb3plbk9iamVjdCA9IE9iamVjdC5mcmVlemUoe30pO1xuICAgKlxuICAgKiAgICAgZXhwZWN0KGZyb3plbk9iamVjdCkudG8uYmUuZnJvemVuO1xuICAgKiAgICAgZXhwZWN0KHt9KS50by5ub3QuYmUuZnJvemVuO1xuICAgKlxuICAgKiBAbmFtZSBmcm96ZW5cbiAgICogQG5hbWVzcGFjZSBCRERcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgQXNzZXJ0aW9uLmFkZFByb3BlcnR5KCdmcm96ZW4nLCBmdW5jdGlvbigpIHtcbiAgICB2YXIgb2JqID0gZmxhZyh0aGlzLCAnb2JqZWN0Jyk7XG5cbiAgICAvLyBJbiBFUzUsIGlmIHRoZSBhcmd1bWVudCB0byB0aGlzIG1ldGhvZCBpcyBub3QgYW4gb2JqZWN0IChhIHByaW1pdGl2ZSksIHRoZW4gaXQgd2lsbCBjYXVzZSBhIFR5cGVFcnJvci5cbiAgICAvLyBJbiBFUzYsIGEgbm9uLW9iamVjdCBhcmd1bWVudCB3aWxsIGJlIHRyZWF0ZWQgYXMgaWYgaXQgd2FzIGEgZnJvemVuIG9yZGluYXJ5IG9iamVjdCwgc2ltcGx5IHJldHVybiB0cnVlLlxuICAgIC8vIFNlZSBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9HbG9iYWxfT2JqZWN0cy9PYmplY3QvaXNGcm96ZW5cbiAgICAvLyBUaGUgZm9sbG93aW5nIHByb3ZpZGVzIEVTNiBiZWhhdmlvciB3aGVuIGEgVHlwZUVycm9yIGlzIHRocm93biB1bmRlciBFUzUuXG5cbiAgICB2YXIgaXNGcm96ZW47XG5cbiAgICB0cnkge1xuICAgICAgaXNGcm96ZW4gPSBPYmplY3QuaXNGcm96ZW4ob2JqKTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGlmIChlcnIgaW5zdGFuY2VvZiBUeXBlRXJyb3IpIGlzRnJvemVuID0gdHJ1ZTtcbiAgICAgIGVsc2UgdGhyb3cgZXJyO1xuICAgIH1cblxuICAgIHRoaXMuYXNzZXJ0KFxuICAgICAgaXNGcm96ZW5cbiAgICAgICwgJ2V4cGVjdGVkICN7dGhpc30gdG8gYmUgZnJvemVuJ1xuICAgICAgLCAnZXhwZWN0ZWQgI3t0aGlzfSB0byBub3QgYmUgZnJvemVuJ1xuICAgICk7XG4gIH0pO1xufTtcbiIsIi8qIVxuICogY2hhaVxuICogQ29weXJpZ2h0KGMpIDIwMTEtMjAxNCBKYWtlIEx1ZXIgPGpha2VAYWxvZ2ljYWxwYXJhZG94LmNvbT5cbiAqIE1JVCBMaWNlbnNlZFxuICovXG5cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY2hhaSwgdXRpbCkge1xuXG4gIC8qIVxuICAgKiBDaGFpIGRlcGVuZGVuY2llcy5cbiAgICovXG5cbiAgdmFyIEFzc2VydGlvbiA9IGNoYWkuQXNzZXJ0aW9uXG4gICAgLCBmbGFnID0gdXRpbC5mbGFnO1xuXG4gIC8qIVxuICAgKiBNb2R1bGUgZXhwb3J0LlxuICAgKi9cblxuICAvKipcbiAgICogIyMjIGFzc2VydChleHByZXNzaW9uLCBtZXNzYWdlKVxuICAgKlxuICAgKiBXcml0ZSB5b3VyIG93biB0ZXN0IGV4cHJlc3Npb25zLlxuICAgKlxuICAgKiAgICAgYXNzZXJ0KCdmb28nICE9PSAnYmFyJywgJ2ZvbyBpcyBub3QgYmFyJyk7XG4gICAqICAgICBhc3NlcnQoQXJyYXkuaXNBcnJheShbXSksICdlbXB0eSBhcnJheXMgYXJlIGFycmF5cycpO1xuICAgKlxuICAgKiBAcGFyYW0ge01peGVkfSBleHByZXNzaW9uIHRvIHRlc3QgZm9yIHRydXRoaW5lc3NcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2UgdG8gZGlzcGxheSBvbiBlcnJvclxuICAgKiBAbmFtZSBhc3NlcnRcbiAgICogQG5hbWVzcGFjZSBBc3NlcnRcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgdmFyIGFzc2VydCA9IGNoYWkuYXNzZXJ0ID0gZnVuY3Rpb24gKGV4cHJlc3MsIGVycm1zZykge1xuICAgIHZhciB0ZXN0ID0gbmV3IEFzc2VydGlvbihudWxsLCBudWxsLCBjaGFpLmFzc2VydCk7XG4gICAgdGVzdC5hc3NlcnQoXG4gICAgICAgIGV4cHJlc3NcbiAgICAgICwgZXJybXNnXG4gICAgICAsICdbIG5lZ2F0aW9uIG1lc3NhZ2UgdW5hdmFpbGFibGUgXSdcbiAgICApO1xuICB9O1xuXG4gIC8qKlxuICAgKiAjIyMgLmZhaWwoYWN0dWFsLCBleHBlY3RlZCwgW21lc3NhZ2VdLCBbb3BlcmF0b3JdKVxuICAgKlxuICAgKiBUaHJvdyBhIGZhaWx1cmUuIE5vZGUuanMgYGFzc2VydGAgbW9kdWxlLWNvbXBhdGlibGUuXG4gICAqXG4gICAqIEBuYW1lIGZhaWxcbiAgICogQHBhcmFtIHtNaXhlZH0gYWN0dWFsXG4gICAqIEBwYXJhbSB7TWl4ZWR9IGV4cGVjdGVkXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBvcGVyYXRvclxuICAgKiBAbmFtZXNwYWNlIEFzc2VydFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBhc3NlcnQuZmFpbCA9IGZ1bmN0aW9uIChhY3R1YWwsIGV4cGVjdGVkLCBtZXNzYWdlLCBvcGVyYXRvcikge1xuICAgIG1lc3NhZ2UgPSBtZXNzYWdlIHx8ICdhc3NlcnQuZmFpbCgpJztcbiAgICB0aHJvdyBuZXcgY2hhaS5Bc3NlcnRpb25FcnJvcihtZXNzYWdlLCB7XG4gICAgICAgIGFjdHVhbDogYWN0dWFsXG4gICAgICAsIGV4cGVjdGVkOiBleHBlY3RlZFxuICAgICAgLCBvcGVyYXRvcjogb3BlcmF0b3JcbiAgICB9LCBhc3NlcnQuZmFpbCk7XG4gIH07XG5cbiAgLyoqXG4gICAqICMjIyAuaXNPayhvYmplY3QsIFttZXNzYWdlXSlcbiAgICpcbiAgICogQXNzZXJ0cyB0aGF0IGBvYmplY3RgIGlzIHRydXRoeS5cbiAgICpcbiAgICogICAgIGFzc2VydC5pc09rKCdldmVyeXRoaW5nJywgJ2V2ZXJ5dGhpbmcgaXMgb2snKTtcbiAgICogICAgIGFzc2VydC5pc09rKGZhbHNlLCAndGhpcyB3aWxsIGZhaWwnKTtcbiAgICpcbiAgICogQG5hbWUgaXNPa1xuICAgKiBAYWxpYXMgb2tcbiAgICogQHBhcmFtIHtNaXhlZH0gb2JqZWN0IHRvIHRlc3RcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2VcbiAgICogQG5hbWVzcGFjZSBBc3NlcnRcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgYXNzZXJ0LmlzT2sgPSBmdW5jdGlvbiAodmFsLCBtc2cpIHtcbiAgICBuZXcgQXNzZXJ0aW9uKHZhbCwgbXNnKS5pcy5vaztcbiAgfTtcblxuICAvKipcbiAgICogIyMjIC5pc05vdE9rKG9iamVjdCwgW21lc3NhZ2VdKVxuICAgKlxuICAgKiBBc3NlcnRzIHRoYXQgYG9iamVjdGAgaXMgZmFsc3kuXG4gICAqXG4gICAqICAgICBhc3NlcnQuaXNOb3RPaygnZXZlcnl0aGluZycsICd0aGlzIHdpbGwgZmFpbCcpO1xuICAgKiAgICAgYXNzZXJ0LmlzTm90T2soZmFsc2UsICd0aGlzIHdpbGwgcGFzcycpO1xuICAgKlxuICAgKiBAbmFtZSBpc05vdE9rXG4gICAqIEBhbGlhcyBub3RPa1xuICAgKiBAcGFyYW0ge01peGVkfSBvYmplY3QgdG8gdGVzdFxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZVxuICAgKiBAbmFtZXNwYWNlIEFzc2VydFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBhc3NlcnQuaXNOb3RPayA9IGZ1bmN0aW9uICh2YWwsIG1zZykge1xuICAgIG5ldyBBc3NlcnRpb24odmFsLCBtc2cpLmlzLm5vdC5vaztcbiAgfTtcblxuICAvKipcbiAgICogIyMjIC5lcXVhbChhY3R1YWwsIGV4cGVjdGVkLCBbbWVzc2FnZV0pXG4gICAqXG4gICAqIEFzc2VydHMgbm9uLXN0cmljdCBlcXVhbGl0eSAoYD09YCkgb2YgYGFjdHVhbGAgYW5kIGBleHBlY3RlZGAuXG4gICAqXG4gICAqICAgICBhc3NlcnQuZXF1YWwoMywgJzMnLCAnPT0gY29lcmNlcyB2YWx1ZXMgdG8gc3RyaW5ncycpO1xuICAgKlxuICAgKiBAbmFtZSBlcXVhbFxuICAgKiBAcGFyYW0ge01peGVkfSBhY3R1YWxcbiAgICogQHBhcmFtIHtNaXhlZH0gZXhwZWN0ZWRcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2VcbiAgICogQG5hbWVzcGFjZSBBc3NlcnRcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgYXNzZXJ0LmVxdWFsID0gZnVuY3Rpb24gKGFjdCwgZXhwLCBtc2cpIHtcbiAgICB2YXIgdGVzdCA9IG5ldyBBc3NlcnRpb24oYWN0LCBtc2csIGFzc2VydC5lcXVhbCk7XG5cbiAgICB0ZXN0LmFzc2VydChcbiAgICAgICAgZXhwID09IGZsYWcodGVzdCwgJ29iamVjdCcpXG4gICAgICAsICdleHBlY3RlZCAje3RoaXN9IHRvIGVxdWFsICN7ZXhwfSdcbiAgICAgICwgJ2V4cGVjdGVkICN7dGhpc30gdG8gbm90IGVxdWFsICN7YWN0fSdcbiAgICAgICwgZXhwXG4gICAgICAsIGFjdFxuICAgICk7XG4gIH07XG5cbiAgLyoqXG4gICAqICMjIyAubm90RXF1YWwoYWN0dWFsLCBleHBlY3RlZCwgW21lc3NhZ2VdKVxuICAgKlxuICAgKiBBc3NlcnRzIG5vbi1zdHJpY3QgaW5lcXVhbGl0eSAoYCE9YCkgb2YgYGFjdHVhbGAgYW5kIGBleHBlY3RlZGAuXG4gICAqXG4gICAqICAgICBhc3NlcnQubm90RXF1YWwoMywgNCwgJ3RoZXNlIG51bWJlcnMgYXJlIG5vdCBlcXVhbCcpO1xuICAgKlxuICAgKiBAbmFtZSBub3RFcXVhbFxuICAgKiBAcGFyYW0ge01peGVkfSBhY3R1YWxcbiAgICogQHBhcmFtIHtNaXhlZH0gZXhwZWN0ZWRcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2VcbiAgICogQG5hbWVzcGFjZSBBc3NlcnRcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgYXNzZXJ0Lm5vdEVxdWFsID0gZnVuY3Rpb24gKGFjdCwgZXhwLCBtc2cpIHtcbiAgICB2YXIgdGVzdCA9IG5ldyBBc3NlcnRpb24oYWN0LCBtc2csIGFzc2VydC5ub3RFcXVhbCk7XG5cbiAgICB0ZXN0LmFzc2VydChcbiAgICAgICAgZXhwICE9IGZsYWcodGVzdCwgJ29iamVjdCcpXG4gICAgICAsICdleHBlY3RlZCAje3RoaXN9IHRvIG5vdCBlcXVhbCAje2V4cH0nXG4gICAgICAsICdleHBlY3RlZCAje3RoaXN9IHRvIGVxdWFsICN7YWN0fSdcbiAgICAgICwgZXhwXG4gICAgICAsIGFjdFxuICAgICk7XG4gIH07XG5cbiAgLyoqXG4gICAqICMjIyAuc3RyaWN0RXF1YWwoYWN0dWFsLCBleHBlY3RlZCwgW21lc3NhZ2VdKVxuICAgKlxuICAgKiBBc3NlcnRzIHN0cmljdCBlcXVhbGl0eSAoYD09PWApIG9mIGBhY3R1YWxgIGFuZCBgZXhwZWN0ZWRgLlxuICAgKlxuICAgKiAgICAgYXNzZXJ0LnN0cmljdEVxdWFsKHRydWUsIHRydWUsICd0aGVzZSBib29sZWFucyBhcmUgc3RyaWN0bHkgZXF1YWwnKTtcbiAgICpcbiAgICogQG5hbWUgc3RyaWN0RXF1YWxcbiAgICogQHBhcmFtIHtNaXhlZH0gYWN0dWFsXG4gICAqIEBwYXJhbSB7TWl4ZWR9IGV4cGVjdGVkXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlXG4gICAqIEBuYW1lc3BhY2UgQXNzZXJ0XG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIGFzc2VydC5zdHJpY3RFcXVhbCA9IGZ1bmN0aW9uIChhY3QsIGV4cCwgbXNnKSB7XG4gICAgbmV3IEFzc2VydGlvbihhY3QsIG1zZykudG8uZXF1YWwoZXhwKTtcbiAgfTtcblxuICAvKipcbiAgICogIyMjIC5ub3RTdHJpY3RFcXVhbChhY3R1YWwsIGV4cGVjdGVkLCBbbWVzc2FnZV0pXG4gICAqXG4gICAqIEFzc2VydHMgc3RyaWN0IGluZXF1YWxpdHkgKGAhPT1gKSBvZiBgYWN0dWFsYCBhbmQgYGV4cGVjdGVkYC5cbiAgICpcbiAgICogICAgIGFzc2VydC5ub3RTdHJpY3RFcXVhbCgzLCAnMycsICdubyBjb2VyY2lvbiBmb3Igc3RyaWN0IGVxdWFsaXR5Jyk7XG4gICAqXG4gICAqIEBuYW1lIG5vdFN0cmljdEVxdWFsXG4gICAqIEBwYXJhbSB7TWl4ZWR9IGFjdHVhbFxuICAgKiBAcGFyYW0ge01peGVkfSBleHBlY3RlZFxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZVxuICAgKiBAbmFtZXNwYWNlIEFzc2VydFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBhc3NlcnQubm90U3RyaWN0RXF1YWwgPSBmdW5jdGlvbiAoYWN0LCBleHAsIG1zZykge1xuICAgIG5ldyBBc3NlcnRpb24oYWN0LCBtc2cpLnRvLm5vdC5lcXVhbChleHApO1xuICB9O1xuXG4gIC8qKlxuICAgKiAjIyMgLmRlZXBFcXVhbChhY3R1YWwsIGV4cGVjdGVkLCBbbWVzc2FnZV0pXG4gICAqXG4gICAqIEFzc2VydHMgdGhhdCBgYWN0dWFsYCBpcyBkZWVwbHkgZXF1YWwgdG8gYGV4cGVjdGVkYC5cbiAgICpcbiAgICogICAgIGFzc2VydC5kZWVwRXF1YWwoeyB0ZWE6ICdncmVlbicgfSwgeyB0ZWE6ICdncmVlbicgfSk7XG4gICAqXG4gICAqIEBuYW1lIGRlZXBFcXVhbFxuICAgKiBAcGFyYW0ge01peGVkfSBhY3R1YWxcbiAgICogQHBhcmFtIHtNaXhlZH0gZXhwZWN0ZWRcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2VcbiAgICogQG5hbWVzcGFjZSBBc3NlcnRcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgYXNzZXJ0LmRlZXBFcXVhbCA9IGZ1bmN0aW9uIChhY3QsIGV4cCwgbXNnKSB7XG4gICAgbmV3IEFzc2VydGlvbihhY3QsIG1zZykudG8uZXFsKGV4cCk7XG4gIH07XG5cbiAgLyoqXG4gICAqICMjIyAubm90RGVlcEVxdWFsKGFjdHVhbCwgZXhwZWN0ZWQsIFttZXNzYWdlXSlcbiAgICpcbiAgICogQXNzZXJ0IHRoYXQgYGFjdHVhbGAgaXMgbm90IGRlZXBseSBlcXVhbCB0byBgZXhwZWN0ZWRgLlxuICAgKlxuICAgKiAgICAgYXNzZXJ0Lm5vdERlZXBFcXVhbCh7IHRlYTogJ2dyZWVuJyB9LCB7IHRlYTogJ2phc21pbmUnIH0pO1xuICAgKlxuICAgKiBAbmFtZSBub3REZWVwRXF1YWxcbiAgICogQHBhcmFtIHtNaXhlZH0gYWN0dWFsXG4gICAqIEBwYXJhbSB7TWl4ZWR9IGV4cGVjdGVkXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlXG4gICAqIEBuYW1lc3BhY2UgQXNzZXJ0XG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIGFzc2VydC5ub3REZWVwRXF1YWwgPSBmdW5jdGlvbiAoYWN0LCBleHAsIG1zZykge1xuICAgIG5ldyBBc3NlcnRpb24oYWN0LCBtc2cpLnRvLm5vdC5lcWwoZXhwKTtcbiAgfTtcblxuICAgLyoqXG4gICAqICMjIyAuaXNBYm92ZSh2YWx1ZVRvQ2hlY2ssIHZhbHVlVG9CZUFib3ZlLCBbbWVzc2FnZV0pXG4gICAqXG4gICAqIEFzc2VydHMgYHZhbHVlVG9DaGVja2AgaXMgc3RyaWN0bHkgZ3JlYXRlciB0aGFuICg+KSBgdmFsdWVUb0JlQWJvdmVgXG4gICAqXG4gICAqICAgICBhc3NlcnQuaXNBYm92ZSg1LCAyLCAnNSBpcyBzdHJpY3RseSBncmVhdGVyIHRoYW4gMicpO1xuICAgKlxuICAgKiBAbmFtZSBpc0Fib3ZlXG4gICAqIEBwYXJhbSB7TWl4ZWR9IHZhbHVlVG9DaGVja1xuICAgKiBAcGFyYW0ge01peGVkfSB2YWx1ZVRvQmVBYm92ZVxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZVxuICAgKiBAbmFtZXNwYWNlIEFzc2VydFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBhc3NlcnQuaXNBYm92ZSA9IGZ1bmN0aW9uICh2YWwsIGFidiwgbXNnKSB7XG4gICAgbmV3IEFzc2VydGlvbih2YWwsIG1zZykudG8uYmUuYWJvdmUoYWJ2KTtcbiAgfTtcblxuICAgLyoqXG4gICAqICMjIyAuaXNBdExlYXN0KHZhbHVlVG9DaGVjaywgdmFsdWVUb0JlQXRMZWFzdCwgW21lc3NhZ2VdKVxuICAgKlxuICAgKiBBc3NlcnRzIGB2YWx1ZVRvQ2hlY2tgIGlzIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byAoPj0pIGB2YWx1ZVRvQmVBdExlYXN0YFxuICAgKlxuICAgKiAgICAgYXNzZXJ0LmlzQXRMZWFzdCg1LCAyLCAnNSBpcyBncmVhdGVyIG9yIGVxdWFsIHRvIDInKTtcbiAgICogICAgIGFzc2VydC5pc0F0TGVhc3QoMywgMywgJzMgaXMgZ3JlYXRlciBvciBlcXVhbCB0byAzJyk7XG4gICAqXG4gICAqIEBuYW1lIGlzQXRMZWFzdFxuICAgKiBAcGFyYW0ge01peGVkfSB2YWx1ZVRvQ2hlY2tcbiAgICogQHBhcmFtIHtNaXhlZH0gdmFsdWVUb0JlQXRMZWFzdFxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZVxuICAgKiBAbmFtZXNwYWNlIEFzc2VydFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBhc3NlcnQuaXNBdExlYXN0ID0gZnVuY3Rpb24gKHZhbCwgYXRsc3QsIG1zZykge1xuICAgIG5ldyBBc3NlcnRpb24odmFsLCBtc2cpLnRvLmJlLmxlYXN0KGF0bHN0KTtcbiAgfTtcblxuICAgLyoqXG4gICAqICMjIyAuaXNCZWxvdyh2YWx1ZVRvQ2hlY2ssIHZhbHVlVG9CZUJlbG93LCBbbWVzc2FnZV0pXG4gICAqXG4gICAqIEFzc2VydHMgYHZhbHVlVG9DaGVja2AgaXMgc3RyaWN0bHkgbGVzcyB0aGFuICg8KSBgdmFsdWVUb0JlQmVsb3dgXG4gICAqXG4gICAqICAgICBhc3NlcnQuaXNCZWxvdygzLCA2LCAnMyBpcyBzdHJpY3RseSBsZXNzIHRoYW4gNicpO1xuICAgKlxuICAgKiBAbmFtZSBpc0JlbG93XG4gICAqIEBwYXJhbSB7TWl4ZWR9IHZhbHVlVG9DaGVja1xuICAgKiBAcGFyYW0ge01peGVkfSB2YWx1ZVRvQmVCZWxvd1xuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZVxuICAgKiBAbmFtZXNwYWNlIEFzc2VydFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBhc3NlcnQuaXNCZWxvdyA9IGZ1bmN0aW9uICh2YWwsIGJsdywgbXNnKSB7XG4gICAgbmV3IEFzc2VydGlvbih2YWwsIG1zZykudG8uYmUuYmVsb3coYmx3KTtcbiAgfTtcblxuICAgLyoqXG4gICAqICMjIyAuaXNBdE1vc3QodmFsdWVUb0NoZWNrLCB2YWx1ZVRvQmVBdE1vc3QsIFttZXNzYWdlXSlcbiAgICpcbiAgICogQXNzZXJ0cyBgdmFsdWVUb0NoZWNrYCBpcyBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gKDw9KSBgdmFsdWVUb0JlQXRNb3N0YFxuICAgKlxuICAgKiAgICAgYXNzZXJ0LmlzQXRNb3N0KDMsIDYsICczIGlzIGxlc3MgdGhhbiBvciBlcXVhbCB0byA2Jyk7XG4gICAqICAgICBhc3NlcnQuaXNBdE1vc3QoNCwgNCwgJzQgaXMgbGVzcyB0aGFuIG9yIGVxdWFsIHRvIDQnKTtcbiAgICpcbiAgICogQG5hbWUgaXNBdE1vc3RcbiAgICogQHBhcmFtIHtNaXhlZH0gdmFsdWVUb0NoZWNrXG4gICAqIEBwYXJhbSB7TWl4ZWR9IHZhbHVlVG9CZUF0TW9zdFxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZVxuICAgKiBAbmFtZXNwYWNlIEFzc2VydFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBhc3NlcnQuaXNBdE1vc3QgPSBmdW5jdGlvbiAodmFsLCBhdG1zdCwgbXNnKSB7XG4gICAgbmV3IEFzc2VydGlvbih2YWwsIG1zZykudG8uYmUubW9zdChhdG1zdCk7XG4gIH07XG5cbiAgLyoqXG4gICAqICMjIyAuaXNUcnVlKHZhbHVlLCBbbWVzc2FnZV0pXG4gICAqXG4gICAqIEFzc2VydHMgdGhhdCBgdmFsdWVgIGlzIHRydWUuXG4gICAqXG4gICAqICAgICB2YXIgdGVhU2VydmVkID0gdHJ1ZTtcbiAgICogICAgIGFzc2VydC5pc1RydWUodGVhU2VydmVkLCAndGhlIHRlYSBoYXMgYmVlbiBzZXJ2ZWQnKTtcbiAgICpcbiAgICogQG5hbWUgaXNUcnVlXG4gICAqIEBwYXJhbSB7TWl4ZWR9IHZhbHVlXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlXG4gICAqIEBuYW1lc3BhY2UgQXNzZXJ0XG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIGFzc2VydC5pc1RydWUgPSBmdW5jdGlvbiAodmFsLCBtc2cpIHtcbiAgICBuZXcgQXNzZXJ0aW9uKHZhbCwgbXNnKS5pc1sndHJ1ZSddO1xuICB9O1xuXG4gIC8qKlxuICAgKiAjIyMgLmlzTm90VHJ1ZSh2YWx1ZSwgW21lc3NhZ2VdKVxuICAgKlxuICAgKiBBc3NlcnRzIHRoYXQgYHZhbHVlYCBpcyBub3QgdHJ1ZS5cbiAgICpcbiAgICogICAgIHZhciB0ZWEgPSAndGFzdHkgY2hhaSc7XG4gICAqICAgICBhc3NlcnQuaXNOb3RUcnVlKHRlYSwgJ2dyZWF0LCB0aW1lIGZvciB0ZWEhJyk7XG4gICAqXG4gICAqIEBuYW1lIGlzTm90VHJ1ZVxuICAgKiBAcGFyYW0ge01peGVkfSB2YWx1ZVxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZVxuICAgKiBAbmFtZXNwYWNlIEFzc2VydFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBhc3NlcnQuaXNOb3RUcnVlID0gZnVuY3Rpb24gKHZhbCwgbXNnKSB7XG4gICAgbmV3IEFzc2VydGlvbih2YWwsIG1zZykudG8ubm90LmVxdWFsKHRydWUpO1xuICB9O1xuXG4gIC8qKlxuICAgKiAjIyMgLmlzRmFsc2UodmFsdWUsIFttZXNzYWdlXSlcbiAgICpcbiAgICogQXNzZXJ0cyB0aGF0IGB2YWx1ZWAgaXMgZmFsc2UuXG4gICAqXG4gICAqICAgICB2YXIgdGVhU2VydmVkID0gZmFsc2U7XG4gICAqICAgICBhc3NlcnQuaXNGYWxzZSh0ZWFTZXJ2ZWQsICdubyB0ZWEgeWV0PyBobW0uLi4nKTtcbiAgICpcbiAgICogQG5hbWUgaXNGYWxzZVxuICAgKiBAcGFyYW0ge01peGVkfSB2YWx1ZVxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZVxuICAgKiBAbmFtZXNwYWNlIEFzc2VydFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBhc3NlcnQuaXNGYWxzZSA9IGZ1bmN0aW9uICh2YWwsIG1zZykge1xuICAgIG5ldyBBc3NlcnRpb24odmFsLCBtc2cpLmlzWydmYWxzZSddO1xuICB9O1xuXG4gIC8qKlxuICAgKiAjIyMgLmlzTm90RmFsc2UodmFsdWUsIFttZXNzYWdlXSlcbiAgICpcbiAgICogQXNzZXJ0cyB0aGF0IGB2YWx1ZWAgaXMgbm90IGZhbHNlLlxuICAgKlxuICAgKiAgICAgdmFyIHRlYSA9ICd0YXN0eSBjaGFpJztcbiAgICogICAgIGFzc2VydC5pc05vdEZhbHNlKHRlYSwgJ2dyZWF0LCB0aW1lIGZvciB0ZWEhJyk7XG4gICAqXG4gICAqIEBuYW1lIGlzTm90RmFsc2VcbiAgICogQHBhcmFtIHtNaXhlZH0gdmFsdWVcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2VcbiAgICogQG5hbWVzcGFjZSBBc3NlcnRcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgYXNzZXJ0LmlzTm90RmFsc2UgPSBmdW5jdGlvbiAodmFsLCBtc2cpIHtcbiAgICBuZXcgQXNzZXJ0aW9uKHZhbCwgbXNnKS50by5ub3QuZXF1YWwoZmFsc2UpO1xuICB9O1xuXG4gIC8qKlxuICAgKiAjIyMgLmlzTnVsbCh2YWx1ZSwgW21lc3NhZ2VdKVxuICAgKlxuICAgKiBBc3NlcnRzIHRoYXQgYHZhbHVlYCBpcyBudWxsLlxuICAgKlxuICAgKiAgICAgYXNzZXJ0LmlzTnVsbChlcnIsICd0aGVyZSB3YXMgbm8gZXJyb3InKTtcbiAgICpcbiAgICogQG5hbWUgaXNOdWxsXG4gICAqIEBwYXJhbSB7TWl4ZWR9IHZhbHVlXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlXG4gICAqIEBuYW1lc3BhY2UgQXNzZXJ0XG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIGFzc2VydC5pc051bGwgPSBmdW5jdGlvbiAodmFsLCBtc2cpIHtcbiAgICBuZXcgQXNzZXJ0aW9uKHZhbCwgbXNnKS50by5lcXVhbChudWxsKTtcbiAgfTtcblxuICAvKipcbiAgICogIyMjIC5pc05vdE51bGwodmFsdWUsIFttZXNzYWdlXSlcbiAgICpcbiAgICogQXNzZXJ0cyB0aGF0IGB2YWx1ZWAgaXMgbm90IG51bGwuXG4gICAqXG4gICAqICAgICB2YXIgdGVhID0gJ3Rhc3R5IGNoYWknO1xuICAgKiAgICAgYXNzZXJ0LmlzTm90TnVsbCh0ZWEsICdncmVhdCwgdGltZSBmb3IgdGVhIScpO1xuICAgKlxuICAgKiBAbmFtZSBpc05vdE51bGxcbiAgICogQHBhcmFtIHtNaXhlZH0gdmFsdWVcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2VcbiAgICogQG5hbWVzcGFjZSBBc3NlcnRcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgYXNzZXJ0LmlzTm90TnVsbCA9IGZ1bmN0aW9uICh2YWwsIG1zZykge1xuICAgIG5ldyBBc3NlcnRpb24odmFsLCBtc2cpLnRvLm5vdC5lcXVhbChudWxsKTtcbiAgfTtcblxuICAvKipcbiAgICogIyMjIC5pc05hTlxuICAgKiBBc3NlcnRzIHRoYXQgdmFsdWUgaXMgTmFOXG4gICAqXG4gICAqICAgIGFzc2VydC5pc05hTignZm9vJywgJ2ZvbyBpcyBOYU4nKTtcbiAgICpcbiAgICogQG5hbWUgaXNOYU5cbiAgICogQHBhcmFtIHtNaXhlZH0gdmFsdWVcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2VcbiAgICogQG5hbWVzcGFjZSBBc3NlcnRcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgYXNzZXJ0LmlzTmFOID0gZnVuY3Rpb24gKHZhbCwgbXNnKSB7XG4gICAgbmV3IEFzc2VydGlvbih2YWwsIG1zZykudG8uYmUuTmFOO1xuICB9O1xuXG4gIC8qKlxuICAgKiAjIyMgLmlzTm90TmFOXG4gICAqIEFzc2VydHMgdGhhdCB2YWx1ZSBpcyBub3QgTmFOXG4gICAqXG4gICAqICAgIGFzc2VydC5pc05vdE5hTig0LCAnNCBpcyBub3QgTmFOJyk7XG4gICAqXG4gICAqIEBuYW1lIGlzTm90TmFOXG4gICAqIEBwYXJhbSB7TWl4ZWR9IHZhbHVlXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlXG4gICAqIEBuYW1lc3BhY2UgQXNzZXJ0XG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuICBhc3NlcnQuaXNOb3ROYU4gPSBmdW5jdGlvbiAodmFsLCBtc2cpIHtcbiAgICBuZXcgQXNzZXJ0aW9uKHZhbCwgbXNnKS5ub3QudG8uYmUuTmFOO1xuICB9O1xuXG4gIC8qKlxuICAgKiAjIyMgLmlzVW5kZWZpbmVkKHZhbHVlLCBbbWVzc2FnZV0pXG4gICAqXG4gICAqIEFzc2VydHMgdGhhdCBgdmFsdWVgIGlzIGB1bmRlZmluZWRgLlxuICAgKlxuICAgKiAgICAgdmFyIHRlYTtcbiAgICogICAgIGFzc2VydC5pc1VuZGVmaW5lZCh0ZWEsICdubyB0ZWEgZGVmaW5lZCcpO1xuICAgKlxuICAgKiBAbmFtZSBpc1VuZGVmaW5lZFxuICAgKiBAcGFyYW0ge01peGVkfSB2YWx1ZVxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZVxuICAgKiBAbmFtZXNwYWNlIEFzc2VydFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBhc3NlcnQuaXNVbmRlZmluZWQgPSBmdW5jdGlvbiAodmFsLCBtc2cpIHtcbiAgICBuZXcgQXNzZXJ0aW9uKHZhbCwgbXNnKS50by5lcXVhbCh1bmRlZmluZWQpO1xuICB9O1xuXG4gIC8qKlxuICAgKiAjIyMgLmlzRGVmaW5lZCh2YWx1ZSwgW21lc3NhZ2VdKVxuICAgKlxuICAgKiBBc3NlcnRzIHRoYXQgYHZhbHVlYCBpcyBub3QgYHVuZGVmaW5lZGAuXG4gICAqXG4gICAqICAgICB2YXIgdGVhID0gJ2N1cCBvZiBjaGFpJztcbiAgICogICAgIGFzc2VydC5pc0RlZmluZWQodGVhLCAndGVhIGhhcyBiZWVuIGRlZmluZWQnKTtcbiAgICpcbiAgICogQG5hbWUgaXNEZWZpbmVkXG4gICAqIEBwYXJhbSB7TWl4ZWR9IHZhbHVlXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlXG4gICAqIEBuYW1lc3BhY2UgQXNzZXJ0XG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIGFzc2VydC5pc0RlZmluZWQgPSBmdW5jdGlvbiAodmFsLCBtc2cpIHtcbiAgICBuZXcgQXNzZXJ0aW9uKHZhbCwgbXNnKS50by5ub3QuZXF1YWwodW5kZWZpbmVkKTtcbiAgfTtcblxuICAvKipcbiAgICogIyMjIC5pc0Z1bmN0aW9uKHZhbHVlLCBbbWVzc2FnZV0pXG4gICAqXG4gICAqIEFzc2VydHMgdGhhdCBgdmFsdWVgIGlzIGEgZnVuY3Rpb24uXG4gICAqXG4gICAqICAgICBmdW5jdGlvbiBzZXJ2ZVRlYSgpIHsgcmV0dXJuICdjdXAgb2YgdGVhJzsgfTtcbiAgICogICAgIGFzc2VydC5pc0Z1bmN0aW9uKHNlcnZlVGVhLCAnZ3JlYXQsIHdlIGNhbiBoYXZlIHRlYSBub3cnKTtcbiAgICpcbiAgICogQG5hbWUgaXNGdW5jdGlvblxuICAgKiBAcGFyYW0ge01peGVkfSB2YWx1ZVxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZVxuICAgKiBAbmFtZXNwYWNlIEFzc2VydFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBhc3NlcnQuaXNGdW5jdGlvbiA9IGZ1bmN0aW9uICh2YWwsIG1zZykge1xuICAgIG5ldyBBc3NlcnRpb24odmFsLCBtc2cpLnRvLmJlLmEoJ2Z1bmN0aW9uJyk7XG4gIH07XG5cbiAgLyoqXG4gICAqICMjIyAuaXNOb3RGdW5jdGlvbih2YWx1ZSwgW21lc3NhZ2VdKVxuICAgKlxuICAgKiBBc3NlcnRzIHRoYXQgYHZhbHVlYCBpcyBfbm90XyBhIGZ1bmN0aW9uLlxuICAgKlxuICAgKiAgICAgdmFyIHNlcnZlVGVhID0gWyAnaGVhdCcsICdwb3VyJywgJ3NpcCcgXTtcbiAgICogICAgIGFzc2VydC5pc05vdEZ1bmN0aW9uKHNlcnZlVGVhLCAnZ3JlYXQsIHdlIGhhdmUgbGlzdGVkIHRoZSBzdGVwcycpO1xuICAgKlxuICAgKiBAbmFtZSBpc05vdEZ1bmN0aW9uXG4gICAqIEBwYXJhbSB7TWl4ZWR9IHZhbHVlXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlXG4gICAqIEBuYW1lc3BhY2UgQXNzZXJ0XG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIGFzc2VydC5pc05vdEZ1bmN0aW9uID0gZnVuY3Rpb24gKHZhbCwgbXNnKSB7XG4gICAgbmV3IEFzc2VydGlvbih2YWwsIG1zZykudG8ubm90LmJlLmEoJ2Z1bmN0aW9uJyk7XG4gIH07XG5cbiAgLyoqXG4gICAqICMjIyAuaXNPYmplY3QodmFsdWUsIFttZXNzYWdlXSlcbiAgICpcbiAgICogQXNzZXJ0cyB0aGF0IGB2YWx1ZWAgaXMgYW4gb2JqZWN0IG9mIHR5cGUgJ09iamVjdCcgKGFzIHJldmVhbGVkIGJ5IGBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nYCkuXG4gICAqIF9UaGUgYXNzZXJ0aW9uIGRvZXMgbm90IG1hdGNoIHN1YmNsYXNzZWQgb2JqZWN0cy5fXG4gICAqXG4gICAqICAgICB2YXIgc2VsZWN0aW9uID0geyBuYW1lOiAnQ2hhaScsIHNlcnZlOiAnd2l0aCBzcGljZXMnIH07XG4gICAqICAgICBhc3NlcnQuaXNPYmplY3Qoc2VsZWN0aW9uLCAndGVhIHNlbGVjdGlvbiBpcyBhbiBvYmplY3QnKTtcbiAgICpcbiAgICogQG5hbWUgaXNPYmplY3RcbiAgICogQHBhcmFtIHtNaXhlZH0gdmFsdWVcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2VcbiAgICogQG5hbWVzcGFjZSBBc3NlcnRcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgYXNzZXJ0LmlzT2JqZWN0ID0gZnVuY3Rpb24gKHZhbCwgbXNnKSB7XG4gICAgbmV3IEFzc2VydGlvbih2YWwsIG1zZykudG8uYmUuYSgnb2JqZWN0Jyk7XG4gIH07XG5cbiAgLyoqXG4gICAqICMjIyAuaXNOb3RPYmplY3QodmFsdWUsIFttZXNzYWdlXSlcbiAgICpcbiAgICogQXNzZXJ0cyB0aGF0IGB2YWx1ZWAgaXMgX25vdF8gYW4gb2JqZWN0IG9mIHR5cGUgJ09iamVjdCcgKGFzIHJldmVhbGVkIGJ5IGBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nYCkuXG4gICAqXG4gICAqICAgICB2YXIgc2VsZWN0aW9uID0gJ2NoYWknXG4gICAqICAgICBhc3NlcnQuaXNOb3RPYmplY3Qoc2VsZWN0aW9uLCAndGVhIHNlbGVjdGlvbiBpcyBub3QgYW4gb2JqZWN0Jyk7XG4gICAqICAgICBhc3NlcnQuaXNOb3RPYmplY3QobnVsbCwgJ251bGwgaXMgbm90IGFuIG9iamVjdCcpO1xuICAgKlxuICAgKiBAbmFtZSBpc05vdE9iamVjdFxuICAgKiBAcGFyYW0ge01peGVkfSB2YWx1ZVxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZVxuICAgKiBAbmFtZXNwYWNlIEFzc2VydFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBhc3NlcnQuaXNOb3RPYmplY3QgPSBmdW5jdGlvbiAodmFsLCBtc2cpIHtcbiAgICBuZXcgQXNzZXJ0aW9uKHZhbCwgbXNnKS50by5ub3QuYmUuYSgnb2JqZWN0Jyk7XG4gIH07XG5cbiAgLyoqXG4gICAqICMjIyAuaXNBcnJheSh2YWx1ZSwgW21lc3NhZ2VdKVxuICAgKlxuICAgKiBBc3NlcnRzIHRoYXQgYHZhbHVlYCBpcyBhbiBhcnJheS5cbiAgICpcbiAgICogICAgIHZhciBtZW51ID0gWyAnZ3JlZW4nLCAnY2hhaScsICdvb2xvbmcnIF07XG4gICAqICAgICBhc3NlcnQuaXNBcnJheShtZW51LCAnd2hhdCBraW5kIG9mIHRlYSBkbyB3ZSB3YW50PycpO1xuICAgKlxuICAgKiBAbmFtZSBpc0FycmF5XG4gICAqIEBwYXJhbSB7TWl4ZWR9IHZhbHVlXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlXG4gICAqIEBuYW1lc3BhY2UgQXNzZXJ0XG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIGFzc2VydC5pc0FycmF5ID0gZnVuY3Rpb24gKHZhbCwgbXNnKSB7XG4gICAgbmV3IEFzc2VydGlvbih2YWwsIG1zZykudG8uYmUuYW4oJ2FycmF5Jyk7XG4gIH07XG5cbiAgLyoqXG4gICAqICMjIyAuaXNOb3RBcnJheSh2YWx1ZSwgW21lc3NhZ2VdKVxuICAgKlxuICAgKiBBc3NlcnRzIHRoYXQgYHZhbHVlYCBpcyBfbm90XyBhbiBhcnJheS5cbiAgICpcbiAgICogICAgIHZhciBtZW51ID0gJ2dyZWVufGNoYWl8b29sb25nJztcbiAgICogICAgIGFzc2VydC5pc05vdEFycmF5KG1lbnUsICd3aGF0IGtpbmQgb2YgdGVhIGRvIHdlIHdhbnQ/Jyk7XG4gICAqXG4gICAqIEBuYW1lIGlzTm90QXJyYXlcbiAgICogQHBhcmFtIHtNaXhlZH0gdmFsdWVcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2VcbiAgICogQG5hbWVzcGFjZSBBc3NlcnRcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgYXNzZXJ0LmlzTm90QXJyYXkgPSBmdW5jdGlvbiAodmFsLCBtc2cpIHtcbiAgICBuZXcgQXNzZXJ0aW9uKHZhbCwgbXNnKS50by5ub3QuYmUuYW4oJ2FycmF5Jyk7XG4gIH07XG5cbiAgLyoqXG4gICAqICMjIyAuaXNTdHJpbmcodmFsdWUsIFttZXNzYWdlXSlcbiAgICpcbiAgICogQXNzZXJ0cyB0aGF0IGB2YWx1ZWAgaXMgYSBzdHJpbmcuXG4gICAqXG4gICAqICAgICB2YXIgdGVhT3JkZXIgPSAnY2hhaSc7XG4gICAqICAgICBhc3NlcnQuaXNTdHJpbmcodGVhT3JkZXIsICdvcmRlciBwbGFjZWQnKTtcbiAgICpcbiAgICogQG5hbWUgaXNTdHJpbmdcbiAgICogQHBhcmFtIHtNaXhlZH0gdmFsdWVcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2VcbiAgICogQG5hbWVzcGFjZSBBc3NlcnRcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgYXNzZXJ0LmlzU3RyaW5nID0gZnVuY3Rpb24gKHZhbCwgbXNnKSB7XG4gICAgbmV3IEFzc2VydGlvbih2YWwsIG1zZykudG8uYmUuYSgnc3RyaW5nJyk7XG4gIH07XG5cbiAgLyoqXG4gICAqICMjIyAuaXNOb3RTdHJpbmcodmFsdWUsIFttZXNzYWdlXSlcbiAgICpcbiAgICogQXNzZXJ0cyB0aGF0IGB2YWx1ZWAgaXMgX25vdF8gYSBzdHJpbmcuXG4gICAqXG4gICAqICAgICB2YXIgdGVhT3JkZXIgPSA0O1xuICAgKiAgICAgYXNzZXJ0LmlzTm90U3RyaW5nKHRlYU9yZGVyLCAnb3JkZXIgcGxhY2VkJyk7XG4gICAqXG4gICAqIEBuYW1lIGlzTm90U3RyaW5nXG4gICAqIEBwYXJhbSB7TWl4ZWR9IHZhbHVlXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlXG4gICAqIEBuYW1lc3BhY2UgQXNzZXJ0XG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIGFzc2VydC5pc05vdFN0cmluZyA9IGZ1bmN0aW9uICh2YWwsIG1zZykge1xuICAgIG5ldyBBc3NlcnRpb24odmFsLCBtc2cpLnRvLm5vdC5iZS5hKCdzdHJpbmcnKTtcbiAgfTtcblxuICAvKipcbiAgICogIyMjIC5pc051bWJlcih2YWx1ZSwgW21lc3NhZ2VdKVxuICAgKlxuICAgKiBBc3NlcnRzIHRoYXQgYHZhbHVlYCBpcyBhIG51bWJlci5cbiAgICpcbiAgICogICAgIHZhciBjdXBzID0gMjtcbiAgICogICAgIGFzc2VydC5pc051bWJlcihjdXBzLCAnaG93IG1hbnkgY3VwcycpO1xuICAgKlxuICAgKiBAbmFtZSBpc051bWJlclxuICAgKiBAcGFyYW0ge051bWJlcn0gdmFsdWVcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2VcbiAgICogQG5hbWVzcGFjZSBBc3NlcnRcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgYXNzZXJ0LmlzTnVtYmVyID0gZnVuY3Rpb24gKHZhbCwgbXNnKSB7XG4gICAgbmV3IEFzc2VydGlvbih2YWwsIG1zZykudG8uYmUuYSgnbnVtYmVyJyk7XG4gIH07XG5cbiAgLyoqXG4gICAqICMjIyAuaXNOb3ROdW1iZXIodmFsdWUsIFttZXNzYWdlXSlcbiAgICpcbiAgICogQXNzZXJ0cyB0aGF0IGB2YWx1ZWAgaXMgX25vdF8gYSBudW1iZXIuXG4gICAqXG4gICAqICAgICB2YXIgY3VwcyA9ICcyIGN1cHMgcGxlYXNlJztcbiAgICogICAgIGFzc2VydC5pc05vdE51bWJlcihjdXBzLCAnaG93IG1hbnkgY3VwcycpO1xuICAgKlxuICAgKiBAbmFtZSBpc05vdE51bWJlclxuICAgKiBAcGFyYW0ge01peGVkfSB2YWx1ZVxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZVxuICAgKiBAbmFtZXNwYWNlIEFzc2VydFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBhc3NlcnQuaXNOb3ROdW1iZXIgPSBmdW5jdGlvbiAodmFsLCBtc2cpIHtcbiAgICBuZXcgQXNzZXJ0aW9uKHZhbCwgbXNnKS50by5ub3QuYmUuYSgnbnVtYmVyJyk7XG4gIH07XG5cbiAgLyoqXG4gICAqICMjIyAuaXNCb29sZWFuKHZhbHVlLCBbbWVzc2FnZV0pXG4gICAqXG4gICAqIEFzc2VydHMgdGhhdCBgdmFsdWVgIGlzIGEgYm9vbGVhbi5cbiAgICpcbiAgICogICAgIHZhciB0ZWFSZWFkeSA9IHRydWVcbiAgICogICAgICAgLCB0ZWFTZXJ2ZWQgPSBmYWxzZTtcbiAgICpcbiAgICogICAgIGFzc2VydC5pc0Jvb2xlYW4odGVhUmVhZHksICdpcyB0aGUgdGVhIHJlYWR5Jyk7XG4gICAqICAgICBhc3NlcnQuaXNCb29sZWFuKHRlYVNlcnZlZCwgJ2hhcyB0ZWEgYmVlbiBzZXJ2ZWQnKTtcbiAgICpcbiAgICogQG5hbWUgaXNCb29sZWFuXG4gICAqIEBwYXJhbSB7TWl4ZWR9IHZhbHVlXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlXG4gICAqIEBuYW1lc3BhY2UgQXNzZXJ0XG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIGFzc2VydC5pc0Jvb2xlYW4gPSBmdW5jdGlvbiAodmFsLCBtc2cpIHtcbiAgICBuZXcgQXNzZXJ0aW9uKHZhbCwgbXNnKS50by5iZS5hKCdib29sZWFuJyk7XG4gIH07XG5cbiAgLyoqXG4gICAqICMjIyAuaXNOb3RCb29sZWFuKHZhbHVlLCBbbWVzc2FnZV0pXG4gICAqXG4gICAqIEFzc2VydHMgdGhhdCBgdmFsdWVgIGlzIF9ub3RfIGEgYm9vbGVhbi5cbiAgICpcbiAgICogICAgIHZhciB0ZWFSZWFkeSA9ICd5ZXAnXG4gICAqICAgICAgICwgdGVhU2VydmVkID0gJ25vcGUnO1xuICAgKlxuICAgKiAgICAgYXNzZXJ0LmlzTm90Qm9vbGVhbih0ZWFSZWFkeSwgJ2lzIHRoZSB0ZWEgcmVhZHknKTtcbiAgICogICAgIGFzc2VydC5pc05vdEJvb2xlYW4odGVhU2VydmVkLCAnaGFzIHRlYSBiZWVuIHNlcnZlZCcpO1xuICAgKlxuICAgKiBAbmFtZSBpc05vdEJvb2xlYW5cbiAgICogQHBhcmFtIHtNaXhlZH0gdmFsdWVcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2VcbiAgICogQG5hbWVzcGFjZSBBc3NlcnRcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgYXNzZXJ0LmlzTm90Qm9vbGVhbiA9IGZ1bmN0aW9uICh2YWwsIG1zZykge1xuICAgIG5ldyBBc3NlcnRpb24odmFsLCBtc2cpLnRvLm5vdC5iZS5hKCdib29sZWFuJyk7XG4gIH07XG5cbiAgLyoqXG4gICAqICMjIyAudHlwZU9mKHZhbHVlLCBuYW1lLCBbbWVzc2FnZV0pXG4gICAqXG4gICAqIEFzc2VydHMgdGhhdCBgdmFsdWVgJ3MgdHlwZSBpcyBgbmFtZWAsIGFzIGRldGVybWluZWQgYnlcbiAgICogYE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmdgLlxuICAgKlxuICAgKiAgICAgYXNzZXJ0LnR5cGVPZih7IHRlYTogJ2NoYWknIH0sICdvYmplY3QnLCAnd2UgaGF2ZSBhbiBvYmplY3QnKTtcbiAgICogICAgIGFzc2VydC50eXBlT2YoWydjaGFpJywgJ2phc21pbmUnXSwgJ2FycmF5JywgJ3dlIGhhdmUgYW4gYXJyYXknKTtcbiAgICogICAgIGFzc2VydC50eXBlT2YoJ3RlYScsICdzdHJpbmcnLCAnd2UgaGF2ZSBhIHN0cmluZycpO1xuICAgKiAgICAgYXNzZXJ0LnR5cGVPZigvdGVhLywgJ3JlZ2V4cCcsICd3ZSBoYXZlIGEgcmVndWxhciBleHByZXNzaW9uJyk7XG4gICAqICAgICBhc3NlcnQudHlwZU9mKG51bGwsICdudWxsJywgJ3dlIGhhdmUgYSBudWxsJyk7XG4gICAqICAgICBhc3NlcnQudHlwZU9mKHVuZGVmaW5lZCwgJ3VuZGVmaW5lZCcsICd3ZSBoYXZlIGFuIHVuZGVmaW5lZCcpO1xuICAgKlxuICAgKiBAbmFtZSB0eXBlT2ZcbiAgICogQHBhcmFtIHtNaXhlZH0gdmFsdWVcbiAgICogQHBhcmFtIHtTdHJpbmd9IG5hbWVcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2VcbiAgICogQG5hbWVzcGFjZSBBc3NlcnRcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgYXNzZXJ0LnR5cGVPZiA9IGZ1bmN0aW9uICh2YWwsIHR5cGUsIG1zZykge1xuICAgIG5ldyBBc3NlcnRpb24odmFsLCBtc2cpLnRvLmJlLmEodHlwZSk7XG4gIH07XG5cbiAgLyoqXG4gICAqICMjIyAubm90VHlwZU9mKHZhbHVlLCBuYW1lLCBbbWVzc2FnZV0pXG4gICAqXG4gICAqIEFzc2VydHMgdGhhdCBgdmFsdWVgJ3MgdHlwZSBpcyBfbm90XyBgbmFtZWAsIGFzIGRldGVybWluZWQgYnlcbiAgICogYE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmdgLlxuICAgKlxuICAgKiAgICAgYXNzZXJ0Lm5vdFR5cGVPZigndGVhJywgJ251bWJlcicsICdzdHJpbmdzIGFyZSBub3QgbnVtYmVycycpO1xuICAgKlxuICAgKiBAbmFtZSBub3RUeXBlT2ZcbiAgICogQHBhcmFtIHtNaXhlZH0gdmFsdWVcbiAgICogQHBhcmFtIHtTdHJpbmd9IHR5cGVvZiBuYW1lXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlXG4gICAqIEBuYW1lc3BhY2UgQXNzZXJ0XG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIGFzc2VydC5ub3RUeXBlT2YgPSBmdW5jdGlvbiAodmFsLCB0eXBlLCBtc2cpIHtcbiAgICBuZXcgQXNzZXJ0aW9uKHZhbCwgbXNnKS50by5ub3QuYmUuYSh0eXBlKTtcbiAgfTtcblxuICAvKipcbiAgICogIyMjIC5pbnN0YW5jZU9mKG9iamVjdCwgY29uc3RydWN0b3IsIFttZXNzYWdlXSlcbiAgICpcbiAgICogQXNzZXJ0cyB0aGF0IGB2YWx1ZWAgaXMgYW4gaW5zdGFuY2Ugb2YgYGNvbnN0cnVjdG9yYC5cbiAgICpcbiAgICogICAgIHZhciBUZWEgPSBmdW5jdGlvbiAobmFtZSkgeyB0aGlzLm5hbWUgPSBuYW1lOyB9XG4gICAqICAgICAgICwgY2hhaSA9IG5ldyBUZWEoJ2NoYWknKTtcbiAgICpcbiAgICogICAgIGFzc2VydC5pbnN0YW5jZU9mKGNoYWksIFRlYSwgJ2NoYWkgaXMgYW4gaW5zdGFuY2Ugb2YgdGVhJyk7XG4gICAqXG4gICAqIEBuYW1lIGluc3RhbmNlT2ZcbiAgICogQHBhcmFtIHtPYmplY3R9IG9iamVjdFxuICAgKiBAcGFyYW0ge0NvbnN0cnVjdG9yfSBjb25zdHJ1Y3RvclxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZVxuICAgKiBAbmFtZXNwYWNlIEFzc2VydFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBhc3NlcnQuaW5zdGFuY2VPZiA9IGZ1bmN0aW9uICh2YWwsIHR5cGUsIG1zZykge1xuICAgIG5ldyBBc3NlcnRpb24odmFsLCBtc2cpLnRvLmJlLmluc3RhbmNlT2YodHlwZSk7XG4gIH07XG5cbiAgLyoqXG4gICAqICMjIyAubm90SW5zdGFuY2VPZihvYmplY3QsIGNvbnN0cnVjdG9yLCBbbWVzc2FnZV0pXG4gICAqXG4gICAqIEFzc2VydHMgYHZhbHVlYCBpcyBub3QgYW4gaW5zdGFuY2Ugb2YgYGNvbnN0cnVjdG9yYC5cbiAgICpcbiAgICogICAgIHZhciBUZWEgPSBmdW5jdGlvbiAobmFtZSkgeyB0aGlzLm5hbWUgPSBuYW1lOyB9XG4gICAqICAgICAgICwgY2hhaSA9IG5ldyBTdHJpbmcoJ2NoYWknKTtcbiAgICpcbiAgICogICAgIGFzc2VydC5ub3RJbnN0YW5jZU9mKGNoYWksIFRlYSwgJ2NoYWkgaXMgbm90IGFuIGluc3RhbmNlIG9mIHRlYScpO1xuICAgKlxuICAgKiBAbmFtZSBub3RJbnN0YW5jZU9mXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3RcbiAgICogQHBhcmFtIHtDb25zdHJ1Y3Rvcn0gY29uc3RydWN0b3JcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2VcbiAgICogQG5hbWVzcGFjZSBBc3NlcnRcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgYXNzZXJ0Lm5vdEluc3RhbmNlT2YgPSBmdW5jdGlvbiAodmFsLCB0eXBlLCBtc2cpIHtcbiAgICBuZXcgQXNzZXJ0aW9uKHZhbCwgbXNnKS50by5ub3QuYmUuaW5zdGFuY2VPZih0eXBlKTtcbiAgfTtcblxuICAvKipcbiAgICogIyMjIC5pbmNsdWRlKGhheXN0YWNrLCBuZWVkbGUsIFttZXNzYWdlXSlcbiAgICpcbiAgICogQXNzZXJ0cyB0aGF0IGBoYXlzdGFja2AgaW5jbHVkZXMgYG5lZWRsZWAuIFdvcmtzXG4gICAqIGZvciBzdHJpbmdzIGFuZCBhcnJheXMuXG4gICAqXG4gICAqICAgICBhc3NlcnQuaW5jbHVkZSgnZm9vYmFyJywgJ2JhcicsICdmb29iYXIgY29udGFpbnMgc3RyaW5nIFwiYmFyXCInKTtcbiAgICogICAgIGFzc2VydC5pbmNsdWRlKFsgMSwgMiwgMyBdLCAzLCAnYXJyYXkgY29udGFpbnMgdmFsdWUnKTtcbiAgICpcbiAgICogQG5hbWUgaW5jbHVkZVxuICAgKiBAcGFyYW0ge0FycmF5fFN0cmluZ30gaGF5c3RhY2tcbiAgICogQHBhcmFtIHtNaXhlZH0gbmVlZGxlXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlXG4gICAqIEBuYW1lc3BhY2UgQXNzZXJ0XG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIGFzc2VydC5pbmNsdWRlID0gZnVuY3Rpb24gKGV4cCwgaW5jLCBtc2cpIHtcbiAgICBuZXcgQXNzZXJ0aW9uKGV4cCwgbXNnLCBhc3NlcnQuaW5jbHVkZSkuaW5jbHVkZShpbmMpO1xuICB9O1xuXG4gIC8qKlxuICAgKiAjIyMgLm5vdEluY2x1ZGUoaGF5c3RhY2ssIG5lZWRsZSwgW21lc3NhZ2VdKVxuICAgKlxuICAgKiBBc3NlcnRzIHRoYXQgYGhheXN0YWNrYCBkb2VzIG5vdCBpbmNsdWRlIGBuZWVkbGVgLiBXb3Jrc1xuICAgKiBmb3Igc3RyaW5ncyBhbmQgYXJyYXlzLlxuICAgKlxuICAgKiAgICAgYXNzZXJ0Lm5vdEluY2x1ZGUoJ2Zvb2JhcicsICdiYXonLCAnc3RyaW5nIG5vdCBpbmNsdWRlIHN1YnN0cmluZycpO1xuICAgKiAgICAgYXNzZXJ0Lm5vdEluY2x1ZGUoWyAxLCAyLCAzIF0sIDQsICdhcnJheSBub3QgaW5jbHVkZSBjb250YWluIHZhbHVlJyk7XG4gICAqXG4gICAqIEBuYW1lIG5vdEluY2x1ZGVcbiAgICogQHBhcmFtIHtBcnJheXxTdHJpbmd9IGhheXN0YWNrXG4gICAqIEBwYXJhbSB7TWl4ZWR9IG5lZWRsZVxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZVxuICAgKiBAbmFtZXNwYWNlIEFzc2VydFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBhc3NlcnQubm90SW5jbHVkZSA9IGZ1bmN0aW9uIChleHAsIGluYywgbXNnKSB7XG4gICAgbmV3IEFzc2VydGlvbihleHAsIG1zZywgYXNzZXJ0Lm5vdEluY2x1ZGUpLm5vdC5pbmNsdWRlKGluYyk7XG4gIH07XG5cbiAgLyoqXG4gICAqICMjIyAubWF0Y2godmFsdWUsIHJlZ2V4cCwgW21lc3NhZ2VdKVxuICAgKlxuICAgKiBBc3NlcnRzIHRoYXQgYHZhbHVlYCBtYXRjaGVzIHRoZSByZWd1bGFyIGV4cHJlc3Npb24gYHJlZ2V4cGAuXG4gICAqXG4gICAqICAgICBhc3NlcnQubWF0Y2goJ2Zvb2JhcicsIC9eZm9vLywgJ3JlZ2V4cCBtYXRjaGVzJyk7XG4gICAqXG4gICAqIEBuYW1lIG1hdGNoXG4gICAqIEBwYXJhbSB7TWl4ZWR9IHZhbHVlXG4gICAqIEBwYXJhbSB7UmVnRXhwfSByZWdleHBcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2VcbiAgICogQG5hbWVzcGFjZSBBc3NlcnRcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgYXNzZXJ0Lm1hdGNoID0gZnVuY3Rpb24gKGV4cCwgcmUsIG1zZykge1xuICAgIG5ldyBBc3NlcnRpb24oZXhwLCBtc2cpLnRvLm1hdGNoKHJlKTtcbiAgfTtcblxuICAvKipcbiAgICogIyMjIC5ub3RNYXRjaCh2YWx1ZSwgcmVnZXhwLCBbbWVzc2FnZV0pXG4gICAqXG4gICAqIEFzc2VydHMgdGhhdCBgdmFsdWVgIGRvZXMgbm90IG1hdGNoIHRoZSByZWd1bGFyIGV4cHJlc3Npb24gYHJlZ2V4cGAuXG4gICAqXG4gICAqICAgICBhc3NlcnQubm90TWF0Y2goJ2Zvb2JhcicsIC9eZm9vLywgJ3JlZ2V4cCBkb2VzIG5vdCBtYXRjaCcpO1xuICAgKlxuICAgKiBAbmFtZSBub3RNYXRjaFxuICAgKiBAcGFyYW0ge01peGVkfSB2YWx1ZVxuICAgKiBAcGFyYW0ge1JlZ0V4cH0gcmVnZXhwXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlXG4gICAqIEBuYW1lc3BhY2UgQXNzZXJ0XG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIGFzc2VydC5ub3RNYXRjaCA9IGZ1bmN0aW9uIChleHAsIHJlLCBtc2cpIHtcbiAgICBuZXcgQXNzZXJ0aW9uKGV4cCwgbXNnKS50by5ub3QubWF0Y2gocmUpO1xuICB9O1xuXG4gIC8qKlxuICAgKiAjIyMgLnByb3BlcnR5KG9iamVjdCwgcHJvcGVydHksIFttZXNzYWdlXSlcbiAgICpcbiAgICogQXNzZXJ0cyB0aGF0IGBvYmplY3RgIGhhcyBhIHByb3BlcnR5IG5hbWVkIGJ5IGBwcm9wZXJ0eWAuXG4gICAqXG4gICAqICAgICBhc3NlcnQucHJvcGVydHkoeyB0ZWE6IHsgZ3JlZW46ICdtYXRjaGEnIH19LCAndGVhJyk7XG4gICAqXG4gICAqIEBuYW1lIHByb3BlcnR5XG4gICAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3RcbiAgICogQHBhcmFtIHtTdHJpbmd9IHByb3BlcnR5XG4gICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlXG4gICAqIEBuYW1lc3BhY2UgQXNzZXJ0XG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIGFzc2VydC5wcm9wZXJ0eSA9IGZ1bmN0aW9uIChvYmosIHByb3AsIG1zZykge1xuICAgIG5ldyBBc3NlcnRpb24ob2JqLCBtc2cpLnRvLmhhdmUucHJvcGVydHkocHJvcCk7XG4gIH07XG5cbiAgLyoqXG4gICAqICMjIyAubm90UHJvcGVydHkob2JqZWN0LCBwcm9wZXJ0eSwgW21lc3NhZ2VdKVxuICAgKlxuICAgKiBBc3NlcnRzIHRoYXQgYG9iamVjdGAgZG9lcyBfbm90XyBoYXZlIGEgcHJvcGVydHkgbmFtZWQgYnkgYHByb3BlcnR5YC5cbiAgICpcbiAgICogICAgIGFzc2VydC5ub3RQcm9wZXJ0eSh7IHRlYTogeyBncmVlbjogJ21hdGNoYScgfX0sICdjb2ZmZWUnKTtcbiAgICpcbiAgICogQG5hbWUgbm90UHJvcGVydHlcbiAgICogQHBhcmFtIHtPYmplY3R9IG9iamVjdFxuICAgKiBAcGFyYW0ge1N0cmluZ30gcHJvcGVydHlcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2VcbiAgICogQG5hbWVzcGFjZSBBc3NlcnRcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgYXNzZXJ0Lm5vdFByb3BlcnR5ID0gZnVuY3Rpb24gKG9iaiwgcHJvcCwgbXNnKSB7XG4gICAgbmV3IEFzc2VydGlvbihvYmosIG1zZykudG8ubm90LmhhdmUucHJvcGVydHkocHJvcCk7XG4gIH07XG5cbiAgLyoqXG4gICAqICMjIyAuZGVlcFByb3BlcnR5KG9iamVjdCwgcHJvcGVydHksIFttZXNzYWdlXSlcbiAgICpcbiAgICogQXNzZXJ0cyB0aGF0IGBvYmplY3RgIGhhcyBhIHByb3BlcnR5IG5hbWVkIGJ5IGBwcm9wZXJ0eWAsIHdoaWNoIGNhbiBiZSBhXG4gICAqIHN0cmluZyB1c2luZyBkb3QtIGFuZCBicmFja2V0LW5vdGF0aW9uIGZvciBkZWVwIHJlZmVyZW5jZS5cbiAgICpcbiAgICogICAgIGFzc2VydC5kZWVwUHJvcGVydHkoeyB0ZWE6IHsgZ3JlZW46ICdtYXRjaGEnIH19LCAndGVhLmdyZWVuJyk7XG4gICAqXG4gICAqIEBuYW1lIGRlZXBQcm9wZXJ0eVxuICAgKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0XG4gICAqIEBwYXJhbSB7U3RyaW5nfSBwcm9wZXJ0eVxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZVxuICAgKiBAbmFtZXNwYWNlIEFzc2VydFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBhc3NlcnQuZGVlcFByb3BlcnR5ID0gZnVuY3Rpb24gKG9iaiwgcHJvcCwgbXNnKSB7XG4gICAgbmV3IEFzc2VydGlvbihvYmosIG1zZykudG8uaGF2ZS5kZWVwLnByb3BlcnR5KHByb3ApO1xuICB9O1xuXG4gIC8qKlxuICAgKiAjIyMgLm5vdERlZXBQcm9wZXJ0eShvYmplY3QsIHByb3BlcnR5LCBbbWVzc2FnZV0pXG4gICAqXG4gICAqIEFzc2VydHMgdGhhdCBgb2JqZWN0YCBkb2VzIF9ub3RfIGhhdmUgYSBwcm9wZXJ0eSBuYW1lZCBieSBgcHJvcGVydHlgLCB3aGljaFxuICAgKiBjYW4gYmUgYSBzdHJpbmcgdXNpbmcgZG90LSBhbmQgYnJhY2tldC1ub3RhdGlvbiBmb3IgZGVlcCByZWZlcmVuY2UuXG4gICAqXG4gICAqICAgICBhc3NlcnQubm90RGVlcFByb3BlcnR5KHsgdGVhOiB7IGdyZWVuOiAnbWF0Y2hhJyB9fSwgJ3RlYS5vb2xvbmcnKTtcbiAgICpcbiAgICogQG5hbWUgbm90RGVlcFByb3BlcnR5XG4gICAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3RcbiAgICogQHBhcmFtIHtTdHJpbmd9IHByb3BlcnR5XG4gICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlXG4gICAqIEBuYW1lc3BhY2UgQXNzZXJ0XG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIGFzc2VydC5ub3REZWVwUHJvcGVydHkgPSBmdW5jdGlvbiAob2JqLCBwcm9wLCBtc2cpIHtcbiAgICBuZXcgQXNzZXJ0aW9uKG9iaiwgbXNnKS50by5ub3QuaGF2ZS5kZWVwLnByb3BlcnR5KHByb3ApO1xuICB9O1xuXG4gIC8qKlxuICAgKiAjIyMgLnByb3BlcnR5VmFsKG9iamVjdCwgcHJvcGVydHksIHZhbHVlLCBbbWVzc2FnZV0pXG4gICAqXG4gICAqIEFzc2VydHMgdGhhdCBgb2JqZWN0YCBoYXMgYSBwcm9wZXJ0eSBuYW1lZCBieSBgcHJvcGVydHlgIHdpdGggdmFsdWUgZ2l2ZW5cbiAgICogYnkgYHZhbHVlYC5cbiAgICpcbiAgICogICAgIGFzc2VydC5wcm9wZXJ0eVZhbCh7IHRlYTogJ2lzIGdvb2QnIH0sICd0ZWEnLCAnaXMgZ29vZCcpO1xuICAgKlxuICAgKiBAbmFtZSBwcm9wZXJ0eVZhbFxuICAgKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0XG4gICAqIEBwYXJhbSB7U3RyaW5nfSBwcm9wZXJ0eVxuICAgKiBAcGFyYW0ge01peGVkfSB2YWx1ZVxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZVxuICAgKiBAbmFtZXNwYWNlIEFzc2VydFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBhc3NlcnQucHJvcGVydHlWYWwgPSBmdW5jdGlvbiAob2JqLCBwcm9wLCB2YWwsIG1zZykge1xuICAgIG5ldyBBc3NlcnRpb24ob2JqLCBtc2cpLnRvLmhhdmUucHJvcGVydHkocHJvcCwgdmFsKTtcbiAgfTtcblxuICAvKipcbiAgICogIyMjIC5wcm9wZXJ0eU5vdFZhbChvYmplY3QsIHByb3BlcnR5LCB2YWx1ZSwgW21lc3NhZ2VdKVxuICAgKlxuICAgKiBBc3NlcnRzIHRoYXQgYG9iamVjdGAgaGFzIGEgcHJvcGVydHkgbmFtZWQgYnkgYHByb3BlcnR5YCwgYnV0IHdpdGggYSB2YWx1ZVxuICAgKiBkaWZmZXJlbnQgZnJvbSB0aGF0IGdpdmVuIGJ5IGB2YWx1ZWAuXG4gICAqXG4gICAqICAgICBhc3NlcnQucHJvcGVydHlOb3RWYWwoeyB0ZWE6ICdpcyBnb29kJyB9LCAndGVhJywgJ2lzIGJhZCcpO1xuICAgKlxuICAgKiBAbmFtZSBwcm9wZXJ0eU5vdFZhbFxuICAgKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0XG4gICAqIEBwYXJhbSB7U3RyaW5nfSBwcm9wZXJ0eVxuICAgKiBAcGFyYW0ge01peGVkfSB2YWx1ZVxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZVxuICAgKiBAbmFtZXNwYWNlIEFzc2VydFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBhc3NlcnQucHJvcGVydHlOb3RWYWwgPSBmdW5jdGlvbiAob2JqLCBwcm9wLCB2YWwsIG1zZykge1xuICAgIG5ldyBBc3NlcnRpb24ob2JqLCBtc2cpLnRvLm5vdC5oYXZlLnByb3BlcnR5KHByb3AsIHZhbCk7XG4gIH07XG5cbiAgLyoqXG4gICAqICMjIyAuZGVlcFByb3BlcnR5VmFsKG9iamVjdCwgcHJvcGVydHksIHZhbHVlLCBbbWVzc2FnZV0pXG4gICAqXG4gICAqIEFzc2VydHMgdGhhdCBgb2JqZWN0YCBoYXMgYSBwcm9wZXJ0eSBuYW1lZCBieSBgcHJvcGVydHlgIHdpdGggdmFsdWUgZ2l2ZW5cbiAgICogYnkgYHZhbHVlYC4gYHByb3BlcnR5YCBjYW4gdXNlIGRvdC0gYW5kIGJyYWNrZXQtbm90YXRpb24gZm9yIGRlZXBcbiAgICogcmVmZXJlbmNlLlxuICAgKlxuICAgKiAgICAgYXNzZXJ0LmRlZXBQcm9wZXJ0eVZhbCh7IHRlYTogeyBncmVlbjogJ21hdGNoYScgfX0sICd0ZWEuZ3JlZW4nLCAnbWF0Y2hhJyk7XG4gICAqXG4gICAqIEBuYW1lIGRlZXBQcm9wZXJ0eVZhbFxuICAgKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0XG4gICAqIEBwYXJhbSB7U3RyaW5nfSBwcm9wZXJ0eVxuICAgKiBAcGFyYW0ge01peGVkfSB2YWx1ZVxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZVxuICAgKiBAbmFtZXNwYWNlIEFzc2VydFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBhc3NlcnQuZGVlcFByb3BlcnR5VmFsID0gZnVuY3Rpb24gKG9iaiwgcHJvcCwgdmFsLCBtc2cpIHtcbiAgICBuZXcgQXNzZXJ0aW9uKG9iaiwgbXNnKS50by5oYXZlLmRlZXAucHJvcGVydHkocHJvcCwgdmFsKTtcbiAgfTtcblxuICAvKipcbiAgICogIyMjIC5kZWVwUHJvcGVydHlOb3RWYWwob2JqZWN0LCBwcm9wZXJ0eSwgdmFsdWUsIFttZXNzYWdlXSlcbiAgICpcbiAgICogQXNzZXJ0cyB0aGF0IGBvYmplY3RgIGhhcyBhIHByb3BlcnR5IG5hbWVkIGJ5IGBwcm9wZXJ0eWAsIGJ1dCB3aXRoIGEgdmFsdWVcbiAgICogZGlmZmVyZW50IGZyb20gdGhhdCBnaXZlbiBieSBgdmFsdWVgLiBgcHJvcGVydHlgIGNhbiB1c2UgZG90LSBhbmRcbiAgICogYnJhY2tldC1ub3RhdGlvbiBmb3IgZGVlcCByZWZlcmVuY2UuXG4gICAqXG4gICAqICAgICBhc3NlcnQuZGVlcFByb3BlcnR5Tm90VmFsKHsgdGVhOiB7IGdyZWVuOiAnbWF0Y2hhJyB9fSwgJ3RlYS5ncmVlbicsICdrb25hY2hhJyk7XG4gICAqXG4gICAqIEBuYW1lIGRlZXBQcm9wZXJ0eU5vdFZhbFxuICAgKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0XG4gICAqIEBwYXJhbSB7U3RyaW5nfSBwcm9wZXJ0eVxuICAgKiBAcGFyYW0ge01peGVkfSB2YWx1ZVxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZVxuICAgKiBAbmFtZXNwYWNlIEFzc2VydFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBhc3NlcnQuZGVlcFByb3BlcnR5Tm90VmFsID0gZnVuY3Rpb24gKG9iaiwgcHJvcCwgdmFsLCBtc2cpIHtcbiAgICBuZXcgQXNzZXJ0aW9uKG9iaiwgbXNnKS50by5ub3QuaGF2ZS5kZWVwLnByb3BlcnR5KHByb3AsIHZhbCk7XG4gIH07XG5cbiAgLyoqXG4gICAqICMjIyAubGVuZ3RoT2Yob2JqZWN0LCBsZW5ndGgsIFttZXNzYWdlXSlcbiAgICpcbiAgICogQXNzZXJ0cyB0aGF0IGBvYmplY3RgIGhhcyBhIGBsZW5ndGhgIHByb3BlcnR5IHdpdGggdGhlIGV4cGVjdGVkIHZhbHVlLlxuICAgKlxuICAgKiAgICAgYXNzZXJ0Lmxlbmd0aE9mKFsxLDIsM10sIDMsICdhcnJheSBoYXMgbGVuZ3RoIG9mIDMnKTtcbiAgICogICAgIGFzc2VydC5sZW5ndGhPZignZm9vYmFyJywgNiwgJ3N0cmluZyBoYXMgbGVuZ3RoIG9mIDYnKTtcbiAgICpcbiAgICogQG5hbWUgbGVuZ3RoT2ZcbiAgICogQHBhcmFtIHtNaXhlZH0gb2JqZWN0XG4gICAqIEBwYXJhbSB7TnVtYmVyfSBsZW5ndGhcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2VcbiAgICogQG5hbWVzcGFjZSBBc3NlcnRcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgYXNzZXJ0Lmxlbmd0aE9mID0gZnVuY3Rpb24gKGV4cCwgbGVuLCBtc2cpIHtcbiAgICBuZXcgQXNzZXJ0aW9uKGV4cCwgbXNnKS50by5oYXZlLmxlbmd0aChsZW4pO1xuICB9O1xuXG4gIC8qKlxuICAgKiAjIyMgLnRocm93cyhmdW5jdGlvbiwgW2NvbnN0cnVjdG9yL3N0cmluZy9yZWdleHBdLCBbc3RyaW5nL3JlZ2V4cF0sIFttZXNzYWdlXSlcbiAgICpcbiAgICogQXNzZXJ0cyB0aGF0IGBmdW5jdGlvbmAgd2lsbCB0aHJvdyBhbiBlcnJvciB0aGF0IGlzIGFuIGluc3RhbmNlIG9mXG4gICAqIGBjb25zdHJ1Y3RvcmAsIG9yIGFsdGVybmF0ZWx5IHRoYXQgaXQgd2lsbCB0aHJvdyBhbiBlcnJvciB3aXRoIG1lc3NhZ2VcbiAgICogbWF0Y2hpbmcgYHJlZ2V4cGAuXG4gICAqXG4gICAqICAgICBhc3NlcnQudGhyb3dzKGZuLCAnZnVuY3Rpb24gdGhyb3dzIGEgcmVmZXJlbmNlIGVycm9yJyk7XG4gICAqICAgICBhc3NlcnQudGhyb3dzKGZuLCAvZnVuY3Rpb24gdGhyb3dzIGEgcmVmZXJlbmNlIGVycm9yLyk7XG4gICAqICAgICBhc3NlcnQudGhyb3dzKGZuLCBSZWZlcmVuY2VFcnJvcik7XG4gICAqICAgICBhc3NlcnQudGhyb3dzKGZuLCBSZWZlcmVuY2VFcnJvciwgJ2Z1bmN0aW9uIHRocm93cyBhIHJlZmVyZW5jZSBlcnJvcicpO1xuICAgKiAgICAgYXNzZXJ0LnRocm93cyhmbiwgUmVmZXJlbmNlRXJyb3IsIC9mdW5jdGlvbiB0aHJvd3MgYSByZWZlcmVuY2UgZXJyb3IvKTtcbiAgICpcbiAgICogQG5hbWUgdGhyb3dzXG4gICAqIEBhbGlhcyB0aHJvd1xuICAgKiBAYWxpYXMgVGhyb3dcbiAgICogQHBhcmFtIHtGdW5jdGlvbn0gZnVuY3Rpb25cbiAgICogQHBhcmFtIHtFcnJvckNvbnN0cnVjdG9yfSBjb25zdHJ1Y3RvclxuICAgKiBAcGFyYW0ge1JlZ0V4cH0gcmVnZXhwXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlXG4gICAqIEBzZWUgaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4vSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvRXJyb3IjRXJyb3JfdHlwZXNcbiAgICogQG5hbWVzcGFjZSBBc3NlcnRcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgYXNzZXJ0LnRocm93cyA9IGZ1bmN0aW9uIChmbiwgZXJydCwgZXJycywgbXNnKSB7XG4gICAgaWYgKCdzdHJpbmcnID09PSB0eXBlb2YgZXJydCB8fCBlcnJ0IGluc3RhbmNlb2YgUmVnRXhwKSB7XG4gICAgICBlcnJzID0gZXJydDtcbiAgICAgIGVycnQgPSBudWxsO1xuICAgIH1cblxuICAgIHZhciBhc3NlcnRFcnIgPSBuZXcgQXNzZXJ0aW9uKGZuLCBtc2cpLnRvLnRocm93KGVycnQsIGVycnMpO1xuICAgIHJldHVybiBmbGFnKGFzc2VydEVyciwgJ29iamVjdCcpO1xuICB9O1xuXG4gIC8qKlxuICAgKiAjIyMgLmRvZXNOb3RUaHJvdyhmdW5jdGlvbiwgW2NvbnN0cnVjdG9yL3JlZ2V4cF0sIFttZXNzYWdlXSlcbiAgICpcbiAgICogQXNzZXJ0cyB0aGF0IGBmdW5jdGlvbmAgd2lsbCBfbm90XyB0aHJvdyBhbiBlcnJvciB0aGF0IGlzIGFuIGluc3RhbmNlIG9mXG4gICAqIGBjb25zdHJ1Y3RvcmAsIG9yIGFsdGVybmF0ZWx5IHRoYXQgaXQgd2lsbCBub3QgdGhyb3cgYW4gZXJyb3Igd2l0aCBtZXNzYWdlXG4gICAqIG1hdGNoaW5nIGByZWdleHBgLlxuICAgKlxuICAgKiAgICAgYXNzZXJ0LmRvZXNOb3RUaHJvdyhmbiwgRXJyb3IsICdmdW5jdGlvbiBkb2VzIG5vdCB0aHJvdycpO1xuICAgKlxuICAgKiBAbmFtZSBkb2VzTm90VGhyb3dcbiAgICogQHBhcmFtIHtGdW5jdGlvbn0gZnVuY3Rpb25cbiAgICogQHBhcmFtIHtFcnJvckNvbnN0cnVjdG9yfSBjb25zdHJ1Y3RvclxuICAgKiBAcGFyYW0ge1JlZ0V4cH0gcmVnZXhwXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlXG4gICAqIEBzZWUgaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4vSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvRXJyb3IjRXJyb3JfdHlwZXNcbiAgICogQG5hbWVzcGFjZSBBc3NlcnRcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgYXNzZXJ0LmRvZXNOb3RUaHJvdyA9IGZ1bmN0aW9uIChmbiwgdHlwZSwgbXNnKSB7XG4gICAgaWYgKCdzdHJpbmcnID09PSB0eXBlb2YgdHlwZSkge1xuICAgICAgbXNnID0gdHlwZTtcbiAgICAgIHR5cGUgPSBudWxsO1xuICAgIH1cblxuICAgIG5ldyBBc3NlcnRpb24oZm4sIG1zZykudG8ubm90LlRocm93KHR5cGUpO1xuICB9O1xuXG4gIC8qKlxuICAgKiAjIyMgLm9wZXJhdG9yKHZhbDEsIG9wZXJhdG9yLCB2YWwyLCBbbWVzc2FnZV0pXG4gICAqXG4gICAqIENvbXBhcmVzIHR3byB2YWx1ZXMgdXNpbmcgYG9wZXJhdG9yYC5cbiAgICpcbiAgICogICAgIGFzc2VydC5vcGVyYXRvcigxLCAnPCcsIDIsICdldmVyeXRoaW5nIGlzIG9rJyk7XG4gICAqICAgICBhc3NlcnQub3BlcmF0b3IoMSwgJz4nLCAyLCAndGhpcyB3aWxsIGZhaWwnKTtcbiAgICpcbiAgICogQG5hbWUgb3BlcmF0b3JcbiAgICogQHBhcmFtIHtNaXhlZH0gdmFsMVxuICAgKiBAcGFyYW0ge1N0cmluZ30gb3BlcmF0b3JcbiAgICogQHBhcmFtIHtNaXhlZH0gdmFsMlxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZVxuICAgKiBAbmFtZXNwYWNlIEFzc2VydFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBhc3NlcnQub3BlcmF0b3IgPSBmdW5jdGlvbiAodmFsLCBvcGVyYXRvciwgdmFsMiwgbXNnKSB7XG4gICAgdmFyIG9rO1xuICAgIHN3aXRjaChvcGVyYXRvcikge1xuICAgICAgY2FzZSAnPT0nOlxuICAgICAgICBvayA9IHZhbCA9PSB2YWwyO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJz09PSc6XG4gICAgICAgIG9rID0gdmFsID09PSB2YWwyO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJz4nOlxuICAgICAgICBvayA9IHZhbCA+IHZhbDI7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnPj0nOlxuICAgICAgICBvayA9IHZhbCA+PSB2YWwyO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJzwnOlxuICAgICAgICBvayA9IHZhbCA8IHZhbDI7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnPD0nOlxuICAgICAgICBvayA9IHZhbCA8PSB2YWwyO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJyE9JzpcbiAgICAgICAgb2sgPSB2YWwgIT0gdmFsMjtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICchPT0nOlxuICAgICAgICBvayA9IHZhbCAhPT0gdmFsMjtcbiAgICAgICAgYnJlYWs7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgb3BlcmF0b3IgXCInICsgb3BlcmF0b3IgKyAnXCInKTtcbiAgICB9XG4gICAgdmFyIHRlc3QgPSBuZXcgQXNzZXJ0aW9uKG9rLCBtc2cpO1xuICAgIHRlc3QuYXNzZXJ0KFxuICAgICAgICB0cnVlID09PSBmbGFnKHRlc3QsICdvYmplY3QnKVxuICAgICAgLCAnZXhwZWN0ZWQgJyArIHV0aWwuaW5zcGVjdCh2YWwpICsgJyB0byBiZSAnICsgb3BlcmF0b3IgKyAnICcgKyB1dGlsLmluc3BlY3QodmFsMilcbiAgICAgICwgJ2V4cGVjdGVkICcgKyB1dGlsLmluc3BlY3QodmFsKSArICcgdG8gbm90IGJlICcgKyBvcGVyYXRvciArICcgJyArIHV0aWwuaW5zcGVjdCh2YWwyKSApO1xuICB9O1xuXG4gIC8qKlxuICAgKiAjIyMgLmNsb3NlVG8oYWN0dWFsLCBleHBlY3RlZCwgZGVsdGEsIFttZXNzYWdlXSlcbiAgICpcbiAgICogQXNzZXJ0cyB0aGF0IHRoZSB0YXJnZXQgaXMgZXF1YWwgYGV4cGVjdGVkYCwgdG8gd2l0aGluIGEgKy8tIGBkZWx0YWAgcmFuZ2UuXG4gICAqXG4gICAqICAgICBhc3NlcnQuY2xvc2VUbygxLjUsIDEsIDAuNSwgJ251bWJlcnMgYXJlIGNsb3NlJyk7XG4gICAqXG4gICAqIEBuYW1lIGNsb3NlVG9cbiAgICogQHBhcmFtIHtOdW1iZXJ9IGFjdHVhbFxuICAgKiBAcGFyYW0ge051bWJlcn0gZXhwZWN0ZWRcbiAgICogQHBhcmFtIHtOdW1iZXJ9IGRlbHRhXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlXG4gICAqIEBuYW1lc3BhY2UgQXNzZXJ0XG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIGFzc2VydC5jbG9zZVRvID0gZnVuY3Rpb24gKGFjdCwgZXhwLCBkZWx0YSwgbXNnKSB7XG4gICAgbmV3IEFzc2VydGlvbihhY3QsIG1zZykudG8uYmUuY2xvc2VUbyhleHAsIGRlbHRhKTtcbiAgfTtcblxuICAvKipcbiAgICogIyMjIC5hcHByb3hpbWF0ZWx5KGFjdHVhbCwgZXhwZWN0ZWQsIGRlbHRhLCBbbWVzc2FnZV0pXG4gICAqXG4gICAqIEFzc2VydHMgdGhhdCB0aGUgdGFyZ2V0IGlzIGVxdWFsIGBleHBlY3RlZGAsIHRvIHdpdGhpbiBhICsvLSBgZGVsdGFgIHJhbmdlLlxuICAgKlxuICAgKiAgICAgYXNzZXJ0LmFwcHJveGltYXRlbHkoMS41LCAxLCAwLjUsICdudW1iZXJzIGFyZSBjbG9zZScpO1xuICAgKlxuICAgKiBAbmFtZSBhcHByb3hpbWF0ZWx5XG4gICAqIEBwYXJhbSB7TnVtYmVyfSBhY3R1YWxcbiAgICogQHBhcmFtIHtOdW1iZXJ9IGV4cGVjdGVkXG4gICAqIEBwYXJhbSB7TnVtYmVyfSBkZWx0YVxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZVxuICAgKiBAbmFtZXNwYWNlIEFzc2VydFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBhc3NlcnQuYXBwcm94aW1hdGVseSA9IGZ1bmN0aW9uIChhY3QsIGV4cCwgZGVsdGEsIG1zZykge1xuICAgIG5ldyBBc3NlcnRpb24oYWN0LCBtc2cpLnRvLmJlLmFwcHJveGltYXRlbHkoZXhwLCBkZWx0YSk7XG4gIH07XG5cbiAgLyoqXG4gICAqICMjIyAuc2FtZU1lbWJlcnMoc2V0MSwgc2V0MiwgW21lc3NhZ2VdKVxuICAgKlxuICAgKiBBc3NlcnRzIHRoYXQgYHNldDFgIGFuZCBgc2V0MmAgaGF2ZSB0aGUgc2FtZSBtZW1iZXJzLlxuICAgKiBPcmRlciBpcyBub3QgdGFrZW4gaW50byBhY2NvdW50LlxuICAgKlxuICAgKiAgICAgYXNzZXJ0LnNhbWVNZW1iZXJzKFsgMSwgMiwgMyBdLCBbIDIsIDEsIDMgXSwgJ3NhbWUgbWVtYmVycycpO1xuICAgKlxuICAgKiBAbmFtZSBzYW1lTWVtYmVyc1xuICAgKiBAcGFyYW0ge0FycmF5fSBzZXQxXG4gICAqIEBwYXJhbSB7QXJyYXl9IHNldDJcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2VcbiAgICogQG5hbWVzcGFjZSBBc3NlcnRcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgYXNzZXJ0LnNhbWVNZW1iZXJzID0gZnVuY3Rpb24gKHNldDEsIHNldDIsIG1zZykge1xuICAgIG5ldyBBc3NlcnRpb24oc2V0MSwgbXNnKS50by5oYXZlLnNhbWUubWVtYmVycyhzZXQyKTtcbiAgfVxuXG4gIC8qKlxuICAgKiAjIyMgLnNhbWVEZWVwTWVtYmVycyhzZXQxLCBzZXQyLCBbbWVzc2FnZV0pXG4gICAqXG4gICAqIEFzc2VydHMgdGhhdCBgc2V0MWAgYW5kIGBzZXQyYCBoYXZlIHRoZSBzYW1lIG1lbWJlcnMgLSB1c2luZyBhIGRlZXAgZXF1YWxpdHkgY2hlY2tpbmcuXG4gICAqIE9yZGVyIGlzIG5vdCB0YWtlbiBpbnRvIGFjY291bnQuXG4gICAqXG4gICAqICAgICBhc3NlcnQuc2FtZURlZXBNZW1iZXJzKFsge2I6IDN9LCB7YTogMn0sIHtjOiA1fSBdLCBbIHtjOiA1fSwge2I6IDN9LCB7YTogMn0gXSwgJ3NhbWUgZGVlcCBtZW1iZXJzJyk7XG4gICAqXG4gICAqIEBuYW1lIHNhbWVEZWVwTWVtYmVyc1xuICAgKiBAcGFyYW0ge0FycmF5fSBzZXQxXG4gICAqIEBwYXJhbSB7QXJyYXl9IHNldDJcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2VcbiAgICogQG5hbWVzcGFjZSBBc3NlcnRcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgYXNzZXJ0LnNhbWVEZWVwTWVtYmVycyA9IGZ1bmN0aW9uIChzZXQxLCBzZXQyLCBtc2cpIHtcbiAgICBuZXcgQXNzZXJ0aW9uKHNldDEsIG1zZykudG8uaGF2ZS5zYW1lLmRlZXAubWVtYmVycyhzZXQyKTtcbiAgfVxuXG4gIC8qKlxuICAgKiAjIyMgLmluY2x1ZGVNZW1iZXJzKHN1cGVyc2V0LCBzdWJzZXQsIFttZXNzYWdlXSlcbiAgICpcbiAgICogQXNzZXJ0cyB0aGF0IGBzdWJzZXRgIGlzIGluY2x1ZGVkIGluIGBzdXBlcnNldGAuXG4gICAqIE9yZGVyIGlzIG5vdCB0YWtlbiBpbnRvIGFjY291bnQuXG4gICAqXG4gICAqICAgICBhc3NlcnQuaW5jbHVkZU1lbWJlcnMoWyAxLCAyLCAzIF0sIFsgMiwgMSBdLCAnaW5jbHVkZSBtZW1iZXJzJyk7XG4gICAqXG4gICAqIEBuYW1lIGluY2x1ZGVNZW1iZXJzXG4gICAqIEBwYXJhbSB7QXJyYXl9IHN1cGVyc2V0XG4gICAqIEBwYXJhbSB7QXJyYXl9IHN1YnNldFxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZVxuICAgKiBAbmFtZXNwYWNlIEFzc2VydFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBhc3NlcnQuaW5jbHVkZU1lbWJlcnMgPSBmdW5jdGlvbiAoc3VwZXJzZXQsIHN1YnNldCwgbXNnKSB7XG4gICAgbmV3IEFzc2VydGlvbihzdXBlcnNldCwgbXNnKS50by5pbmNsdWRlLm1lbWJlcnMoc3Vic2V0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiAjIyMgLmluY2x1ZGVEZWVwTWVtYmVycyhzdXBlcnNldCwgc3Vic2V0LCBbbWVzc2FnZV0pXG4gICAqXG4gICAqIEFzc2VydHMgdGhhdCBgc3Vic2V0YCBpcyBpbmNsdWRlZCBpbiBgc3VwZXJzZXRgIC0gdXNpbmcgZGVlcCBlcXVhbGl0eSBjaGVja2luZy5cbiAgICogT3JkZXIgaXMgbm90IHRha2VuIGludG8gYWNjb3VudC5cbiAgICogRHVwbGljYXRlcyBhcmUgaWdub3JlZC5cbiAgICpcbiAgICogICAgIGFzc2VydC5pbmNsdWRlRGVlcE1lbWJlcnMoWyB7YTogMX0sIHtiOiAyfSwge2M6IDN9IF0sIFsge2I6IDJ9LCB7YTogMX0sIHtiOiAyfSBdLCAnaW5jbHVkZSBkZWVwIG1lbWJlcnMnKTtcbiAgICpcbiAgICogQG5hbWUgaW5jbHVkZURlZXBNZW1iZXJzXG4gICAqIEBwYXJhbSB7QXJyYXl9IHN1cGVyc2V0XG4gICAqIEBwYXJhbSB7QXJyYXl9IHN1YnNldFxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZVxuICAgKiBAbmFtZXNwYWNlIEFzc2VydFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBhc3NlcnQuaW5jbHVkZURlZXBNZW1iZXJzID0gZnVuY3Rpb24gKHN1cGVyc2V0LCBzdWJzZXQsIG1zZykge1xuICAgIG5ldyBBc3NlcnRpb24oc3VwZXJzZXQsIG1zZykudG8uaW5jbHVkZS5kZWVwLm1lbWJlcnMoc3Vic2V0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiAjIyMgLm9uZU9mKGluTGlzdCwgbGlzdCwgW21lc3NhZ2VdKVxuICAgKlxuICAgKiBBc3NlcnRzIHRoYXQgbm9uLW9iamVjdCwgbm9uLWFycmF5IHZhbHVlIGBpbkxpc3RgIGFwcGVhcnMgaW4gdGhlIGZsYXQgYXJyYXkgYGxpc3RgLlxuICAgKlxuICAgKiAgICAgYXNzZXJ0Lm9uZU9mKDEsIFsgMiwgMSBdLCAnTm90IGZvdW5kIGluIGxpc3QnKTtcbiAgICpcbiAgICogQG5hbWUgb25lT2ZcbiAgICogQHBhcmFtIHsqfSBpbkxpc3RcbiAgICogQHBhcmFtIHtBcnJheTwqPn0gbGlzdFxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZVxuICAgKiBAbmFtZXNwYWNlIEFzc2VydFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBhc3NlcnQub25lT2YgPSBmdW5jdGlvbiAoaW5MaXN0LCBsaXN0LCBtc2cpIHtcbiAgICBuZXcgQXNzZXJ0aW9uKGluTGlzdCwgbXNnKS50by5iZS5vbmVPZihsaXN0KTtcbiAgfVxuXG4gICAvKipcbiAgICogIyMjIC5jaGFuZ2VzKGZ1bmN0aW9uLCBvYmplY3QsIHByb3BlcnR5KVxuICAgKlxuICAgKiBBc3NlcnRzIHRoYXQgYSBmdW5jdGlvbiBjaGFuZ2VzIHRoZSB2YWx1ZSBvZiBhIHByb3BlcnR5XG4gICAqXG4gICAqICAgICB2YXIgb2JqID0geyB2YWw6IDEwIH07XG4gICAqICAgICB2YXIgZm4gPSBmdW5jdGlvbigpIHsgb2JqLnZhbCA9IDIyIH07XG4gICAqICAgICBhc3NlcnQuY2hhbmdlcyhmbiwgb2JqLCAndmFsJyk7XG4gICAqXG4gICAqIEBuYW1lIGNoYW5nZXNcbiAgICogQHBhcmFtIHtGdW5jdGlvbn0gbW9kaWZpZXIgZnVuY3Rpb25cbiAgICogQHBhcmFtIHtPYmplY3R9IG9iamVjdFxuICAgKiBAcGFyYW0ge1N0cmluZ30gcHJvcGVydHkgbmFtZVxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZSBfb3B0aW9uYWxfXG4gICAqIEBuYW1lc3BhY2UgQXNzZXJ0XG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIGFzc2VydC5jaGFuZ2VzID0gZnVuY3Rpb24gKGZuLCBvYmosIHByb3ApIHtcbiAgICBuZXcgQXNzZXJ0aW9uKGZuKS50by5jaGFuZ2Uob2JqLCBwcm9wKTtcbiAgfVxuXG4gICAvKipcbiAgICogIyMjIC5kb2VzTm90Q2hhbmdlKGZ1bmN0aW9uLCBvYmplY3QsIHByb3BlcnR5KVxuICAgKlxuICAgKiBBc3NlcnRzIHRoYXQgYSBmdW5jdGlvbiBkb2VzIG5vdCBjaGFuZ2VzIHRoZSB2YWx1ZSBvZiBhIHByb3BlcnR5XG4gICAqXG4gICAqICAgICB2YXIgb2JqID0geyB2YWw6IDEwIH07XG4gICAqICAgICB2YXIgZm4gPSBmdW5jdGlvbigpIHsgY29uc29sZS5sb2coJ2ZvbycpOyB9O1xuICAgKiAgICAgYXNzZXJ0LmRvZXNOb3RDaGFuZ2UoZm4sIG9iaiwgJ3ZhbCcpO1xuICAgKlxuICAgKiBAbmFtZSBkb2VzTm90Q2hhbmdlXG4gICAqIEBwYXJhbSB7RnVuY3Rpb259IG1vZGlmaWVyIGZ1bmN0aW9uXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3RcbiAgICogQHBhcmFtIHtTdHJpbmd9IHByb3BlcnR5IG5hbWVcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2UgX29wdGlvbmFsX1xuICAgKiBAbmFtZXNwYWNlIEFzc2VydFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBhc3NlcnQuZG9lc05vdENoYW5nZSA9IGZ1bmN0aW9uIChmbiwgb2JqLCBwcm9wKSB7XG4gICAgbmV3IEFzc2VydGlvbihmbikudG8ubm90LmNoYW5nZShvYmosIHByb3ApO1xuICB9XG5cbiAgIC8qKlxuICAgKiAjIyMgLmluY3JlYXNlcyhmdW5jdGlvbiwgb2JqZWN0LCBwcm9wZXJ0eSlcbiAgICpcbiAgICogQXNzZXJ0cyB0aGF0IGEgZnVuY3Rpb24gaW5jcmVhc2VzIGFuIG9iamVjdCBwcm9wZXJ0eVxuICAgKlxuICAgKiAgICAgdmFyIG9iaiA9IHsgdmFsOiAxMCB9O1xuICAgKiAgICAgdmFyIGZuID0gZnVuY3Rpb24oKSB7IG9iai52YWwgPSAxMyB9O1xuICAgKiAgICAgYXNzZXJ0LmluY3JlYXNlcyhmbiwgb2JqLCAndmFsJyk7XG4gICAqXG4gICAqIEBuYW1lIGluY3JlYXNlc1xuICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBtb2RpZmllciBmdW5jdGlvblxuICAgKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0XG4gICAqIEBwYXJhbSB7U3RyaW5nfSBwcm9wZXJ0eSBuYW1lXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlIF9vcHRpb25hbF9cbiAgICogQG5hbWVzcGFjZSBBc3NlcnRcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgYXNzZXJ0LmluY3JlYXNlcyA9IGZ1bmN0aW9uIChmbiwgb2JqLCBwcm9wKSB7XG4gICAgbmV3IEFzc2VydGlvbihmbikudG8uaW5jcmVhc2Uob2JqLCBwcm9wKTtcbiAgfVxuXG4gICAvKipcbiAgICogIyMjIC5kb2VzTm90SW5jcmVhc2UoZnVuY3Rpb24sIG9iamVjdCwgcHJvcGVydHkpXG4gICAqXG4gICAqIEFzc2VydHMgdGhhdCBhIGZ1bmN0aW9uIGRvZXMgbm90IGluY3JlYXNlIG9iamVjdCBwcm9wZXJ0eVxuICAgKlxuICAgKiAgICAgdmFyIG9iaiA9IHsgdmFsOiAxMCB9O1xuICAgKiAgICAgdmFyIGZuID0gZnVuY3Rpb24oKSB7IG9iai52YWwgPSA4IH07XG4gICAqICAgICBhc3NlcnQuZG9lc05vdEluY3JlYXNlKGZuLCBvYmosICd2YWwnKTtcbiAgICpcbiAgICogQG5hbWUgZG9lc05vdEluY3JlYXNlXG4gICAqIEBwYXJhbSB7RnVuY3Rpb259IG1vZGlmaWVyIGZ1bmN0aW9uXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3RcbiAgICogQHBhcmFtIHtTdHJpbmd9IHByb3BlcnR5IG5hbWVcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2UgX29wdGlvbmFsX1xuICAgKiBAbmFtZXNwYWNlIEFzc2VydFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBhc3NlcnQuZG9lc05vdEluY3JlYXNlID0gZnVuY3Rpb24gKGZuLCBvYmosIHByb3ApIHtcbiAgICBuZXcgQXNzZXJ0aW9uKGZuKS50by5ub3QuaW5jcmVhc2Uob2JqLCBwcm9wKTtcbiAgfVxuXG4gICAvKipcbiAgICogIyMjIC5kZWNyZWFzZXMoZnVuY3Rpb24sIG9iamVjdCwgcHJvcGVydHkpXG4gICAqXG4gICAqIEFzc2VydHMgdGhhdCBhIGZ1bmN0aW9uIGRlY3JlYXNlcyBhbiBvYmplY3QgcHJvcGVydHlcbiAgICpcbiAgICogICAgIHZhciBvYmogPSB7IHZhbDogMTAgfTtcbiAgICogICAgIHZhciBmbiA9IGZ1bmN0aW9uKCkgeyBvYmoudmFsID0gNSB9O1xuICAgKiAgICAgYXNzZXJ0LmRlY3JlYXNlcyhmbiwgb2JqLCAndmFsJyk7XG4gICAqXG4gICAqIEBuYW1lIGRlY3JlYXNlc1xuICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBtb2RpZmllciBmdW5jdGlvblxuICAgKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0XG4gICAqIEBwYXJhbSB7U3RyaW5nfSBwcm9wZXJ0eSBuYW1lXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlIF9vcHRpb25hbF9cbiAgICogQG5hbWVzcGFjZSBBc3NlcnRcbiAgICogQGFwaSBwdWJsaWNcbiAgICovXG5cbiAgYXNzZXJ0LmRlY3JlYXNlcyA9IGZ1bmN0aW9uIChmbiwgb2JqLCBwcm9wKSB7XG4gICAgbmV3IEFzc2VydGlvbihmbikudG8uZGVjcmVhc2Uob2JqLCBwcm9wKTtcbiAgfVxuXG4gICAvKipcbiAgICogIyMjIC5kb2VzTm90RGVjcmVhc2UoZnVuY3Rpb24sIG9iamVjdCwgcHJvcGVydHkpXG4gICAqXG4gICAqIEFzc2VydHMgdGhhdCBhIGZ1bmN0aW9uIGRvZXMgbm90IGRlY3JlYXNlcyBhbiBvYmplY3QgcHJvcGVydHlcbiAgICpcbiAgICogICAgIHZhciBvYmogPSB7IHZhbDogMTAgfTtcbiAgICogICAgIHZhciBmbiA9IGZ1bmN0aW9uKCkgeyBvYmoudmFsID0gMTUgfTtcbiAgICogICAgIGFzc2VydC5kb2VzTm90RGVjcmVhc2UoZm4sIG9iaiwgJ3ZhbCcpO1xuICAgKlxuICAgKiBAbmFtZSBkb2VzTm90RGVjcmVhc2VcbiAgICogQHBhcmFtIHtGdW5jdGlvbn0gbW9kaWZpZXIgZnVuY3Rpb25cbiAgICogQHBhcmFtIHtPYmplY3R9IG9iamVjdFxuICAgKiBAcGFyYW0ge1N0cmluZ30gcHJvcGVydHkgbmFtZVxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZSBfb3B0aW9uYWxfXG4gICAqIEBuYW1lc3BhY2UgQXNzZXJ0XG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIGFzc2VydC5kb2VzTm90RGVjcmVhc2UgPSBmdW5jdGlvbiAoZm4sIG9iaiwgcHJvcCkge1xuICAgIG5ldyBBc3NlcnRpb24oZm4pLnRvLm5vdC5kZWNyZWFzZShvYmosIHByb3ApO1xuICB9XG5cbiAgLyohXG4gICAqICMjIyAuaWZFcnJvcihvYmplY3QpXG4gICAqXG4gICAqIEFzc2VydHMgaWYgdmFsdWUgaXMgbm90IGEgZmFsc2UgdmFsdWUsIGFuZCB0aHJvd3MgaWYgaXQgaXMgYSB0cnVlIHZhbHVlLlxuICAgKiBUaGlzIGlzIGFkZGVkIHRvIGFsbG93IGZvciBjaGFpIHRvIGJlIGEgZHJvcC1pbiByZXBsYWNlbWVudCBmb3IgTm9kZSdzXG4gICAqIGFzc2VydCBjbGFzcy5cbiAgICpcbiAgICogICAgIHZhciBlcnIgPSBuZXcgRXJyb3IoJ0kgYW0gYSBjdXN0b20gZXJyb3InKTtcbiAgICogICAgIGFzc2VydC5pZkVycm9yKGVycik7IC8vIFJldGhyb3dzIGVyciFcbiAgICpcbiAgICogQG5hbWUgaWZFcnJvclxuICAgKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0XG4gICAqIEBuYW1lc3BhY2UgQXNzZXJ0XG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIGFzc2VydC5pZkVycm9yID0gZnVuY3Rpb24gKHZhbCkge1xuICAgIGlmICh2YWwpIHtcbiAgICAgIHRocm93KHZhbCk7XG4gICAgfVxuICB9O1xuXG4gIC8qKlxuICAgKiAjIyMgLmlzRXh0ZW5zaWJsZShvYmplY3QpXG4gICAqXG4gICAqIEFzc2VydHMgdGhhdCBgb2JqZWN0YCBpcyBleHRlbnNpYmxlIChjYW4gaGF2ZSBuZXcgcHJvcGVydGllcyBhZGRlZCB0byBpdCkuXG4gICAqXG4gICAqICAgICBhc3NlcnQuaXNFeHRlbnNpYmxlKHt9KTtcbiAgICpcbiAgICogQG5hbWUgaXNFeHRlbnNpYmxlXG4gICAqIEBhbGlhcyBleHRlbnNpYmxlXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3RcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2UgX29wdGlvbmFsX1xuICAgKiBAbmFtZXNwYWNlIEFzc2VydFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBhc3NlcnQuaXNFeHRlbnNpYmxlID0gZnVuY3Rpb24gKG9iaiwgbXNnKSB7XG4gICAgbmV3IEFzc2VydGlvbihvYmosIG1zZykudG8uYmUuZXh0ZW5zaWJsZTtcbiAgfTtcblxuICAvKipcbiAgICogIyMjIC5pc05vdEV4dGVuc2libGUob2JqZWN0KVxuICAgKlxuICAgKiBBc3NlcnRzIHRoYXQgYG9iamVjdGAgaXMgX25vdF8gZXh0ZW5zaWJsZS5cbiAgICpcbiAgICogICAgIHZhciBub25FeHRlbnNpYmxlT2JqZWN0ID0gT2JqZWN0LnByZXZlbnRFeHRlbnNpb25zKHt9KTtcbiAgICogICAgIHZhciBzZWFsZWRPYmplY3QgPSBPYmplY3Quc2VhbCh7fSk7XG4gICAqICAgICB2YXIgZnJvemVuT2JqZWN0ID0gT2JqZWN0LmZyZWVzZSh7fSk7XG4gICAqXG4gICAqICAgICBhc3NlcnQuaXNOb3RFeHRlbnNpYmxlKG5vbkV4dGVuc2libGVPYmplY3QpO1xuICAgKiAgICAgYXNzZXJ0LmlzTm90RXh0ZW5zaWJsZShzZWFsZWRPYmplY3QpO1xuICAgKiAgICAgYXNzZXJ0LmlzTm90RXh0ZW5zaWJsZShmcm96ZW5PYmplY3QpO1xuICAgKlxuICAgKiBAbmFtZSBpc05vdEV4dGVuc2libGVcbiAgICogQGFsaWFzIG5vdEV4dGVuc2libGVcbiAgICogQHBhcmFtIHtPYmplY3R9IG9iamVjdFxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZSBfb3B0aW9uYWxfXG4gICAqIEBuYW1lc3BhY2UgQXNzZXJ0XG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIGFzc2VydC5pc05vdEV4dGVuc2libGUgPSBmdW5jdGlvbiAob2JqLCBtc2cpIHtcbiAgICBuZXcgQXNzZXJ0aW9uKG9iaiwgbXNnKS50by5ub3QuYmUuZXh0ZW5zaWJsZTtcbiAgfTtcblxuICAvKipcbiAgICogIyMjIC5pc1NlYWxlZChvYmplY3QpXG4gICAqXG4gICAqIEFzc2VydHMgdGhhdCBgb2JqZWN0YCBpcyBzZWFsZWQgKGNhbm5vdCBoYXZlIG5ldyBwcm9wZXJ0aWVzIGFkZGVkIHRvIGl0XG4gICAqIGFuZCBpdHMgZXhpc3RpbmcgcHJvcGVydGllcyBjYW5ub3QgYmUgcmVtb3ZlZCkuXG4gICAqXG4gICAqICAgICB2YXIgc2VhbGVkT2JqZWN0ID0gT2JqZWN0LnNlYWwoe30pO1xuICAgKiAgICAgdmFyIGZyb3plbk9iamVjdCA9IE9iamVjdC5zZWFsKHt9KTtcbiAgICpcbiAgICogICAgIGFzc2VydC5pc1NlYWxlZChzZWFsZWRPYmplY3QpO1xuICAgKiAgICAgYXNzZXJ0LmlzU2VhbGVkKGZyb3plbk9iamVjdCk7XG4gICAqXG4gICAqIEBuYW1lIGlzU2VhbGVkXG4gICAqIEBhbGlhcyBzZWFsZWRcbiAgICogQHBhcmFtIHtPYmplY3R9IG9iamVjdFxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZSBfb3B0aW9uYWxfXG4gICAqIEBuYW1lc3BhY2UgQXNzZXJ0XG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIGFzc2VydC5pc1NlYWxlZCA9IGZ1bmN0aW9uIChvYmosIG1zZykge1xuICAgIG5ldyBBc3NlcnRpb24ob2JqLCBtc2cpLnRvLmJlLnNlYWxlZDtcbiAgfTtcblxuICAvKipcbiAgICogIyMjIC5pc05vdFNlYWxlZChvYmplY3QpXG4gICAqXG4gICAqIEFzc2VydHMgdGhhdCBgb2JqZWN0YCBpcyBfbm90XyBzZWFsZWQuXG4gICAqXG4gICAqICAgICBhc3NlcnQuaXNOb3RTZWFsZWQoe30pO1xuICAgKlxuICAgKiBAbmFtZSBpc05vdFNlYWxlZFxuICAgKiBAYWxpYXMgbm90U2VhbGVkXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3RcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2UgX29wdGlvbmFsX1xuICAgKiBAbmFtZXNwYWNlIEFzc2VydFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBhc3NlcnQuaXNOb3RTZWFsZWQgPSBmdW5jdGlvbiAob2JqLCBtc2cpIHtcbiAgICBuZXcgQXNzZXJ0aW9uKG9iaiwgbXNnKS50by5ub3QuYmUuc2VhbGVkO1xuICB9O1xuXG4gIC8qKlxuICAgKiAjIyMgLmlzRnJvemVuKG9iamVjdClcbiAgICpcbiAgICogQXNzZXJ0cyB0aGF0IGBvYmplY3RgIGlzIGZyb3plbiAoY2Fubm90IGhhdmUgbmV3IHByb3BlcnRpZXMgYWRkZWQgdG8gaXRcbiAgICogYW5kIGl0cyBleGlzdGluZyBwcm9wZXJ0aWVzIGNhbm5vdCBiZSBtb2RpZmllZCkuXG4gICAqXG4gICAqICAgICB2YXIgZnJvemVuT2JqZWN0ID0gT2JqZWN0LmZyZWV6ZSh7fSk7XG4gICAqICAgICBhc3NlcnQuZnJvemVuKGZyb3plbk9iamVjdCk7XG4gICAqXG4gICAqIEBuYW1lIGlzRnJvemVuXG4gICAqIEBhbGlhcyBmcm96ZW5cbiAgICogQHBhcmFtIHtPYmplY3R9IG9iamVjdFxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZSBfb3B0aW9uYWxfXG4gICAqIEBuYW1lc3BhY2UgQXNzZXJ0XG4gICAqIEBhcGkgcHVibGljXG4gICAqL1xuXG4gIGFzc2VydC5pc0Zyb3plbiA9IGZ1bmN0aW9uIChvYmosIG1zZykge1xuICAgIG5ldyBBc3NlcnRpb24ob2JqLCBtc2cpLnRvLmJlLmZyb3plbjtcbiAgfTtcblxuICAvKipcbiAgICogIyMjIC5pc05vdEZyb3plbihvYmplY3QpXG4gICAqXG4gICAqIEFzc2VydHMgdGhhdCBgb2JqZWN0YCBpcyBfbm90XyBmcm96ZW4uXG4gICAqXG4gICAqICAgICBhc3NlcnQuaXNOb3RGcm96ZW4oe30pO1xuICAgKlxuICAgKiBAbmFtZSBpc05vdEZyb3plblxuICAgKiBAYWxpYXMgbm90RnJvemVuXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3RcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2UgX29wdGlvbmFsX1xuICAgKiBAbmFtZXNwYWNlIEFzc2VydFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBhc3NlcnQuaXNOb3RGcm96ZW4gPSBmdW5jdGlvbiAob2JqLCBtc2cpIHtcbiAgICBuZXcgQXNzZXJ0aW9uKG9iaiwgbXNnKS50by5ub3QuYmUuZnJvemVuO1xuICB9O1xuXG4gIC8qIVxuICAgKiBBbGlhc2VzLlxuICAgKi9cblxuICAoZnVuY3Rpb24gYWxpYXMobmFtZSwgYXMpe1xuICAgIGFzc2VydFthc10gPSBhc3NlcnRbbmFtZV07XG4gICAgcmV0dXJuIGFsaWFzO1xuICB9KVxuICAoJ2lzT2snLCAnb2snKVxuICAoJ2lzTm90T2snLCAnbm90T2snKVxuICAoJ3Rocm93cycsICd0aHJvdycpXG4gICgndGhyb3dzJywgJ1Rocm93JylcbiAgKCdpc0V4dGVuc2libGUnLCAnZXh0ZW5zaWJsZScpXG4gICgnaXNOb3RFeHRlbnNpYmxlJywgJ25vdEV4dGVuc2libGUnKVxuICAoJ2lzU2VhbGVkJywgJ3NlYWxlZCcpXG4gICgnaXNOb3RTZWFsZWQnLCAnbm90U2VhbGVkJylcbiAgKCdpc0Zyb3plbicsICdmcm96ZW4nKVxuICAoJ2lzTm90RnJvemVuJywgJ25vdEZyb3plbicpO1xufTtcbiIsIi8qIVxuICogY2hhaVxuICogQ29weXJpZ2h0KGMpIDIwMTEtMjAxNCBKYWtlIEx1ZXIgPGpha2VAYWxvZ2ljYWxwYXJhZG94LmNvbT5cbiAqIE1JVCBMaWNlbnNlZFxuICovXG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNoYWksIHV0aWwpIHtcbiAgY2hhaS5leHBlY3QgPSBmdW5jdGlvbiAodmFsLCBtZXNzYWdlKSB7XG4gICAgcmV0dXJuIG5ldyBjaGFpLkFzc2VydGlvbih2YWwsIG1lc3NhZ2UpO1xuICB9O1xuXG4gIC8qKlxuICAgKiAjIyMgLmZhaWwoYWN0dWFsLCBleHBlY3RlZCwgW21lc3NhZ2VdLCBbb3BlcmF0b3JdKVxuICAgKlxuICAgKiBUaHJvdyBhIGZhaWx1cmUuXG4gICAqXG4gICAqIEBuYW1lIGZhaWxcbiAgICogQHBhcmFtIHtNaXhlZH0gYWN0dWFsXG4gICAqIEBwYXJhbSB7TWl4ZWR9IGV4cGVjdGVkXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBvcGVyYXRvclxuICAgKiBAbmFtZXNwYWNlIEV4cGVjdFxuICAgKiBAYXBpIHB1YmxpY1xuICAgKi9cblxuICBjaGFpLmV4cGVjdC5mYWlsID0gZnVuY3Rpb24gKGFjdHVhbCwgZXhwZWN0ZWQsIG1lc3NhZ2UsIG9wZXJhdG9yKSB7XG4gICAgbWVzc2FnZSA9IG1lc3NhZ2UgfHwgJ2V4cGVjdC5mYWlsKCknO1xuICAgIHRocm93IG5ldyBjaGFpLkFzc2VydGlvbkVycm9yKG1lc3NhZ2UsIHtcbiAgICAgICAgYWN0dWFsOiBhY3R1YWxcbiAgICAgICwgZXhwZWN0ZWQ6IGV4cGVjdGVkXG4gICAgICAsIG9wZXJhdG9yOiBvcGVyYXRvclxuICAgIH0sIGNoYWkuZXhwZWN0LmZhaWwpO1xuICB9O1xufTtcbiIsIi8qIVxuICogY2hhaVxuICogQ29weXJpZ2h0KGMpIDIwMTEtMjAxNCBKYWtlIEx1ZXIgPGpha2VAYWxvZ2ljYWxwYXJhZG94LmNvbT5cbiAqIE1JVCBMaWNlbnNlZFxuICovXG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNoYWksIHV0aWwpIHtcbiAgdmFyIEFzc2VydGlvbiA9IGNoYWkuQXNzZXJ0aW9uO1xuXG4gIGZ1bmN0aW9uIGxvYWRTaG91bGQgKCkge1xuICAgIC8vIGV4cGxpY2l0bHkgZGVmaW5lIHRoaXMgbWV0aG9kIGFzIGZ1bmN0aW9uIGFzIHRvIGhhdmUgaXQncyBuYW1lIHRvIGluY2x1ZGUgYXMgYHNzZmlgXG4gICAgZnVuY3Rpb24gc2hvdWxkR2V0dGVyKCkge1xuICAgICAgaWYgKHRoaXMgaW5zdGFuY2VvZiBTdHJpbmcgfHwgdGhpcyBpbnN0YW5jZW9mIE51bWJlciB8fCB0aGlzIGluc3RhbmNlb2YgQm9vbGVhbiApIHtcbiAgICAgICAgcmV0dXJuIG5ldyBBc3NlcnRpb24odGhpcy52YWx1ZU9mKCksIG51bGwsIHNob3VsZEdldHRlcik7XG4gICAgICB9XG4gICAgICByZXR1cm4gbmV3IEFzc2VydGlvbih0aGlzLCBudWxsLCBzaG91bGRHZXR0ZXIpO1xuICAgIH1cbiAgICBmdW5jdGlvbiBzaG91bGRTZXR0ZXIodmFsdWUpIHtcbiAgICAgIC8vIFNlZSBodHRwczovL2dpdGh1Yi5jb20vY2hhaWpzL2NoYWkvaXNzdWVzLzg2OiB0aGlzIG1ha2VzXG4gICAgICAvLyBgd2hhdGV2ZXIuc2hvdWxkID0gc29tZVZhbHVlYCBhY3R1YWxseSBzZXQgYHNvbWVWYWx1ZWAsIHdoaWNoIGlzXG4gICAgICAvLyBlc3BlY2lhbGx5IHVzZWZ1bCBmb3IgYGdsb2JhbC5zaG91bGQgPSByZXF1aXJlKCdjaGFpJykuc2hvdWxkKClgLlxuICAgICAgLy9cbiAgICAgIC8vIE5vdGUgdGhhdCB3ZSBoYXZlIHRvIHVzZSBbW0RlZmluZVByb3BlcnR5XV0gaW5zdGVhZCBvZiBbW1B1dF1dXG4gICAgICAvLyBzaW5jZSBvdGhlcndpc2Ugd2Ugd291bGQgdHJpZ2dlciB0aGlzIHZlcnkgc2V0dGVyIVxuICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRoaXMsICdzaG91bGQnLCB7XG4gICAgICAgIHZhbHVlOiB2YWx1ZSxcbiAgICAgICAgZW51bWVyYWJsZTogdHJ1ZSxcbiAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgICB3cml0YWJsZTogdHJ1ZVxuICAgICAgfSk7XG4gICAgfVxuICAgIC8vIG1vZGlmeSBPYmplY3QucHJvdG90eXBlIHRvIGhhdmUgYHNob3VsZGBcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoT2JqZWN0LnByb3RvdHlwZSwgJ3Nob3VsZCcsIHtcbiAgICAgIHNldDogc2hvdWxkU2V0dGVyXG4gICAgICAsIGdldDogc2hvdWxkR2V0dGVyXG4gICAgICAsIGNvbmZpZ3VyYWJsZTogdHJ1ZVxuICAgIH0pO1xuXG4gICAgdmFyIHNob3VsZCA9IHt9O1xuXG4gICAgLyoqXG4gICAgICogIyMjIC5mYWlsKGFjdHVhbCwgZXhwZWN0ZWQsIFttZXNzYWdlXSwgW29wZXJhdG9yXSlcbiAgICAgKlxuICAgICAqIFRocm93IGEgZmFpbHVyZS5cbiAgICAgKlxuICAgICAqIEBuYW1lIGZhaWxcbiAgICAgKiBAcGFyYW0ge01peGVkfSBhY3R1YWxcbiAgICAgKiBAcGFyYW0ge01peGVkfSBleHBlY3RlZFxuICAgICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IG9wZXJhdG9yXG4gICAgICogQG5hbWVzcGFjZSBTaG91bGRcbiAgICAgKiBAYXBpIHB1YmxpY1xuICAgICAqL1xuXG4gICAgc2hvdWxkLmZhaWwgPSBmdW5jdGlvbiAoYWN0dWFsLCBleHBlY3RlZCwgbWVzc2FnZSwgb3BlcmF0b3IpIHtcbiAgICAgIG1lc3NhZ2UgPSBtZXNzYWdlIHx8ICdzaG91bGQuZmFpbCgpJztcbiAgICAgIHRocm93IG5ldyBjaGFpLkFzc2VydGlvbkVycm9yKG1lc3NhZ2UsIHtcbiAgICAgICAgICBhY3R1YWw6IGFjdHVhbFxuICAgICAgICAsIGV4cGVjdGVkOiBleHBlY3RlZFxuICAgICAgICAsIG9wZXJhdG9yOiBvcGVyYXRvclxuICAgICAgfSwgc2hvdWxkLmZhaWwpO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiAjIyMgLmVxdWFsKGFjdHVhbCwgZXhwZWN0ZWQsIFttZXNzYWdlXSlcbiAgICAgKlxuICAgICAqIEFzc2VydHMgbm9uLXN0cmljdCBlcXVhbGl0eSAoYD09YCkgb2YgYGFjdHVhbGAgYW5kIGBleHBlY3RlZGAuXG4gICAgICpcbiAgICAgKiAgICAgc2hvdWxkLmVxdWFsKDMsICczJywgJz09IGNvZXJjZXMgdmFsdWVzIHRvIHN0cmluZ3MnKTtcbiAgICAgKlxuICAgICAqIEBuYW1lIGVxdWFsXG4gICAgICogQHBhcmFtIHtNaXhlZH0gYWN0dWFsXG4gICAgICogQHBhcmFtIHtNaXhlZH0gZXhwZWN0ZWRcbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZVxuICAgICAqIEBuYW1lc3BhY2UgU2hvdWxkXG4gICAgICogQGFwaSBwdWJsaWNcbiAgICAgKi9cblxuICAgIHNob3VsZC5lcXVhbCA9IGZ1bmN0aW9uICh2YWwxLCB2YWwyLCBtc2cpIHtcbiAgICAgIG5ldyBBc3NlcnRpb24odmFsMSwgbXNnKS50by5lcXVhbCh2YWwyKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogIyMjIC50aHJvdyhmdW5jdGlvbiwgW2NvbnN0cnVjdG9yL3N0cmluZy9yZWdleHBdLCBbc3RyaW5nL3JlZ2V4cF0sIFttZXNzYWdlXSlcbiAgICAgKlxuICAgICAqIEFzc2VydHMgdGhhdCBgZnVuY3Rpb25gIHdpbGwgdGhyb3cgYW4gZXJyb3IgdGhhdCBpcyBhbiBpbnN0YW5jZSBvZlxuICAgICAqIGBjb25zdHJ1Y3RvcmAsIG9yIGFsdGVybmF0ZWx5IHRoYXQgaXQgd2lsbCB0aHJvdyBhbiBlcnJvciB3aXRoIG1lc3NhZ2VcbiAgICAgKiBtYXRjaGluZyBgcmVnZXhwYC5cbiAgICAgKlxuICAgICAqICAgICBzaG91bGQudGhyb3coZm4sICdmdW5jdGlvbiB0aHJvd3MgYSByZWZlcmVuY2UgZXJyb3InKTtcbiAgICAgKiAgICAgc2hvdWxkLnRocm93KGZuLCAvZnVuY3Rpb24gdGhyb3dzIGEgcmVmZXJlbmNlIGVycm9yLyk7XG4gICAgICogICAgIHNob3VsZC50aHJvdyhmbiwgUmVmZXJlbmNlRXJyb3IpO1xuICAgICAqICAgICBzaG91bGQudGhyb3coZm4sIFJlZmVyZW5jZUVycm9yLCAnZnVuY3Rpb24gdGhyb3dzIGEgcmVmZXJlbmNlIGVycm9yJyk7XG4gICAgICogICAgIHNob3VsZC50aHJvdyhmbiwgUmVmZXJlbmNlRXJyb3IsIC9mdW5jdGlvbiB0aHJvd3MgYSByZWZlcmVuY2UgZXJyb3IvKTtcbiAgICAgKlxuICAgICAqIEBuYW1lIHRocm93XG4gICAgICogQGFsaWFzIFRocm93XG4gICAgICogQHBhcmFtIHtGdW5jdGlvbn0gZnVuY3Rpb25cbiAgICAgKiBAcGFyYW0ge0Vycm9yQ29uc3RydWN0b3J9IGNvbnN0cnVjdG9yXG4gICAgICogQHBhcmFtIHtSZWdFeHB9IHJlZ2V4cFxuICAgICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlXG4gICAgICogQHNlZSBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9HbG9iYWxfT2JqZWN0cy9FcnJvciNFcnJvcl90eXBlc1xuICAgICAqIEBuYW1lc3BhY2UgU2hvdWxkXG4gICAgICogQGFwaSBwdWJsaWNcbiAgICAgKi9cblxuICAgIHNob3VsZC5UaHJvdyA9IGZ1bmN0aW9uIChmbiwgZXJydCwgZXJycywgbXNnKSB7XG4gICAgICBuZXcgQXNzZXJ0aW9uKGZuLCBtc2cpLnRvLlRocm93KGVycnQsIGVycnMpO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiAjIyMgLmV4aXN0XG4gICAgICpcbiAgICAgKiBBc3NlcnRzIHRoYXQgdGhlIHRhcmdldCBpcyBuZWl0aGVyIGBudWxsYCBub3IgYHVuZGVmaW5lZGAuXG4gICAgICpcbiAgICAgKiAgICAgdmFyIGZvbyA9ICdoaSc7XG4gICAgICpcbiAgICAgKiAgICAgc2hvdWxkLmV4aXN0KGZvbywgJ2ZvbyBleGlzdHMnKTtcbiAgICAgKlxuICAgICAqIEBuYW1lIGV4aXN0XG4gICAgICogQG5hbWVzcGFjZSBTaG91bGRcbiAgICAgKiBAYXBpIHB1YmxpY1xuICAgICAqL1xuXG4gICAgc2hvdWxkLmV4aXN0ID0gZnVuY3Rpb24gKHZhbCwgbXNnKSB7XG4gICAgICBuZXcgQXNzZXJ0aW9uKHZhbCwgbXNnKS50by5leGlzdDtcbiAgICB9XG5cbiAgICAvLyBuZWdhdGlvblxuICAgIHNob3VsZC5ub3QgPSB7fVxuXG4gICAgLyoqXG4gICAgICogIyMjIC5ub3QuZXF1YWwoYWN0dWFsLCBleHBlY3RlZCwgW21lc3NhZ2VdKVxuICAgICAqXG4gICAgICogQXNzZXJ0cyBub24tc3RyaWN0IGluZXF1YWxpdHkgKGAhPWApIG9mIGBhY3R1YWxgIGFuZCBgZXhwZWN0ZWRgLlxuICAgICAqXG4gICAgICogICAgIHNob3VsZC5ub3QuZXF1YWwoMywgNCwgJ3RoZXNlIG51bWJlcnMgYXJlIG5vdCBlcXVhbCcpO1xuICAgICAqXG4gICAgICogQG5hbWUgbm90LmVxdWFsXG4gICAgICogQHBhcmFtIHtNaXhlZH0gYWN0dWFsXG4gICAgICogQHBhcmFtIHtNaXhlZH0gZXhwZWN0ZWRcbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZVxuICAgICAqIEBuYW1lc3BhY2UgU2hvdWxkXG4gICAgICogQGFwaSBwdWJsaWNcbiAgICAgKi9cblxuICAgIHNob3VsZC5ub3QuZXF1YWwgPSBmdW5jdGlvbiAodmFsMSwgdmFsMiwgbXNnKSB7XG4gICAgICBuZXcgQXNzZXJ0aW9uKHZhbDEsIG1zZykudG8ubm90LmVxdWFsKHZhbDIpO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiAjIyMgLnRocm93KGZ1bmN0aW9uLCBbY29uc3RydWN0b3IvcmVnZXhwXSwgW21lc3NhZ2VdKVxuICAgICAqXG4gICAgICogQXNzZXJ0cyB0aGF0IGBmdW5jdGlvbmAgd2lsbCBfbm90XyB0aHJvdyBhbiBlcnJvciB0aGF0IGlzIGFuIGluc3RhbmNlIG9mXG4gICAgICogYGNvbnN0cnVjdG9yYCwgb3IgYWx0ZXJuYXRlbHkgdGhhdCBpdCB3aWxsIG5vdCB0aHJvdyBhbiBlcnJvciB3aXRoIG1lc3NhZ2VcbiAgICAgKiBtYXRjaGluZyBgcmVnZXhwYC5cbiAgICAgKlxuICAgICAqICAgICBzaG91bGQubm90LnRocm93KGZuLCBFcnJvciwgJ2Z1bmN0aW9uIGRvZXMgbm90IHRocm93Jyk7XG4gICAgICpcbiAgICAgKiBAbmFtZSBub3QudGhyb3dcbiAgICAgKiBAYWxpYXMgbm90LlRocm93XG4gICAgICogQHBhcmFtIHtGdW5jdGlvbn0gZnVuY3Rpb25cbiAgICAgKiBAcGFyYW0ge0Vycm9yQ29uc3RydWN0b3J9IGNvbnN0cnVjdG9yXG4gICAgICogQHBhcmFtIHtSZWdFeHB9IHJlZ2V4cFxuICAgICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlXG4gICAgICogQHNlZSBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9HbG9iYWxfT2JqZWN0cy9FcnJvciNFcnJvcl90eXBlc1xuICAgICAqIEBuYW1lc3BhY2UgU2hvdWxkXG4gICAgICogQGFwaSBwdWJsaWNcbiAgICAgKi9cblxuICAgIHNob3VsZC5ub3QuVGhyb3cgPSBmdW5jdGlvbiAoZm4sIGVycnQsIGVycnMsIG1zZykge1xuICAgICAgbmV3IEFzc2VydGlvbihmbiwgbXNnKS50by5ub3QuVGhyb3coZXJydCwgZXJycyk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqICMjIyAubm90LmV4aXN0XG4gICAgICpcbiAgICAgKiBBc3NlcnRzIHRoYXQgdGhlIHRhcmdldCBpcyBuZWl0aGVyIGBudWxsYCBub3IgYHVuZGVmaW5lZGAuXG4gICAgICpcbiAgICAgKiAgICAgdmFyIGJhciA9IG51bGw7XG4gICAgICpcbiAgICAgKiAgICAgc2hvdWxkLm5vdC5leGlzdChiYXIsICdiYXIgZG9lcyBub3QgZXhpc3QnKTtcbiAgICAgKlxuICAgICAqIEBuYW1lIG5vdC5leGlzdFxuICAgICAqIEBuYW1lc3BhY2UgU2hvdWxkXG4gICAgICogQGFwaSBwdWJsaWNcbiAgICAgKi9cblxuICAgIHNob3VsZC5ub3QuZXhpc3QgPSBmdW5jdGlvbiAodmFsLCBtc2cpIHtcbiAgICAgIG5ldyBBc3NlcnRpb24odmFsLCBtc2cpLnRvLm5vdC5leGlzdDtcbiAgICB9XG5cbiAgICBzaG91bGRbJ3Rocm93J10gPSBzaG91bGRbJ1Rocm93J107XG4gICAgc2hvdWxkLm5vdFsndGhyb3cnXSA9IHNob3VsZC5ub3RbJ1Rocm93J107XG5cbiAgICByZXR1cm4gc2hvdWxkO1xuICB9O1xuXG4gIGNoYWkuc2hvdWxkID0gbG9hZFNob3VsZDtcbiAgY2hhaS5TaG91bGQgPSBsb2FkU2hvdWxkO1xufTtcbiIsIi8qIVxuICogQ2hhaSAtIGFkZENoYWluaW5nTWV0aG9kIHV0aWxpdHlcbiAqIENvcHlyaWdodChjKSAyMDEyLTIwMTQgSmFrZSBMdWVyIDxqYWtlQGFsb2dpY2FscGFyYWRveC5jb20+XG4gKiBNSVQgTGljZW5zZWRcbiAqL1xuXG4vKiFcbiAqIE1vZHVsZSBkZXBlbmRlbmNpZXNcbiAqL1xuXG52YXIgdHJhbnNmZXJGbGFncyA9IHJlcXVpcmUoJy4vdHJhbnNmZXJGbGFncycpO1xudmFyIGZsYWcgPSByZXF1aXJlKCcuL2ZsYWcnKTtcbnZhciBjb25maWcgPSByZXF1aXJlKCcuLi9jb25maWcnKTtcblxuLyohXG4gKiBNb2R1bGUgdmFyaWFibGVzXG4gKi9cblxuLy8gQ2hlY2sgd2hldGhlciBgX19wcm90b19fYCBpcyBzdXBwb3J0ZWRcbnZhciBoYXNQcm90b1N1cHBvcnQgPSAnX19wcm90b19fJyBpbiBPYmplY3Q7XG5cbi8vIFdpdGhvdXQgYF9fcHJvdG9fX2Agc3VwcG9ydCwgdGhpcyBtb2R1bGUgd2lsbCBuZWVkIHRvIGFkZCBwcm9wZXJ0aWVzIHRvIGEgZnVuY3Rpb24uXG4vLyBIb3dldmVyLCBzb21lIEZ1bmN0aW9uLnByb3RvdHlwZSBtZXRob2RzIGNhbm5vdCBiZSBvdmVyd3JpdHRlbixcbi8vIGFuZCB0aGVyZSBzZWVtcyBubyBlYXN5IGNyb3NzLXBsYXRmb3JtIHdheSB0byBkZXRlY3QgdGhlbSAoQHNlZSBjaGFpanMvY2hhaS9pc3N1ZXMvNjkpLlxudmFyIGV4Y2x1ZGVOYW1lcyA9IC9eKD86bGVuZ3RofG5hbWV8YXJndW1lbnRzfGNhbGxlcikkLztcblxuLy8gQ2FjaGUgYEZ1bmN0aW9uYCBwcm9wZXJ0aWVzXG52YXIgY2FsbCAgPSBGdW5jdGlvbi5wcm90b3R5cGUuY2FsbCxcbiAgICBhcHBseSA9IEZ1bmN0aW9uLnByb3RvdHlwZS5hcHBseTtcblxuLyoqXG4gKiAjIyMgYWRkQ2hhaW5hYmxlTWV0aG9kIChjdHgsIG5hbWUsIG1ldGhvZCwgY2hhaW5pbmdCZWhhdmlvcilcbiAqXG4gKiBBZGRzIGEgbWV0aG9kIHRvIGFuIG9iamVjdCwgc3VjaCB0aGF0IHRoZSBtZXRob2QgY2FuIGFsc28gYmUgY2hhaW5lZC5cbiAqXG4gKiAgICAgdXRpbHMuYWRkQ2hhaW5hYmxlTWV0aG9kKGNoYWkuQXNzZXJ0aW9uLnByb3RvdHlwZSwgJ2ZvbycsIGZ1bmN0aW9uIChzdHIpIHtcbiAqICAgICAgIHZhciBvYmogPSB1dGlscy5mbGFnKHRoaXMsICdvYmplY3QnKTtcbiAqICAgICAgIG5ldyBjaGFpLkFzc2VydGlvbihvYmopLnRvLmJlLmVxdWFsKHN0cik7XG4gKiAgICAgfSk7XG4gKlxuICogQ2FuIGFsc28gYmUgYWNjZXNzZWQgZGlyZWN0bHkgZnJvbSBgY2hhaS5Bc3NlcnRpb25gLlxuICpcbiAqICAgICBjaGFpLkFzc2VydGlvbi5hZGRDaGFpbmFibGVNZXRob2QoJ2ZvbycsIGZuLCBjaGFpbmluZ0JlaGF2aW9yKTtcbiAqXG4gKiBUaGUgcmVzdWx0IGNhbiB0aGVuIGJlIHVzZWQgYXMgYm90aCBhIG1ldGhvZCBhc3NlcnRpb24sIGV4ZWN1dGluZyBib3RoIGBtZXRob2RgIGFuZFxuICogYGNoYWluaW5nQmVoYXZpb3JgLCBvciBhcyBhIGxhbmd1YWdlIGNoYWluLCB3aGljaCBvbmx5IGV4ZWN1dGVzIGBjaGFpbmluZ0JlaGF2aW9yYC5cbiAqXG4gKiAgICAgZXhwZWN0KGZvb1N0cikudG8uYmUuZm9vKCdiYXInKTtcbiAqICAgICBleHBlY3QoZm9vU3RyKS50by5iZS5mb28uZXF1YWwoJ2ZvbycpO1xuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBjdHggb2JqZWN0IHRvIHdoaWNoIHRoZSBtZXRob2QgaXMgYWRkZWRcbiAqIEBwYXJhbSB7U3RyaW5nfSBuYW1lIG9mIG1ldGhvZCB0byBhZGRcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG1ldGhvZCBmdW5jdGlvbiB0byBiZSB1c2VkIGZvciBgbmFtZWAsIHdoZW4gY2FsbGVkXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBjaGFpbmluZ0JlaGF2aW9yIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZCBldmVyeSB0aW1lIHRoZSBwcm9wZXJ0eSBpcyBhY2Nlc3NlZFxuICogQG5hbWVzcGFjZSBVdGlsc1xuICogQG5hbWUgYWRkQ2hhaW5hYmxlTWV0aG9kXG4gKiBAYXBpIHB1YmxpY1xuICovXG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGN0eCwgbmFtZSwgbWV0aG9kLCBjaGFpbmluZ0JlaGF2aW9yKSB7XG4gIGlmICh0eXBlb2YgY2hhaW5pbmdCZWhhdmlvciAhPT0gJ2Z1bmN0aW9uJykge1xuICAgIGNoYWluaW5nQmVoYXZpb3IgPSBmdW5jdGlvbiAoKSB7IH07XG4gIH1cblxuICB2YXIgY2hhaW5hYmxlQmVoYXZpb3IgPSB7XG4gICAgICBtZXRob2Q6IG1ldGhvZFxuICAgICwgY2hhaW5pbmdCZWhhdmlvcjogY2hhaW5pbmdCZWhhdmlvclxuICB9O1xuXG4gIC8vIHNhdmUgdGhlIG1ldGhvZHMgc28gd2UgY2FuIG92ZXJ3cml0ZSB0aGVtIGxhdGVyLCBpZiB3ZSBuZWVkIHRvLlxuICBpZiAoIWN0eC5fX21ldGhvZHMpIHtcbiAgICBjdHguX19tZXRob2RzID0ge307XG4gIH1cbiAgY3R4Ll9fbWV0aG9kc1tuYW1lXSA9IGNoYWluYWJsZUJlaGF2aW9yO1xuXG4gIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShjdHgsIG5hbWUsXG4gICAgeyBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY2hhaW5hYmxlQmVoYXZpb3IuY2hhaW5pbmdCZWhhdmlvci5jYWxsKHRoaXMpO1xuXG4gICAgICAgIHZhciBhc3NlcnQgPSBmdW5jdGlvbiBhc3NlcnQoKSB7XG4gICAgICAgICAgdmFyIG9sZF9zc2ZpID0gZmxhZyh0aGlzLCAnc3NmaScpO1xuICAgICAgICAgIGlmIChvbGRfc3NmaSAmJiBjb25maWcuaW5jbHVkZVN0YWNrID09PSBmYWxzZSlcbiAgICAgICAgICAgIGZsYWcodGhpcywgJ3NzZmknLCBhc3NlcnQpO1xuICAgICAgICAgIHZhciByZXN1bHQgPSBjaGFpbmFibGVCZWhhdmlvci5tZXRob2QuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICByZXR1cm4gcmVzdWx0ID09PSB1bmRlZmluZWQgPyB0aGlzIDogcmVzdWx0O1xuICAgICAgICB9O1xuXG4gICAgICAgIC8vIFVzZSBgX19wcm90b19fYCBpZiBhdmFpbGFibGVcbiAgICAgICAgaWYgKGhhc1Byb3RvU3VwcG9ydCkge1xuICAgICAgICAgIC8vIEluaGVyaXQgYWxsIHByb3BlcnRpZXMgZnJvbSB0aGUgb2JqZWN0IGJ5IHJlcGxhY2luZyB0aGUgYEZ1bmN0aW9uYCBwcm90b3R5cGVcbiAgICAgICAgICB2YXIgcHJvdG90eXBlID0gYXNzZXJ0Ll9fcHJvdG9fXyA9IE9iamVjdC5jcmVhdGUodGhpcyk7XG4gICAgICAgICAgLy8gUmVzdG9yZSB0aGUgYGNhbGxgIGFuZCBgYXBwbHlgIG1ldGhvZHMgZnJvbSBgRnVuY3Rpb25gXG4gICAgICAgICAgcHJvdG90eXBlLmNhbGwgPSBjYWxsO1xuICAgICAgICAgIHByb3RvdHlwZS5hcHBseSA9IGFwcGx5O1xuICAgICAgICB9XG4gICAgICAgIC8vIE90aGVyd2lzZSwgcmVkZWZpbmUgYWxsIHByb3BlcnRpZXMgKHNsb3chKVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICB2YXIgYXNzZXJ0ZXJOYW1lcyA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKGN0eCk7XG4gICAgICAgICAgYXNzZXJ0ZXJOYW1lcy5mb3JFYWNoKGZ1bmN0aW9uIChhc3NlcnRlck5hbWUpIHtcbiAgICAgICAgICAgIGlmICghZXhjbHVkZU5hbWVzLnRlc3QoYXNzZXJ0ZXJOYW1lKSkge1xuICAgICAgICAgICAgICB2YXIgcGQgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKGN0eCwgYXNzZXJ0ZXJOYW1lKTtcbiAgICAgICAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KGFzc2VydCwgYXNzZXJ0ZXJOYW1lLCBwZCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICB0cmFuc2ZlckZsYWdzKHRoaXMsIGFzc2VydCk7XG4gICAgICAgIHJldHVybiBhc3NlcnQ7XG4gICAgICB9XG4gICAgLCBjb25maWd1cmFibGU6IHRydWVcbiAgfSk7XG59O1xuIiwiLyohXG4gKiBDaGFpIC0gYWRkTWV0aG9kIHV0aWxpdHlcbiAqIENvcHlyaWdodChjKSAyMDEyLTIwMTQgSmFrZSBMdWVyIDxqYWtlQGFsb2dpY2FscGFyYWRveC5jb20+XG4gKiBNSVQgTGljZW5zZWRcbiAqL1xuXG52YXIgY29uZmlnID0gcmVxdWlyZSgnLi4vY29uZmlnJyk7XG5cbi8qKlxuICogIyMjIC5hZGRNZXRob2QgKGN0eCwgbmFtZSwgbWV0aG9kKVxuICpcbiAqIEFkZHMgYSBtZXRob2QgdG8gdGhlIHByb3RvdHlwZSBvZiBhbiBvYmplY3QuXG4gKlxuICogICAgIHV0aWxzLmFkZE1ldGhvZChjaGFpLkFzc2VydGlvbi5wcm90b3R5cGUsICdmb28nLCBmdW5jdGlvbiAoc3RyKSB7XG4gKiAgICAgICB2YXIgb2JqID0gdXRpbHMuZmxhZyh0aGlzLCAnb2JqZWN0Jyk7XG4gKiAgICAgICBuZXcgY2hhaS5Bc3NlcnRpb24ob2JqKS50by5iZS5lcXVhbChzdHIpO1xuICogICAgIH0pO1xuICpcbiAqIENhbiBhbHNvIGJlIGFjY2Vzc2VkIGRpcmVjdGx5IGZyb20gYGNoYWkuQXNzZXJ0aW9uYC5cbiAqXG4gKiAgICAgY2hhaS5Bc3NlcnRpb24uYWRkTWV0aG9kKCdmb28nLCBmbik7XG4gKlxuICogVGhlbiBjYW4gYmUgdXNlZCBhcyBhbnkgb3RoZXIgYXNzZXJ0aW9uLlxuICpcbiAqICAgICBleHBlY3QoZm9vU3RyKS50by5iZS5mb28oJ2JhcicpO1xuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBjdHggb2JqZWN0IHRvIHdoaWNoIHRoZSBtZXRob2QgaXMgYWRkZWRcbiAqIEBwYXJhbSB7U3RyaW5nfSBuYW1lIG9mIG1ldGhvZCB0byBhZGRcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG1ldGhvZCBmdW5jdGlvbiB0byBiZSB1c2VkIGZvciBuYW1lXG4gKiBAbmFtZXNwYWNlIFV0aWxzXG4gKiBAbmFtZSBhZGRNZXRob2RcbiAqIEBhcGkgcHVibGljXG4gKi9cbnZhciBmbGFnID0gcmVxdWlyZSgnLi9mbGFnJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGN0eCwgbmFtZSwgbWV0aG9kKSB7XG4gIGN0eFtuYW1lXSA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgb2xkX3NzZmkgPSBmbGFnKHRoaXMsICdzc2ZpJyk7XG4gICAgaWYgKG9sZF9zc2ZpICYmIGNvbmZpZy5pbmNsdWRlU3RhY2sgPT09IGZhbHNlKVxuICAgICAgZmxhZyh0aGlzLCAnc3NmaScsIGN0eFtuYW1lXSk7XG4gICAgdmFyIHJlc3VsdCA9IG1ldGhvZC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIHJldHVybiByZXN1bHQgPT09IHVuZGVmaW5lZCA/IHRoaXMgOiByZXN1bHQ7XG4gIH07XG59O1xuIiwiLyohXG4gKiBDaGFpIC0gYWRkUHJvcGVydHkgdXRpbGl0eVxuICogQ29weXJpZ2h0KGMpIDIwMTItMjAxNCBKYWtlIEx1ZXIgPGpha2VAYWxvZ2ljYWxwYXJhZG94LmNvbT5cbiAqIE1JVCBMaWNlbnNlZFxuICovXG5cbnZhciBjb25maWcgPSByZXF1aXJlKCcuLi9jb25maWcnKTtcbnZhciBmbGFnID0gcmVxdWlyZSgnLi9mbGFnJyk7XG5cbi8qKlxuICogIyMjIGFkZFByb3BlcnR5IChjdHgsIG5hbWUsIGdldHRlcilcbiAqXG4gKiBBZGRzIGEgcHJvcGVydHkgdG8gdGhlIHByb3RvdHlwZSBvZiBhbiBvYmplY3QuXG4gKlxuICogICAgIHV0aWxzLmFkZFByb3BlcnR5KGNoYWkuQXNzZXJ0aW9uLnByb3RvdHlwZSwgJ2ZvbycsIGZ1bmN0aW9uICgpIHtcbiAqICAgICAgIHZhciBvYmogPSB1dGlscy5mbGFnKHRoaXMsICdvYmplY3QnKTtcbiAqICAgICAgIG5ldyBjaGFpLkFzc2VydGlvbihvYmopLnRvLmJlLmluc3RhbmNlb2YoRm9vKTtcbiAqICAgICB9KTtcbiAqXG4gKiBDYW4gYWxzbyBiZSBhY2Nlc3NlZCBkaXJlY3RseSBmcm9tIGBjaGFpLkFzc2VydGlvbmAuXG4gKlxuICogICAgIGNoYWkuQXNzZXJ0aW9uLmFkZFByb3BlcnR5KCdmb28nLCBmbik7XG4gKlxuICogVGhlbiBjYW4gYmUgdXNlZCBhcyBhbnkgb3RoZXIgYXNzZXJ0aW9uLlxuICpcbiAqICAgICBleHBlY3QobXlGb28pLnRvLmJlLmZvbztcbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gY3R4IG9iamVjdCB0byB3aGljaCB0aGUgcHJvcGVydHkgaXMgYWRkZWRcbiAqIEBwYXJhbSB7U3RyaW5nfSBuYW1lIG9mIHByb3BlcnR5IHRvIGFkZFxuICogQHBhcmFtIHtGdW5jdGlvbn0gZ2V0dGVyIGZ1bmN0aW9uIHRvIGJlIHVzZWQgZm9yIG5hbWVcbiAqIEBuYW1lc3BhY2UgVXRpbHNcbiAqIEBuYW1lIGFkZFByb3BlcnR5XG4gKiBAYXBpIHB1YmxpY1xuICovXG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGN0eCwgbmFtZSwgZ2V0dGVyKSB7XG4gIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShjdHgsIG5hbWUsXG4gICAgeyBnZXQ6IGZ1bmN0aW9uIGFkZFByb3BlcnR5KCkge1xuICAgICAgICB2YXIgb2xkX3NzZmkgPSBmbGFnKHRoaXMsICdzc2ZpJyk7XG4gICAgICAgIGlmIChvbGRfc3NmaSAmJiBjb25maWcuaW5jbHVkZVN0YWNrID09PSBmYWxzZSlcbiAgICAgICAgICBmbGFnKHRoaXMsICdzc2ZpJywgYWRkUHJvcGVydHkpO1xuXG4gICAgICAgIHZhciByZXN1bHQgPSBnZXR0ZXIuY2FsbCh0aGlzKTtcbiAgICAgICAgcmV0dXJuIHJlc3VsdCA9PT0gdW5kZWZpbmVkID8gdGhpcyA6IHJlc3VsdDtcbiAgICAgIH1cbiAgICAsIGNvbmZpZ3VyYWJsZTogdHJ1ZVxuICB9KTtcbn07XG4iLCIvKiFcbiAqIENoYWkgLSBleHBlY3RUeXBlcyB1dGlsaXR5XG4gKiBDb3B5cmlnaHQoYykgMjAxMi0yMDE0IEpha2UgTHVlciA8amFrZUBhbG9naWNhbHBhcmFkb3guY29tPlxuICogTUlUIExpY2Vuc2VkXG4gKi9cblxuLyoqXG4gKiAjIyMgZXhwZWN0VHlwZXMob2JqLCB0eXBlcylcbiAqXG4gKiBFbnN1cmVzIHRoYXQgdGhlIG9iamVjdCBiZWluZyB0ZXN0ZWQgYWdhaW5zdCBpcyBvZiBhIHZhbGlkIHR5cGUuXG4gKlxuICogICAgIHV0aWxzLmV4cGVjdFR5cGVzKHRoaXMsIFsnYXJyYXknLCAnb2JqZWN0JywgJ3N0cmluZyddKTtcbiAqXG4gKiBAcGFyYW0ge01peGVkfSBvYmogY29uc3RydWN0ZWQgQXNzZXJ0aW9uXG4gKiBAcGFyYW0ge0FycmF5fSB0eXBlIEEgbGlzdCBvZiBhbGxvd2VkIHR5cGVzIGZvciB0aGlzIGFzc2VydGlvblxuICogQG5hbWVzcGFjZSBVdGlsc1xuICogQG5hbWUgZXhwZWN0VHlwZXNcbiAqIEBhcGkgcHVibGljXG4gKi9cblxudmFyIEFzc2VydGlvbkVycm9yID0gcmVxdWlyZSgnYXNzZXJ0aW9uLWVycm9yJyk7XG52YXIgZmxhZyA9IHJlcXVpcmUoJy4vZmxhZycpO1xudmFyIHR5cGUgPSByZXF1aXJlKCd0eXBlLWRldGVjdCcpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChvYmosIHR5cGVzKSB7XG4gIHZhciBvYmogPSBmbGFnKG9iaiwgJ29iamVjdCcpO1xuICB0eXBlcyA9IHR5cGVzLm1hcChmdW5jdGlvbiAodCkgeyByZXR1cm4gdC50b0xvd2VyQ2FzZSgpOyB9KTtcbiAgdHlwZXMuc29ydCgpO1xuXG4gIC8vIFRyYW5zZm9ybXMgWydsb3JlbScsICdpcHN1bSddIGludG8gJ2EgbGlydW0sIG9yIGFuIGlwc3VtJ1xuICB2YXIgc3RyID0gdHlwZXMubWFwKGZ1bmN0aW9uICh0LCBpbmRleCkge1xuICAgIHZhciBhcnQgPSB+WyAnYScsICdlJywgJ2knLCAnbycsICd1JyBdLmluZGV4T2YodC5jaGFyQXQoMCkpID8gJ2FuJyA6ICdhJztcbiAgICB2YXIgb3IgPSB0eXBlcy5sZW5ndGggPiAxICYmIGluZGV4ID09PSB0eXBlcy5sZW5ndGggLSAxID8gJ29yICcgOiAnJztcbiAgICByZXR1cm4gb3IgKyBhcnQgKyAnICcgKyB0O1xuICB9KS5qb2luKCcsICcpO1xuXG4gIGlmICghdHlwZXMuc29tZShmdW5jdGlvbiAoZXhwZWN0ZWQpIHsgcmV0dXJuIHR5cGUob2JqKSA9PT0gZXhwZWN0ZWQ7IH0pKSB7XG4gICAgdGhyb3cgbmV3IEFzc2VydGlvbkVycm9yKFxuICAgICAgJ29iamVjdCB0ZXN0ZWQgbXVzdCBiZSAnICsgc3RyICsgJywgYnV0ICcgKyB0eXBlKG9iaikgKyAnIGdpdmVuJ1xuICAgICk7XG4gIH1cbn07XG4iLCIvKiFcbiAqIENoYWkgLSBmbGFnIHV0aWxpdHlcbiAqIENvcHlyaWdodChjKSAyMDEyLTIwMTQgSmFrZSBMdWVyIDxqYWtlQGFsb2dpY2FscGFyYWRveC5jb20+XG4gKiBNSVQgTGljZW5zZWRcbiAqL1xuXG4vKipcbiAqICMjIyBmbGFnKG9iamVjdCwga2V5LCBbdmFsdWVdKVxuICpcbiAqIEdldCBvciBzZXQgYSBmbGFnIHZhbHVlIG9uIGFuIG9iamVjdC4gSWYgYVxuICogdmFsdWUgaXMgcHJvdmlkZWQgaXQgd2lsbCBiZSBzZXQsIGVsc2UgaXQgd2lsbFxuICogcmV0dXJuIHRoZSBjdXJyZW50bHkgc2V0IHZhbHVlIG9yIGB1bmRlZmluZWRgIGlmXG4gKiB0aGUgdmFsdWUgaXMgbm90IHNldC5cbiAqXG4gKiAgICAgdXRpbHMuZmxhZyh0aGlzLCAnZm9vJywgJ2JhcicpOyAvLyBzZXR0ZXJcbiAqICAgICB1dGlscy5mbGFnKHRoaXMsICdmb28nKTsgLy8gZ2V0dGVyLCByZXR1cm5zIGBiYXJgXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IG9iamVjdCBjb25zdHJ1Y3RlZCBBc3NlcnRpb25cbiAqIEBwYXJhbSB7U3RyaW5nfSBrZXlcbiAqIEBwYXJhbSB7TWl4ZWR9IHZhbHVlIChvcHRpb25hbClcbiAqIEBuYW1lc3BhY2UgVXRpbHNcbiAqIEBuYW1lIGZsYWdcbiAqIEBhcGkgcHJpdmF0ZVxuICovXG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKG9iaiwga2V5LCB2YWx1ZSkge1xuICB2YXIgZmxhZ3MgPSBvYmouX19mbGFncyB8fCAob2JqLl9fZmxhZ3MgPSBPYmplY3QuY3JlYXRlKG51bGwpKTtcbiAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPT09IDMpIHtcbiAgICBmbGFnc1trZXldID0gdmFsdWU7XG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIGZsYWdzW2tleV07XG4gIH1cbn07XG4iLCIvKiFcbiAqIENoYWkgLSBnZXRBY3R1YWwgdXRpbGl0eVxuICogQ29weXJpZ2h0KGMpIDIwMTItMjAxNCBKYWtlIEx1ZXIgPGpha2VAYWxvZ2ljYWxwYXJhZG94LmNvbT5cbiAqIE1JVCBMaWNlbnNlZFxuICovXG5cbi8qKlxuICogIyBnZXRBY3R1YWwob2JqZWN0LCBbYWN0dWFsXSlcbiAqXG4gKiBSZXR1cm5zIHRoZSBgYWN0dWFsYCB2YWx1ZSBmb3IgYW4gQXNzZXJ0aW9uXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IG9iamVjdCAoY29uc3RydWN0ZWQgQXNzZXJ0aW9uKVxuICogQHBhcmFtIHtBcmd1bWVudHN9IGNoYWkuQXNzZXJ0aW9uLnByb3RvdHlwZS5hc3NlcnQgYXJndW1lbnRzXG4gKiBAbmFtZXNwYWNlIFV0aWxzXG4gKiBAbmFtZSBnZXRBY3R1YWxcbiAqL1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChvYmosIGFyZ3MpIHtcbiAgcmV0dXJuIGFyZ3MubGVuZ3RoID4gNCA/IGFyZ3NbNF0gOiBvYmouX29iajtcbn07XG4iLCIvKiFcbiAqIENoYWkgLSBnZXRFbnVtZXJhYmxlUHJvcGVydGllcyB1dGlsaXR5XG4gKiBDb3B5cmlnaHQoYykgMjAxMi0yMDE0IEpha2UgTHVlciA8amFrZUBhbG9naWNhbHBhcmFkb3guY29tPlxuICogTUlUIExpY2Vuc2VkXG4gKi9cblxuLyoqXG4gKiAjIyMgLmdldEVudW1lcmFibGVQcm9wZXJ0aWVzKG9iamVjdClcbiAqXG4gKiBUaGlzIGFsbG93cyB0aGUgcmV0cmlldmFsIG9mIGVudW1lcmFibGUgcHJvcGVydHkgbmFtZXMgb2YgYW4gb2JqZWN0LFxuICogaW5oZXJpdGVkIG9yIG5vdC5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0XG4gKiBAcmV0dXJucyB7QXJyYXl9XG4gKiBAbmFtZXNwYWNlIFV0aWxzXG4gKiBAbmFtZSBnZXRFbnVtZXJhYmxlUHJvcGVydGllc1xuICogQGFwaSBwdWJsaWNcbiAqL1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIGdldEVudW1lcmFibGVQcm9wZXJ0aWVzKG9iamVjdCkge1xuICB2YXIgcmVzdWx0ID0gW107XG4gIGZvciAodmFyIG5hbWUgaW4gb2JqZWN0KSB7XG4gICAgcmVzdWx0LnB1c2gobmFtZSk7XG4gIH1cbiAgcmV0dXJuIHJlc3VsdDtcbn07XG4iLCIvKiFcbiAqIENoYWkgLSBtZXNzYWdlIGNvbXBvc2l0aW9uIHV0aWxpdHlcbiAqIENvcHlyaWdodChjKSAyMDEyLTIwMTQgSmFrZSBMdWVyIDxqYWtlQGFsb2dpY2FscGFyYWRveC5jb20+XG4gKiBNSVQgTGljZW5zZWRcbiAqL1xuXG4vKiFcbiAqIE1vZHVsZSBkZXBlbmRhbmNpZXNcbiAqL1xuXG52YXIgZmxhZyA9IHJlcXVpcmUoJy4vZmxhZycpXG4gICwgZ2V0QWN0dWFsID0gcmVxdWlyZSgnLi9nZXRBY3R1YWwnKVxuICAsIGluc3BlY3QgPSByZXF1aXJlKCcuL2luc3BlY3QnKVxuICAsIG9iakRpc3BsYXkgPSByZXF1aXJlKCcuL29iakRpc3BsYXknKTtcblxuLyoqXG4gKiAjIyMgLmdldE1lc3NhZ2Uob2JqZWN0LCBtZXNzYWdlLCBuZWdhdGVNZXNzYWdlKVxuICpcbiAqIENvbnN0cnVjdCB0aGUgZXJyb3IgbWVzc2FnZSBiYXNlZCBvbiBmbGFnc1xuICogYW5kIHRlbXBsYXRlIHRhZ3MuIFRlbXBsYXRlIHRhZ3Mgd2lsbCByZXR1cm5cbiAqIGEgc3RyaW5naWZpZWQgaW5zcGVjdGlvbiBvZiB0aGUgb2JqZWN0IHJlZmVyZW5jZWQuXG4gKlxuICogTWVzc2FnZSB0ZW1wbGF0ZSB0YWdzOlxuICogLSBgI3t0aGlzfWAgY3VycmVudCBhc3NlcnRlZCBvYmplY3RcbiAqIC0gYCN7YWN0fWAgYWN0dWFsIHZhbHVlXG4gKiAtIGAje2V4cH1gIGV4cGVjdGVkIHZhbHVlXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IG9iamVjdCAoY29uc3RydWN0ZWQgQXNzZXJ0aW9uKVxuICogQHBhcmFtIHtBcmd1bWVudHN9IGNoYWkuQXNzZXJ0aW9uLnByb3RvdHlwZS5hc3NlcnQgYXJndW1lbnRzXG4gKiBAbmFtZXNwYWNlIFV0aWxzXG4gKiBAbmFtZSBnZXRNZXNzYWdlXG4gKiBAYXBpIHB1YmxpY1xuICovXG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKG9iaiwgYXJncykge1xuICB2YXIgbmVnYXRlID0gZmxhZyhvYmosICduZWdhdGUnKVxuICAgICwgdmFsID0gZmxhZyhvYmosICdvYmplY3QnKVxuICAgICwgZXhwZWN0ZWQgPSBhcmdzWzNdXG4gICAgLCBhY3R1YWwgPSBnZXRBY3R1YWwob2JqLCBhcmdzKVxuICAgICwgbXNnID0gbmVnYXRlID8gYXJnc1syXSA6IGFyZ3NbMV1cbiAgICAsIGZsYWdNc2cgPSBmbGFnKG9iaiwgJ21lc3NhZ2UnKTtcblxuICBpZih0eXBlb2YgbXNnID09PSBcImZ1bmN0aW9uXCIpIG1zZyA9IG1zZygpO1xuICBtc2cgPSBtc2cgfHwgJyc7XG4gIG1zZyA9IG1zZ1xuICAgIC5yZXBsYWNlKC8jXFx7dGhpc1xcfS9nLCBmdW5jdGlvbiAoKSB7IHJldHVybiBvYmpEaXNwbGF5KHZhbCk7IH0pXG4gICAgLnJlcGxhY2UoLyNcXHthY3RcXH0vZywgZnVuY3Rpb24gKCkgeyByZXR1cm4gb2JqRGlzcGxheShhY3R1YWwpOyB9KVxuICAgIC5yZXBsYWNlKC8jXFx7ZXhwXFx9L2csIGZ1bmN0aW9uICgpIHsgcmV0dXJuIG9iakRpc3BsYXkoZXhwZWN0ZWQpOyB9KTtcblxuICByZXR1cm4gZmxhZ01zZyA/IGZsYWdNc2cgKyAnOiAnICsgbXNnIDogbXNnO1xufTtcbiIsIi8qIVxuICogQ2hhaSAtIGdldE5hbWUgdXRpbGl0eVxuICogQ29weXJpZ2h0KGMpIDIwMTItMjAxNCBKYWtlIEx1ZXIgPGpha2VAYWxvZ2ljYWxwYXJhZG94LmNvbT5cbiAqIE1JVCBMaWNlbnNlZFxuICovXG5cbi8qKlxuICogIyBnZXROYW1lKGZ1bmMpXG4gKlxuICogR2V0cyB0aGUgbmFtZSBvZiBhIGZ1bmN0aW9uLCBpbiBhIGNyb3NzLWJyb3dzZXIgd2F5LlxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGEgZnVuY3Rpb24gKHVzdWFsbHkgYSBjb25zdHJ1Y3RvcilcbiAqIEBuYW1lc3BhY2UgVXRpbHNcbiAqIEBuYW1lIGdldE5hbWVcbiAqL1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChmdW5jKSB7XG4gIGlmIChmdW5jLm5hbWUpIHJldHVybiBmdW5jLm5hbWU7XG5cbiAgdmFyIG1hdGNoID0gL15cXHM/ZnVuY3Rpb24gKFteKF0qKVxcKC8uZXhlYyhmdW5jKTtcbiAgcmV0dXJuIG1hdGNoICYmIG1hdGNoWzFdID8gbWF0Y2hbMV0gOiBcIlwiO1xufTtcbiIsIi8qIVxuICogQ2hhaSAtIGdldFBhdGhJbmZvIHV0aWxpdHlcbiAqIENvcHlyaWdodChjKSAyMDEyLTIwMTQgSmFrZSBMdWVyIDxqYWtlQGFsb2dpY2FscGFyYWRveC5jb20+XG4gKiBNSVQgTGljZW5zZWRcbiAqL1xuXG52YXIgaGFzUHJvcGVydHkgPSByZXF1aXJlKCcuL2hhc1Byb3BlcnR5Jyk7XG5cbi8qKlxuICogIyMjIC5nZXRQYXRoSW5mbyhwYXRoLCBvYmplY3QpXG4gKlxuICogVGhpcyBhbGxvd3MgdGhlIHJldHJpZXZhbCBvZiBwcm9wZXJ0eSBpbmZvIGluIGFuXG4gKiBvYmplY3QgZ2l2ZW4gYSBzdHJpbmcgcGF0aC5cbiAqXG4gKiBUaGUgcGF0aCBpbmZvIGNvbnNpc3RzIG9mIGFuIG9iamVjdCB3aXRoIHRoZVxuICogZm9sbG93aW5nIHByb3BlcnRpZXM6XG4gKlxuICogKiBwYXJlbnQgLSBUaGUgcGFyZW50IG9iamVjdCBvZiB0aGUgcHJvcGVydHkgcmVmZXJlbmNlZCBieSBgcGF0aGBcbiAqICogbmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBmaW5hbCBwcm9wZXJ0eSwgYSBudW1iZXIgaWYgaXQgd2FzIGFuIGFycmF5IGluZGV4ZXJcbiAqICogdmFsdWUgLSBUaGUgdmFsdWUgb2YgdGhlIHByb3BlcnR5LCBpZiBpdCBleGlzdHMsIG90aGVyd2lzZSBgdW5kZWZpbmVkYFxuICogKiBleGlzdHMgLSBXaGV0aGVyIHRoZSBwcm9wZXJ0eSBleGlzdHMgb3Igbm90XG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IHBhdGhcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3RcbiAqIEByZXR1cm5zIHtPYmplY3R9IGluZm9cbiAqIEBuYW1lc3BhY2UgVXRpbHNcbiAqIEBuYW1lIGdldFBhdGhJbmZvXG4gKiBAYXBpIHB1YmxpY1xuICovXG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gZ2V0UGF0aEluZm8ocGF0aCwgb2JqKSB7XG4gIHZhciBwYXJzZWQgPSBwYXJzZVBhdGgocGF0aCksXG4gICAgICBsYXN0ID0gcGFyc2VkW3BhcnNlZC5sZW5ndGggLSAxXTtcblxuICB2YXIgaW5mbyA9IHtcbiAgICBwYXJlbnQ6IHBhcnNlZC5sZW5ndGggPiAxID8gX2dldFBhdGhWYWx1ZShwYXJzZWQsIG9iaiwgcGFyc2VkLmxlbmd0aCAtIDEpIDogb2JqLFxuICAgIG5hbWU6IGxhc3QucCB8fCBsYXN0LmksXG4gICAgdmFsdWU6IF9nZXRQYXRoVmFsdWUocGFyc2VkLCBvYmopXG4gIH07XG4gIGluZm8uZXhpc3RzID0gaGFzUHJvcGVydHkoaW5mby5uYW1lLCBpbmZvLnBhcmVudCk7XG5cbiAgcmV0dXJuIGluZm87XG59O1xuXG5cbi8qIVxuICogIyMgcGFyc2VQYXRoKHBhdGgpXG4gKlxuICogSGVscGVyIGZ1bmN0aW9uIHVzZWQgdG8gcGFyc2Ugc3RyaW5nIG9iamVjdFxuICogcGF0aHMuIFVzZSBpbiBjb25qdW5jdGlvbiB3aXRoIGBfZ2V0UGF0aFZhbHVlYC5cbiAqXG4gKiAgICAgIHZhciBwYXJzZWQgPSBwYXJzZVBhdGgoJ215b2JqZWN0LnByb3BlcnR5LnN1YnByb3AnKTtcbiAqXG4gKiAjIyMgUGF0aHM6XG4gKlxuICogKiBDYW4gYmUgYXMgbmVhciBpbmZpbml0ZWx5IGRlZXAgYW5kIG5lc3RlZFxuICogKiBBcnJheXMgYXJlIGFsc28gdmFsaWQgdXNpbmcgdGhlIGZvcm1hbCBgbXlvYmplY3QuZG9jdW1lbnRbM10ucHJvcGVydHlgLlxuICogKiBMaXRlcmFsIGRvdHMgYW5kIGJyYWNrZXRzIChub3QgZGVsaW1pdGVyKSBtdXN0IGJlIGJhY2tzbGFzaC1lc2NhcGVkLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBwYXRoXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBwYXJzZWRcbiAqIEBhcGkgcHJpdmF0ZVxuICovXG5cbmZ1bmN0aW9uIHBhcnNlUGF0aCAocGF0aCkge1xuICB2YXIgc3RyID0gcGF0aC5yZXBsYWNlKC8oW15cXFxcXSlcXFsvZywgJyQxLlsnKVxuICAgICwgcGFydHMgPSBzdHIubWF0Y2goLyhcXFxcXFwufFteLl0rPykrL2cpO1xuICByZXR1cm4gcGFydHMubWFwKGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgIHZhciByZSA9IC9eXFxbKFxcZCspXFxdJC9cbiAgICAgICwgbUFyciA9IHJlLmV4ZWModmFsdWUpO1xuICAgIGlmIChtQXJyKSByZXR1cm4geyBpOiBwYXJzZUZsb2F0KG1BcnJbMV0pIH07XG4gICAgZWxzZSByZXR1cm4geyBwOiB2YWx1ZS5yZXBsYWNlKC9cXFxcKFsuXFxbXFxdXSkvZywgJyQxJykgfTtcbiAgfSk7XG59XG5cblxuLyohXG4gKiAjIyBfZ2V0UGF0aFZhbHVlKHBhcnNlZCwgb2JqKVxuICpcbiAqIEhlbHBlciBjb21wYW5pb24gZnVuY3Rpb24gZm9yIGAucGFyc2VQYXRoYCB0aGF0IHJldHVybnNcbiAqIHRoZSB2YWx1ZSBsb2NhdGVkIGF0IHRoZSBwYXJzZWQgYWRkcmVzcy5cbiAqXG4gKiAgICAgIHZhciB2YWx1ZSA9IGdldFBhdGhWYWx1ZShwYXJzZWQsIG9iaik7XG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHBhcnNlZCBkZWZpbml0aW9uIGZyb20gYHBhcnNlUGF0aGAuXG4gKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0IHRvIHNlYXJjaCBhZ2FpbnN0XG4gKiBAcGFyYW0ge051bWJlcn0gb2JqZWN0IHRvIHNlYXJjaCBhZ2FpbnN0XG4gKiBAcmV0dXJucyB7T2JqZWN0fFVuZGVmaW5lZH0gdmFsdWVcbiAqIEBhcGkgcHJpdmF0ZVxuICovXG5cbmZ1bmN0aW9uIF9nZXRQYXRoVmFsdWUgKHBhcnNlZCwgb2JqLCBpbmRleCkge1xuICB2YXIgdG1wID0gb2JqXG4gICAgLCByZXM7XG5cbiAgaW5kZXggPSAoaW5kZXggPT09IHVuZGVmaW5lZCA/IHBhcnNlZC5sZW5ndGggOiBpbmRleCk7XG5cbiAgZm9yICh2YXIgaSA9IDAsIGwgPSBpbmRleDsgaSA8IGw7IGkrKykge1xuICAgIHZhciBwYXJ0ID0gcGFyc2VkW2ldO1xuICAgIGlmICh0bXApIHtcbiAgICAgIGlmICgndW5kZWZpbmVkJyAhPT0gdHlwZW9mIHBhcnQucClcbiAgICAgICAgdG1wID0gdG1wW3BhcnQucF07XG4gICAgICBlbHNlIGlmICgndW5kZWZpbmVkJyAhPT0gdHlwZW9mIHBhcnQuaSlcbiAgICAgICAgdG1wID0gdG1wW3BhcnQuaV07XG4gICAgICBpZiAoaSA9PSAobCAtIDEpKSByZXMgPSB0bXA7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJlcyA9IHVuZGVmaW5lZDtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHJlcztcbn1cbiIsIi8qIVxuICogQ2hhaSAtIGdldFBhdGhWYWx1ZSB1dGlsaXR5XG4gKiBDb3B5cmlnaHQoYykgMjAxMi0yMDE0IEpha2UgTHVlciA8amFrZUBhbG9naWNhbHBhcmFkb3guY29tPlxuICogQHNlZSBodHRwczovL2dpdGh1Yi5jb20vbG9naWNhbHBhcmFkb3gvZmlsdHJcbiAqIE1JVCBMaWNlbnNlZFxuICovXG5cbnZhciBnZXRQYXRoSW5mbyA9IHJlcXVpcmUoJy4vZ2V0UGF0aEluZm8nKTtcblxuLyoqXG4gKiAjIyMgLmdldFBhdGhWYWx1ZShwYXRoLCBvYmplY3QpXG4gKlxuICogVGhpcyBhbGxvd3MgdGhlIHJldHJpZXZhbCBvZiB2YWx1ZXMgaW4gYW5cbiAqIG9iamVjdCBnaXZlbiBhIHN0cmluZyBwYXRoLlxuICpcbiAqICAgICB2YXIgb2JqID0ge1xuICogICAgICAgICBwcm9wMToge1xuICogICAgICAgICAgICAgYXJyOiBbJ2EnLCAnYicsICdjJ11cbiAqICAgICAgICAgICAsIHN0cjogJ0hlbGxvJ1xuICogICAgICAgICB9XG4gKiAgICAgICAsIHByb3AyOiB7XG4gKiAgICAgICAgICAgICBhcnI6IFsgeyBuZXN0ZWQ6ICdVbml2ZXJzZScgfSBdXG4gKiAgICAgICAgICAgLCBzdHI6ICdIZWxsbyBhZ2FpbiEnXG4gKiAgICAgICAgIH1cbiAqICAgICB9XG4gKlxuICogVGhlIGZvbGxvd2luZyB3b3VsZCBiZSB0aGUgcmVzdWx0cy5cbiAqXG4gKiAgICAgZ2V0UGF0aFZhbHVlKCdwcm9wMS5zdHInLCBvYmopOyAvLyBIZWxsb1xuICogICAgIGdldFBhdGhWYWx1ZSgncHJvcDEuYXR0WzJdJywgb2JqKTsgLy8gYlxuICogICAgIGdldFBhdGhWYWx1ZSgncHJvcDIuYXJyWzBdLm5lc3RlZCcsIG9iaik7IC8vIFVuaXZlcnNlXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IHBhdGhcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3RcbiAqIEByZXR1cm5zIHtPYmplY3R9IHZhbHVlIG9yIGB1bmRlZmluZWRgXG4gKiBAbmFtZXNwYWNlIFV0aWxzXG4gKiBAbmFtZSBnZXRQYXRoVmFsdWVcbiAqIEBhcGkgcHVibGljXG4gKi9cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24ocGF0aCwgb2JqKSB7XG4gIHZhciBpbmZvID0gZ2V0UGF0aEluZm8ocGF0aCwgb2JqKTtcbiAgcmV0dXJuIGluZm8udmFsdWU7XG59O1xuIiwiLyohXG4gKiBDaGFpIC0gZ2V0UHJvcGVydGllcyB1dGlsaXR5XG4gKiBDb3B5cmlnaHQoYykgMjAxMi0yMDE0IEpha2UgTHVlciA8amFrZUBhbG9naWNhbHBhcmFkb3guY29tPlxuICogTUlUIExpY2Vuc2VkXG4gKi9cblxuLyoqXG4gKiAjIyMgLmdldFByb3BlcnRpZXMob2JqZWN0KVxuICpcbiAqIFRoaXMgYWxsb3dzIHRoZSByZXRyaWV2YWwgb2YgcHJvcGVydHkgbmFtZXMgb2YgYW4gb2JqZWN0LCBlbnVtZXJhYmxlIG9yIG5vdCxcbiAqIGluaGVyaXRlZCBvciBub3QuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IG9iamVjdFxuICogQHJldHVybnMge0FycmF5fVxuICogQG5hbWVzcGFjZSBVdGlsc1xuICogQG5hbWUgZ2V0UHJvcGVydGllc1xuICogQGFwaSBwdWJsaWNcbiAqL1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIGdldFByb3BlcnRpZXMob2JqZWN0KSB7XG4gIHZhciByZXN1bHQgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhvYmplY3QpO1xuXG4gIGZ1bmN0aW9uIGFkZFByb3BlcnR5KHByb3BlcnR5KSB7XG4gICAgaWYgKHJlc3VsdC5pbmRleE9mKHByb3BlcnR5KSA9PT0gLTEpIHtcbiAgICAgIHJlc3VsdC5wdXNoKHByb3BlcnR5KTtcbiAgICB9XG4gIH1cblxuICB2YXIgcHJvdG8gPSBPYmplY3QuZ2V0UHJvdG90eXBlT2Yob2JqZWN0KTtcbiAgd2hpbGUgKHByb3RvICE9PSBudWxsKSB7XG4gICAgT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMocHJvdG8pLmZvckVhY2goYWRkUHJvcGVydHkpO1xuICAgIHByb3RvID0gT2JqZWN0LmdldFByb3RvdHlwZU9mKHByb3RvKTtcbiAgfVxuXG4gIHJldHVybiByZXN1bHQ7XG59O1xuIiwiLyohXG4gKiBDaGFpIC0gaGFzUHJvcGVydHkgdXRpbGl0eVxuICogQ29weXJpZ2h0KGMpIDIwMTItMjAxNCBKYWtlIEx1ZXIgPGpha2VAYWxvZ2ljYWxwYXJhZG94LmNvbT5cbiAqIE1JVCBMaWNlbnNlZFxuICovXG5cbnZhciB0eXBlID0gcmVxdWlyZSgndHlwZS1kZXRlY3QnKTtcblxuLyoqXG4gKiAjIyMgLmhhc1Byb3BlcnR5KG9iamVjdCwgbmFtZSlcbiAqXG4gKiBUaGlzIGFsbG93cyBjaGVja2luZyB3aGV0aGVyIGFuIG9iamVjdCBoYXNcbiAqIG5hbWVkIHByb3BlcnR5IG9yIG51bWVyaWMgYXJyYXkgaW5kZXguXG4gKlxuICogQmFzaWNhbGx5IGRvZXMgdGhlIHNhbWUgdGhpbmcgYXMgdGhlIGBpbmBcbiAqIG9wZXJhdG9yIGJ1dCB3b3JrcyBwcm9wZXJseSB3aXRoIG5hdGl2ZXNcbiAqIGFuZCBudWxsL3VuZGVmaW5lZCB2YWx1ZXMuXG4gKlxuICogICAgIHZhciBvYmogPSB7XG4gKiAgICAgICAgIGFycjogWydhJywgJ2InLCAnYyddXG4gKiAgICAgICAsIHN0cjogJ0hlbGxvJ1xuICogICAgIH1cbiAqXG4gKiBUaGUgZm9sbG93aW5nIHdvdWxkIGJlIHRoZSByZXN1bHRzLlxuICpcbiAqICAgICBoYXNQcm9wZXJ0eSgnc3RyJywgb2JqKTsgIC8vIHRydWVcbiAqICAgICBoYXNQcm9wZXJ0eSgnY29uc3RydWN0b3InLCBvYmopOyAgLy8gdHJ1ZVxuICogICAgIGhhc1Byb3BlcnR5KCdiYXInLCBvYmopOyAgLy8gZmFsc2VcbiAqXG4gKiAgICAgaGFzUHJvcGVydHkoJ2xlbmd0aCcsIG9iai5zdHIpOyAvLyB0cnVlXG4gKiAgICAgaGFzUHJvcGVydHkoMSwgb2JqLnN0cik7ICAvLyB0cnVlXG4gKiAgICAgaGFzUHJvcGVydHkoNSwgb2JqLnN0cik7ICAvLyBmYWxzZVxuICpcbiAqICAgICBoYXNQcm9wZXJ0eSgnbGVuZ3RoJywgb2JqLmFycik7ICAvLyB0cnVlXG4gKiAgICAgaGFzUHJvcGVydHkoMiwgb2JqLmFycik7ICAvLyB0cnVlXG4gKiAgICAgaGFzUHJvcGVydHkoMywgb2JqLmFycik7ICAvLyBmYWxzZVxuICpcbiAqIEBwYXJhbSB7T2JqdWVjdH0gb2JqZWN0XG4gKiBAcGFyYW0ge1N0cmluZ3xOdW1iZXJ9IG5hbWVcbiAqIEByZXR1cm5zIHtCb29sZWFufSB3aGV0aGVyIGl0IGV4aXN0c1xuICogQG5hbWVzcGFjZSBVdGlsc1xuICogQG5hbWUgZ2V0UGF0aEluZm9cbiAqIEBhcGkgcHVibGljXG4gKi9cblxudmFyIGxpdGVyYWxzID0ge1xuICAgICdudW1iZXInOiBOdW1iZXJcbiAgLCAnc3RyaW5nJzogU3RyaW5nXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIGhhc1Byb3BlcnR5KG5hbWUsIG9iaikge1xuICB2YXIgb3QgPSB0eXBlKG9iaik7XG5cbiAgLy8gQmFkIE9iamVjdCwgb2J2aW91c2x5IG5vIHByb3BzIGF0IGFsbFxuICBpZihvdCA9PT0gJ251bGwnIHx8IG90ID09PSAndW5kZWZpbmVkJylcbiAgICByZXR1cm4gZmFsc2U7XG5cbiAgLy8gVGhlIGBpbmAgb3BlcmF0b3IgZG9lcyBub3Qgd29yayB3aXRoIGNlcnRhaW4gbGl0ZXJhbHNcbiAgLy8gYm94IHRoZXNlIGJlZm9yZSB0aGUgY2hlY2tcbiAgaWYobGl0ZXJhbHNbb3RdICYmIHR5cGVvZiBvYmogIT09ICdvYmplY3QnKVxuICAgIG9iaiA9IG5ldyBsaXRlcmFsc1tvdF0ob2JqKTtcblxuICByZXR1cm4gbmFtZSBpbiBvYmo7XG59O1xuIiwiLyohXG4gKiBjaGFpXG4gKiBDb3B5cmlnaHQoYykgMjAxMSBKYWtlIEx1ZXIgPGpha2VAYWxvZ2ljYWxwYXJhZG94LmNvbT5cbiAqIE1JVCBMaWNlbnNlZFxuICovXG5cbi8qIVxuICogTWFpbiBleHBvcnRzXG4gKi9cblxudmFyIGV4cG9ydHMgPSBtb2R1bGUuZXhwb3J0cyA9IHt9O1xuXG4vKiFcbiAqIHRlc3QgdXRpbGl0eVxuICovXG5cbmV4cG9ydHMudGVzdCA9IHJlcXVpcmUoJy4vdGVzdCcpO1xuXG4vKiFcbiAqIHR5cGUgdXRpbGl0eVxuICovXG5cbmV4cG9ydHMudHlwZSA9IHJlcXVpcmUoJ3R5cGUtZGV0ZWN0Jyk7XG5cbi8qIVxuICogZXhwZWN0VHlwZXMgdXRpbGl0eVxuICovXG5leHBvcnRzLmV4cGVjdFR5cGVzID0gcmVxdWlyZSgnLi9leHBlY3RUeXBlcycpO1xuXG4vKiFcbiAqIG1lc3NhZ2UgdXRpbGl0eVxuICovXG5cbmV4cG9ydHMuZ2V0TWVzc2FnZSA9IHJlcXVpcmUoJy4vZ2V0TWVzc2FnZScpO1xuXG4vKiFcbiAqIGFjdHVhbCB1dGlsaXR5XG4gKi9cblxuZXhwb3J0cy5nZXRBY3R1YWwgPSByZXF1aXJlKCcuL2dldEFjdHVhbCcpO1xuXG4vKiFcbiAqIEluc3BlY3QgdXRpbFxuICovXG5cbmV4cG9ydHMuaW5zcGVjdCA9IHJlcXVpcmUoJy4vaW5zcGVjdCcpO1xuXG4vKiFcbiAqIE9iamVjdCBEaXNwbGF5IHV0aWxcbiAqL1xuXG5leHBvcnRzLm9iakRpc3BsYXkgPSByZXF1aXJlKCcuL29iakRpc3BsYXknKTtcblxuLyohXG4gKiBGbGFnIHV0aWxpdHlcbiAqL1xuXG5leHBvcnRzLmZsYWcgPSByZXF1aXJlKCcuL2ZsYWcnKTtcblxuLyohXG4gKiBGbGFnIHRyYW5zZmVycmluZyB1dGlsaXR5XG4gKi9cblxuZXhwb3J0cy50cmFuc2ZlckZsYWdzID0gcmVxdWlyZSgnLi90cmFuc2ZlckZsYWdzJyk7XG5cbi8qIVxuICogRGVlcCBlcXVhbCB1dGlsaXR5XG4gKi9cblxuZXhwb3J0cy5lcWwgPSByZXF1aXJlKCdkZWVwLWVxbCcpO1xuXG4vKiFcbiAqIERlZXAgcGF0aCB2YWx1ZVxuICovXG5cbmV4cG9ydHMuZ2V0UGF0aFZhbHVlID0gcmVxdWlyZSgnLi9nZXRQYXRoVmFsdWUnKTtcblxuLyohXG4gKiBEZWVwIHBhdGggaW5mb1xuICovXG5cbmV4cG9ydHMuZ2V0UGF0aEluZm8gPSByZXF1aXJlKCcuL2dldFBhdGhJbmZvJyk7XG5cbi8qIVxuICogQ2hlY2sgaWYgYSBwcm9wZXJ0eSBleGlzdHNcbiAqL1xuXG5leHBvcnRzLmhhc1Byb3BlcnR5ID0gcmVxdWlyZSgnLi9oYXNQcm9wZXJ0eScpO1xuXG4vKiFcbiAqIEZ1bmN0aW9uIG5hbWVcbiAqL1xuXG5leHBvcnRzLmdldE5hbWUgPSByZXF1aXJlKCcuL2dldE5hbWUnKTtcblxuLyohXG4gKiBhZGQgUHJvcGVydHlcbiAqL1xuXG5leHBvcnRzLmFkZFByb3BlcnR5ID0gcmVxdWlyZSgnLi9hZGRQcm9wZXJ0eScpO1xuXG4vKiFcbiAqIGFkZCBNZXRob2RcbiAqL1xuXG5leHBvcnRzLmFkZE1ldGhvZCA9IHJlcXVpcmUoJy4vYWRkTWV0aG9kJyk7XG5cbi8qIVxuICogb3ZlcndyaXRlIFByb3BlcnR5XG4gKi9cblxuZXhwb3J0cy5vdmVyd3JpdGVQcm9wZXJ0eSA9IHJlcXVpcmUoJy4vb3ZlcndyaXRlUHJvcGVydHknKTtcblxuLyohXG4gKiBvdmVyd3JpdGUgTWV0aG9kXG4gKi9cblxuZXhwb3J0cy5vdmVyd3JpdGVNZXRob2QgPSByZXF1aXJlKCcuL292ZXJ3cml0ZU1ldGhvZCcpO1xuXG4vKiFcbiAqIEFkZCBhIGNoYWluYWJsZSBtZXRob2RcbiAqL1xuXG5leHBvcnRzLmFkZENoYWluYWJsZU1ldGhvZCA9IHJlcXVpcmUoJy4vYWRkQ2hhaW5hYmxlTWV0aG9kJyk7XG5cbi8qIVxuICogT3ZlcndyaXRlIGNoYWluYWJsZSBtZXRob2RcbiAqL1xuXG5leHBvcnRzLm92ZXJ3cml0ZUNoYWluYWJsZU1ldGhvZCA9IHJlcXVpcmUoJy4vb3ZlcndyaXRlQ2hhaW5hYmxlTWV0aG9kJyk7XG4iLCIvLyBUaGlzIGlzIChhbG1vc3QpIGRpcmVjdGx5IGZyb20gTm9kZS5qcyB1dGlsc1xuLy8gaHR0cHM6Ly9naXRodWIuY29tL2pveWVudC9ub2RlL2Jsb2IvZjhjMzM1ZDBjYWY0N2YxNmQzMTQxM2Y4OWFhMjhlZGEzODc4ZTNhYS9saWIvdXRpbC5qc1xuXG52YXIgZ2V0TmFtZSA9IHJlcXVpcmUoJy4vZ2V0TmFtZScpO1xudmFyIGdldFByb3BlcnRpZXMgPSByZXF1aXJlKCcuL2dldFByb3BlcnRpZXMnKTtcbnZhciBnZXRFbnVtZXJhYmxlUHJvcGVydGllcyA9IHJlcXVpcmUoJy4vZ2V0RW51bWVyYWJsZVByb3BlcnRpZXMnKTtcblxubW9kdWxlLmV4cG9ydHMgPSBpbnNwZWN0O1xuXG4vKipcbiAqIEVjaG9zIHRoZSB2YWx1ZSBvZiBhIHZhbHVlLiBUcnlzIHRvIHByaW50IHRoZSB2YWx1ZSBvdXRcbiAqIGluIHRoZSBiZXN0IHdheSBwb3NzaWJsZSBnaXZlbiB0aGUgZGlmZmVyZW50IHR5cGVzLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmogVGhlIG9iamVjdCB0byBwcmludCBvdXQuXG4gKiBAcGFyYW0ge0Jvb2xlYW59IHNob3dIaWRkZW4gRmxhZyB0aGF0IHNob3dzIGhpZGRlbiAobm90IGVudW1lcmFibGUpXG4gKiAgICBwcm9wZXJ0aWVzIG9mIG9iamVjdHMuXG4gKiBAcGFyYW0ge051bWJlcn0gZGVwdGggRGVwdGggaW4gd2hpY2ggdG8gZGVzY2VuZCBpbiBvYmplY3QuIERlZmF1bHQgaXMgMi5cbiAqIEBwYXJhbSB7Qm9vbGVhbn0gY29sb3JzIEZsYWcgdG8gdHVybiBvbiBBTlNJIGVzY2FwZSBjb2RlcyB0byBjb2xvciB0aGVcbiAqICAgIG91dHB1dC4gRGVmYXVsdCBpcyBmYWxzZSAobm8gY29sb3JpbmcpLlxuICogQG5hbWVzcGFjZSBVdGlsc1xuICogQG5hbWUgaW5zcGVjdFxuICovXG5mdW5jdGlvbiBpbnNwZWN0KG9iaiwgc2hvd0hpZGRlbiwgZGVwdGgsIGNvbG9ycykge1xuICB2YXIgY3R4ID0ge1xuICAgIHNob3dIaWRkZW46IHNob3dIaWRkZW4sXG4gICAgc2VlbjogW10sXG4gICAgc3R5bGl6ZTogZnVuY3Rpb24gKHN0cikgeyByZXR1cm4gc3RyOyB9XG4gIH07XG4gIHJldHVybiBmb3JtYXRWYWx1ZShjdHgsIG9iaiwgKHR5cGVvZiBkZXB0aCA9PT0gJ3VuZGVmaW5lZCcgPyAyIDogZGVwdGgpKTtcbn1cblxuLy8gUmV0dXJucyB0cnVlIGlmIG9iamVjdCBpcyBhIERPTSBlbGVtZW50LlxudmFyIGlzRE9NRWxlbWVudCA9IGZ1bmN0aW9uIChvYmplY3QpIHtcbiAgaWYgKHR5cGVvZiBIVE1MRWxlbWVudCA9PT0gJ29iamVjdCcpIHtcbiAgICByZXR1cm4gb2JqZWN0IGluc3RhbmNlb2YgSFRNTEVsZW1lbnQ7XG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIG9iamVjdCAmJlxuICAgICAgdHlwZW9mIG9iamVjdCA9PT0gJ29iamVjdCcgJiZcbiAgICAgIG9iamVjdC5ub2RlVHlwZSA9PT0gMSAmJlxuICAgICAgdHlwZW9mIG9iamVjdC5ub2RlTmFtZSA9PT0gJ3N0cmluZyc7XG4gIH1cbn07XG5cbmZ1bmN0aW9uIGZvcm1hdFZhbHVlKGN0eCwgdmFsdWUsIHJlY3Vyc2VUaW1lcykge1xuICAvLyBQcm92aWRlIGEgaG9vayBmb3IgdXNlci1zcGVjaWZpZWQgaW5zcGVjdCBmdW5jdGlvbnMuXG4gIC8vIENoZWNrIHRoYXQgdmFsdWUgaXMgYW4gb2JqZWN0IHdpdGggYW4gaW5zcGVjdCBmdW5jdGlvbiBvbiBpdFxuICBpZiAodmFsdWUgJiYgdHlwZW9mIHZhbHVlLmluc3BlY3QgPT09ICdmdW5jdGlvbicgJiZcbiAgICAgIC8vIEZpbHRlciBvdXQgdGhlIHV0aWwgbW9kdWxlLCBpdCdzIGluc3BlY3QgZnVuY3Rpb24gaXMgc3BlY2lhbFxuICAgICAgdmFsdWUuaW5zcGVjdCAhPT0gZXhwb3J0cy5pbnNwZWN0ICYmXG4gICAgICAvLyBBbHNvIGZpbHRlciBvdXQgYW55IHByb3RvdHlwZSBvYmplY3RzIHVzaW5nIHRoZSBjaXJjdWxhciBjaGVjay5cbiAgICAgICEodmFsdWUuY29uc3RydWN0b3IgJiYgdmFsdWUuY29uc3RydWN0b3IucHJvdG90eXBlID09PSB2YWx1ZSkpIHtcbiAgICB2YXIgcmV0ID0gdmFsdWUuaW5zcGVjdChyZWN1cnNlVGltZXMpO1xuICAgIGlmICh0eXBlb2YgcmV0ICE9PSAnc3RyaW5nJykge1xuICAgICAgcmV0ID0gZm9ybWF0VmFsdWUoY3R4LCByZXQsIHJlY3Vyc2VUaW1lcyk7XG4gICAgfVxuICAgIHJldHVybiByZXQ7XG4gIH1cblxuICAvLyBQcmltaXRpdmUgdHlwZXMgY2Fubm90IGhhdmUgcHJvcGVydGllc1xuICB2YXIgcHJpbWl0aXZlID0gZm9ybWF0UHJpbWl0aXZlKGN0eCwgdmFsdWUpO1xuICBpZiAocHJpbWl0aXZlKSB7XG4gICAgcmV0dXJuIHByaW1pdGl2ZTtcbiAgfVxuXG4gIC8vIElmIHRoaXMgaXMgYSBET00gZWxlbWVudCwgdHJ5IHRvIGdldCB0aGUgb3V0ZXIgSFRNTC5cbiAgaWYgKGlzRE9NRWxlbWVudCh2YWx1ZSkpIHtcbiAgICBpZiAoJ291dGVySFRNTCcgaW4gdmFsdWUpIHtcbiAgICAgIHJldHVybiB2YWx1ZS5vdXRlckhUTUw7XG4gICAgICAvLyBUaGlzIHZhbHVlIGRvZXMgbm90IGhhdmUgYW4gb3V0ZXJIVE1MIGF0dHJpYnV0ZSxcbiAgICAgIC8vICAgaXQgY291bGQgc3RpbGwgYmUgYW4gWE1MIGVsZW1lbnRcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gQXR0ZW1wdCB0byBzZXJpYWxpemUgaXRcbiAgICAgIHRyeSB7XG4gICAgICAgIGlmIChkb2N1bWVudC54bWxWZXJzaW9uKSB7XG4gICAgICAgICAgdmFyIHhtbFNlcmlhbGl6ZXIgPSBuZXcgWE1MU2VyaWFsaXplcigpO1xuICAgICAgICAgIHJldHVybiB4bWxTZXJpYWxpemVyLnNlcmlhbGl6ZVRvU3RyaW5nKHZhbHVlKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBGaXJlZm94IDExLSBkbyBub3Qgc3VwcG9ydCBvdXRlckhUTUxcbiAgICAgICAgICAvLyAgIEl0IGRvZXMsIGhvd2V2ZXIsIHN1cHBvcnQgaW5uZXJIVE1MXG4gICAgICAgICAgLy8gICBVc2UgdGhlIGZvbGxvd2luZyB0byByZW5kZXIgdGhlIGVsZW1lbnRcbiAgICAgICAgICB2YXIgbnMgPSBcImh0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWxcIjtcbiAgICAgICAgICB2YXIgY29udGFpbmVyID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudE5TKG5zLCAnXycpO1xuXG4gICAgICAgICAgY29udGFpbmVyLmFwcGVuZENoaWxkKHZhbHVlLmNsb25lTm9kZShmYWxzZSkpO1xuICAgICAgICAgIGh0bWwgPSBjb250YWluZXIuaW5uZXJIVE1MXG4gICAgICAgICAgICAucmVwbGFjZSgnPjwnLCAnPicgKyB2YWx1ZS5pbm5lckhUTUwgKyAnPCcpO1xuICAgICAgICAgIGNvbnRhaW5lci5pbm5lckhUTUwgPSAnJztcbiAgICAgICAgICByZXR1cm4gaHRtbDtcbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIC8vIFRoaXMgY291bGQgYmUgYSBub24tbmF0aXZlIERPTSBpbXBsZW1lbnRhdGlvbixcbiAgICAgICAgLy8gICBjb250aW51ZSB3aXRoIHRoZSBub3JtYWwgZmxvdzpcbiAgICAgICAgLy8gICBwcmludGluZyB0aGUgZWxlbWVudCBhcyBpZiBpdCBpcyBhbiBvYmplY3QuXG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gTG9vayB1cCB0aGUga2V5cyBvZiB0aGUgb2JqZWN0LlxuICB2YXIgdmlzaWJsZUtleXMgPSBnZXRFbnVtZXJhYmxlUHJvcGVydGllcyh2YWx1ZSk7XG4gIHZhciBrZXlzID0gY3R4LnNob3dIaWRkZW4gPyBnZXRQcm9wZXJ0aWVzKHZhbHVlKSA6IHZpc2libGVLZXlzO1xuXG4gIC8vIFNvbWUgdHlwZSBvZiBvYmplY3Qgd2l0aG91dCBwcm9wZXJ0aWVzIGNhbiBiZSBzaG9ydGN1dHRlZC5cbiAgLy8gSW4gSUUsIGVycm9ycyBoYXZlIGEgc2luZ2xlIGBzdGFja2AgcHJvcGVydHksIG9yIGlmIHRoZXkgYXJlIHZhbmlsbGEgYEVycm9yYCxcbiAgLy8gYSBgc3RhY2tgIHBsdXMgYGRlc2NyaXB0aW9uYCBwcm9wZXJ0eTsgaWdub3JlIHRob3NlIGZvciBjb25zaXN0ZW5jeS5cbiAgaWYgKGtleXMubGVuZ3RoID09PSAwIHx8IChpc0Vycm9yKHZhbHVlKSAmJiAoXG4gICAgICAoa2V5cy5sZW5ndGggPT09IDEgJiYga2V5c1swXSA9PT0gJ3N0YWNrJykgfHxcbiAgICAgIChrZXlzLmxlbmd0aCA9PT0gMiAmJiBrZXlzWzBdID09PSAnZGVzY3JpcHRpb24nICYmIGtleXNbMV0gPT09ICdzdGFjaycpXG4gICAgICkpKSB7XG4gICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgdmFyIG5hbWUgPSBnZXROYW1lKHZhbHVlKTtcbiAgICAgIHZhciBuYW1lU3VmZml4ID0gbmFtZSA/ICc6ICcgKyBuYW1lIDogJyc7XG4gICAgICByZXR1cm4gY3R4LnN0eWxpemUoJ1tGdW5jdGlvbicgKyBuYW1lU3VmZml4ICsgJ10nLCAnc3BlY2lhbCcpO1xuICAgIH1cbiAgICBpZiAoaXNSZWdFeHAodmFsdWUpKSB7XG4gICAgICByZXR1cm4gY3R4LnN0eWxpemUoUmVnRXhwLnByb3RvdHlwZS50b1N0cmluZy5jYWxsKHZhbHVlKSwgJ3JlZ2V4cCcpO1xuICAgIH1cbiAgICBpZiAoaXNEYXRlKHZhbHVlKSkge1xuICAgICAgcmV0dXJuIGN0eC5zdHlsaXplKERhdGUucHJvdG90eXBlLnRvVVRDU3RyaW5nLmNhbGwodmFsdWUpLCAnZGF0ZScpO1xuICAgIH1cbiAgICBpZiAoaXNFcnJvcih2YWx1ZSkpIHtcbiAgICAgIHJldHVybiBmb3JtYXRFcnJvcih2YWx1ZSk7XG4gICAgfVxuICB9XG5cbiAgdmFyIGJhc2UgPSAnJywgYXJyYXkgPSBmYWxzZSwgYnJhY2VzID0gWyd7JywgJ30nXTtcblxuICAvLyBNYWtlIEFycmF5IHNheSB0aGF0IHRoZXkgYXJlIEFycmF5XG4gIGlmIChpc0FycmF5KHZhbHVlKSkge1xuICAgIGFycmF5ID0gdHJ1ZTtcbiAgICBicmFjZXMgPSBbJ1snLCAnXSddO1xuICB9XG5cbiAgLy8gTWFrZSBmdW5jdGlvbnMgc2F5IHRoYXQgdGhleSBhcmUgZnVuY3Rpb25zXG4gIGlmICh0eXBlb2YgdmFsdWUgPT09ICdmdW5jdGlvbicpIHtcbiAgICB2YXIgbmFtZSA9IGdldE5hbWUodmFsdWUpO1xuICAgIHZhciBuYW1lU3VmZml4ID0gbmFtZSA/ICc6ICcgKyBuYW1lIDogJyc7XG4gICAgYmFzZSA9ICcgW0Z1bmN0aW9uJyArIG5hbWVTdWZmaXggKyAnXSc7XG4gIH1cblxuICAvLyBNYWtlIFJlZ0V4cHMgc2F5IHRoYXQgdGhleSBhcmUgUmVnRXhwc1xuICBpZiAoaXNSZWdFeHAodmFsdWUpKSB7XG4gICAgYmFzZSA9ICcgJyArIFJlZ0V4cC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbCh2YWx1ZSk7XG4gIH1cblxuICAvLyBNYWtlIGRhdGVzIHdpdGggcHJvcGVydGllcyBmaXJzdCBzYXkgdGhlIGRhdGVcbiAgaWYgKGlzRGF0ZSh2YWx1ZSkpIHtcbiAgICBiYXNlID0gJyAnICsgRGF0ZS5wcm90b3R5cGUudG9VVENTdHJpbmcuY2FsbCh2YWx1ZSk7XG4gIH1cblxuICAvLyBNYWtlIGVycm9yIHdpdGggbWVzc2FnZSBmaXJzdCBzYXkgdGhlIGVycm9yXG4gIGlmIChpc0Vycm9yKHZhbHVlKSkge1xuICAgIHJldHVybiBmb3JtYXRFcnJvcih2YWx1ZSk7XG4gIH1cblxuICBpZiAoa2V5cy5sZW5ndGggPT09IDAgJiYgKCFhcnJheSB8fCB2YWx1ZS5sZW5ndGggPT0gMCkpIHtcbiAgICByZXR1cm4gYnJhY2VzWzBdICsgYmFzZSArIGJyYWNlc1sxXTtcbiAgfVxuXG4gIGlmIChyZWN1cnNlVGltZXMgPCAwKSB7XG4gICAgaWYgKGlzUmVnRXhwKHZhbHVlKSkge1xuICAgICAgcmV0dXJuIGN0eC5zdHlsaXplKFJlZ0V4cC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbCh2YWx1ZSksICdyZWdleHAnKTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIGN0eC5zdHlsaXplKCdbT2JqZWN0XScsICdzcGVjaWFsJyk7XG4gICAgfVxuICB9XG5cbiAgY3R4LnNlZW4ucHVzaCh2YWx1ZSk7XG5cbiAgdmFyIG91dHB1dDtcbiAgaWYgKGFycmF5KSB7XG4gICAgb3V0cHV0ID0gZm9ybWF0QXJyYXkoY3R4LCB2YWx1ZSwgcmVjdXJzZVRpbWVzLCB2aXNpYmxlS2V5cywga2V5cyk7XG4gIH0gZWxzZSB7XG4gICAgb3V0cHV0ID0ga2V5cy5tYXAoZnVuY3Rpb24oa2V5KSB7XG4gICAgICByZXR1cm4gZm9ybWF0UHJvcGVydHkoY3R4LCB2YWx1ZSwgcmVjdXJzZVRpbWVzLCB2aXNpYmxlS2V5cywga2V5LCBhcnJheSk7XG4gICAgfSk7XG4gIH1cblxuICBjdHguc2Vlbi5wb3AoKTtcblxuICByZXR1cm4gcmVkdWNlVG9TaW5nbGVTdHJpbmcob3V0cHV0LCBiYXNlLCBicmFjZXMpO1xufVxuXG5cbmZ1bmN0aW9uIGZvcm1hdFByaW1pdGl2ZShjdHgsIHZhbHVlKSB7XG4gIHN3aXRjaCAodHlwZW9mIHZhbHVlKSB7XG4gICAgY2FzZSAndW5kZWZpbmVkJzpcbiAgICAgIHJldHVybiBjdHguc3R5bGl6ZSgndW5kZWZpbmVkJywgJ3VuZGVmaW5lZCcpO1xuXG4gICAgY2FzZSAnc3RyaW5nJzpcbiAgICAgIHZhciBzaW1wbGUgPSAnXFwnJyArIEpTT04uc3RyaW5naWZ5KHZhbHVlKS5yZXBsYWNlKC9eXCJ8XCIkL2csICcnKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAucmVwbGFjZSgvJy9nLCBcIlxcXFwnXCIpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5yZXBsYWNlKC9cXFxcXCIvZywgJ1wiJykgKyAnXFwnJztcbiAgICAgIHJldHVybiBjdHguc3R5bGl6ZShzaW1wbGUsICdzdHJpbmcnKTtcblxuICAgIGNhc2UgJ251bWJlcic6XG4gICAgICBpZiAodmFsdWUgPT09IDAgJiYgKDEvdmFsdWUpID09PSAtSW5maW5pdHkpIHtcbiAgICAgICAgcmV0dXJuIGN0eC5zdHlsaXplKCctMCcsICdudW1iZXInKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBjdHguc3R5bGl6ZSgnJyArIHZhbHVlLCAnbnVtYmVyJyk7XG5cbiAgICBjYXNlICdib29sZWFuJzpcbiAgICAgIHJldHVybiBjdHguc3R5bGl6ZSgnJyArIHZhbHVlLCAnYm9vbGVhbicpO1xuICB9XG4gIC8vIEZvciBzb21lIHJlYXNvbiB0eXBlb2YgbnVsbCBpcyBcIm9iamVjdFwiLCBzbyBzcGVjaWFsIGNhc2UgaGVyZS5cbiAgaWYgKHZhbHVlID09PSBudWxsKSB7XG4gICAgcmV0dXJuIGN0eC5zdHlsaXplKCdudWxsJywgJ251bGwnKTtcbiAgfVxufVxuXG5cbmZ1bmN0aW9uIGZvcm1hdEVycm9yKHZhbHVlKSB7XG4gIHJldHVybiAnWycgKyBFcnJvci5wcm90b3R5cGUudG9TdHJpbmcuY2FsbCh2YWx1ZSkgKyAnXSc7XG59XG5cblxuZnVuY3Rpb24gZm9ybWF0QXJyYXkoY3R4LCB2YWx1ZSwgcmVjdXJzZVRpbWVzLCB2aXNpYmxlS2V5cywga2V5cykge1xuICB2YXIgb3V0cHV0ID0gW107XG4gIGZvciAodmFyIGkgPSAwLCBsID0gdmFsdWUubGVuZ3RoOyBpIDwgbDsgKytpKSB7XG4gICAgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh2YWx1ZSwgU3RyaW5nKGkpKSkge1xuICAgICAgb3V0cHV0LnB1c2goZm9ybWF0UHJvcGVydHkoY3R4LCB2YWx1ZSwgcmVjdXJzZVRpbWVzLCB2aXNpYmxlS2V5cyxcbiAgICAgICAgICBTdHJpbmcoaSksIHRydWUpKTtcbiAgICB9IGVsc2Uge1xuICAgICAgb3V0cHV0LnB1c2goJycpO1xuICAgIH1cbiAgfVxuICBrZXlzLmZvckVhY2goZnVuY3Rpb24oa2V5KSB7XG4gICAgaWYgKCFrZXkubWF0Y2goL15cXGQrJC8pKSB7XG4gICAgICBvdXRwdXQucHVzaChmb3JtYXRQcm9wZXJ0eShjdHgsIHZhbHVlLCByZWN1cnNlVGltZXMsIHZpc2libGVLZXlzLFxuICAgICAgICAgIGtleSwgdHJ1ZSkpO1xuICAgIH1cbiAgfSk7XG4gIHJldHVybiBvdXRwdXQ7XG59XG5cblxuZnVuY3Rpb24gZm9ybWF0UHJvcGVydHkoY3R4LCB2YWx1ZSwgcmVjdXJzZVRpbWVzLCB2aXNpYmxlS2V5cywga2V5LCBhcnJheSkge1xuICB2YXIgbmFtZSwgc3RyO1xuICBpZiAodmFsdWUuX19sb29rdXBHZXR0ZXJfXykge1xuICAgIGlmICh2YWx1ZS5fX2xvb2t1cEdldHRlcl9fKGtleSkpIHtcbiAgICAgIGlmICh2YWx1ZS5fX2xvb2t1cFNldHRlcl9fKGtleSkpIHtcbiAgICAgICAgc3RyID0gY3R4LnN0eWxpemUoJ1tHZXR0ZXIvU2V0dGVyXScsICdzcGVjaWFsJyk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBzdHIgPSBjdHguc3R5bGl6ZSgnW0dldHRlcl0nLCAnc3BlY2lhbCcpO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBpZiAodmFsdWUuX19sb29rdXBTZXR0ZXJfXyhrZXkpKSB7XG4gICAgICAgIHN0ciA9IGN0eC5zdHlsaXplKCdbU2V0dGVyXScsICdzcGVjaWFsJyk7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIGlmICh2aXNpYmxlS2V5cy5pbmRleE9mKGtleSkgPCAwKSB7XG4gICAgbmFtZSA9ICdbJyArIGtleSArICddJztcbiAgfVxuICBpZiAoIXN0cikge1xuICAgIGlmIChjdHguc2Vlbi5pbmRleE9mKHZhbHVlW2tleV0pIDwgMCkge1xuICAgICAgaWYgKHJlY3Vyc2VUaW1lcyA9PT0gbnVsbCkge1xuICAgICAgICBzdHIgPSBmb3JtYXRWYWx1ZShjdHgsIHZhbHVlW2tleV0sIG51bGwpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgc3RyID0gZm9ybWF0VmFsdWUoY3R4LCB2YWx1ZVtrZXldLCByZWN1cnNlVGltZXMgLSAxKTtcbiAgICAgIH1cbiAgICAgIGlmIChzdHIuaW5kZXhPZignXFxuJykgPiAtMSkge1xuICAgICAgICBpZiAoYXJyYXkpIHtcbiAgICAgICAgICBzdHIgPSBzdHIuc3BsaXQoJ1xcbicpLm1hcChmdW5jdGlvbihsaW5lKSB7XG4gICAgICAgICAgICByZXR1cm4gJyAgJyArIGxpbmU7XG4gICAgICAgICAgfSkuam9pbignXFxuJykuc3Vic3RyKDIpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHN0ciA9ICdcXG4nICsgc3RyLnNwbGl0KCdcXG4nKS5tYXAoZnVuY3Rpb24obGluZSkge1xuICAgICAgICAgICAgcmV0dXJuICcgICAnICsgbGluZTtcbiAgICAgICAgICB9KS5qb2luKCdcXG4nKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBzdHIgPSBjdHguc3R5bGl6ZSgnW0NpcmN1bGFyXScsICdzcGVjaWFsJyk7XG4gICAgfVxuICB9XG4gIGlmICh0eXBlb2YgbmFtZSA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBpZiAoYXJyYXkgJiYga2V5Lm1hdGNoKC9eXFxkKyQvKSkge1xuICAgICAgcmV0dXJuIHN0cjtcbiAgICB9XG4gICAgbmFtZSA9IEpTT04uc3RyaW5naWZ5KCcnICsga2V5KTtcbiAgICBpZiAobmFtZS5tYXRjaCgvXlwiKFthLXpBLVpfXVthLXpBLVpfMC05XSopXCIkLykpIHtcbiAgICAgIG5hbWUgPSBuYW1lLnN1YnN0cigxLCBuYW1lLmxlbmd0aCAtIDIpO1xuICAgICAgbmFtZSA9IGN0eC5zdHlsaXplKG5hbWUsICduYW1lJyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIG5hbWUgPSBuYW1lLnJlcGxhY2UoLycvZywgXCJcXFxcJ1wiKVxuICAgICAgICAgICAgICAgICAucmVwbGFjZSgvXFxcXFwiL2csICdcIicpXG4gICAgICAgICAgICAgICAgIC5yZXBsYWNlKC8oXlwifFwiJCkvZywgXCInXCIpO1xuICAgICAgbmFtZSA9IGN0eC5zdHlsaXplKG5hbWUsICdzdHJpbmcnKTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gbmFtZSArICc6ICcgKyBzdHI7XG59XG5cblxuZnVuY3Rpb24gcmVkdWNlVG9TaW5nbGVTdHJpbmcob3V0cHV0LCBiYXNlLCBicmFjZXMpIHtcbiAgdmFyIG51bUxpbmVzRXN0ID0gMDtcbiAgdmFyIGxlbmd0aCA9IG91dHB1dC5yZWR1Y2UoZnVuY3Rpb24ocHJldiwgY3VyKSB7XG4gICAgbnVtTGluZXNFc3QrKztcbiAgICBpZiAoY3VyLmluZGV4T2YoJ1xcbicpID49IDApIG51bUxpbmVzRXN0Kys7XG4gICAgcmV0dXJuIHByZXYgKyBjdXIubGVuZ3RoICsgMTtcbiAgfSwgMCk7XG5cbiAgaWYgKGxlbmd0aCA+IDYwKSB7XG4gICAgcmV0dXJuIGJyYWNlc1swXSArXG4gICAgICAgICAgIChiYXNlID09PSAnJyA/ICcnIDogYmFzZSArICdcXG4gJykgK1xuICAgICAgICAgICAnICcgK1xuICAgICAgICAgICBvdXRwdXQuam9pbignLFxcbiAgJykgK1xuICAgICAgICAgICAnICcgK1xuICAgICAgICAgICBicmFjZXNbMV07XG4gIH1cblxuICByZXR1cm4gYnJhY2VzWzBdICsgYmFzZSArICcgJyArIG91dHB1dC5qb2luKCcsICcpICsgJyAnICsgYnJhY2VzWzFdO1xufVxuXG5mdW5jdGlvbiBpc0FycmF5KGFyKSB7XG4gIHJldHVybiBBcnJheS5pc0FycmF5KGFyKSB8fFxuICAgICAgICAgKHR5cGVvZiBhciA9PT0gJ29iamVjdCcgJiYgb2JqZWN0VG9TdHJpbmcoYXIpID09PSAnW29iamVjdCBBcnJheV0nKTtcbn1cblxuZnVuY3Rpb24gaXNSZWdFeHAocmUpIHtcbiAgcmV0dXJuIHR5cGVvZiByZSA9PT0gJ29iamVjdCcgJiYgb2JqZWN0VG9TdHJpbmcocmUpID09PSAnW29iamVjdCBSZWdFeHBdJztcbn1cblxuZnVuY3Rpb24gaXNEYXRlKGQpIHtcbiAgcmV0dXJuIHR5cGVvZiBkID09PSAnb2JqZWN0JyAmJiBvYmplY3RUb1N0cmluZyhkKSA9PT0gJ1tvYmplY3QgRGF0ZV0nO1xufVxuXG5mdW5jdGlvbiBpc0Vycm9yKGUpIHtcbiAgcmV0dXJuIHR5cGVvZiBlID09PSAnb2JqZWN0JyAmJiBvYmplY3RUb1N0cmluZyhlKSA9PT0gJ1tvYmplY3QgRXJyb3JdJztcbn1cblxuZnVuY3Rpb24gb2JqZWN0VG9TdHJpbmcobykge1xuICByZXR1cm4gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKG8pO1xufVxuIiwiLyohXG4gKiBDaGFpIC0gZmxhZyB1dGlsaXR5XG4gKiBDb3B5cmlnaHQoYykgMjAxMi0yMDE0IEpha2UgTHVlciA8amFrZUBhbG9naWNhbHBhcmFkb3guY29tPlxuICogTUlUIExpY2Vuc2VkXG4gKi9cblxuLyohXG4gKiBNb2R1bGUgZGVwZW5kYW5jaWVzXG4gKi9cblxudmFyIGluc3BlY3QgPSByZXF1aXJlKCcuL2luc3BlY3QnKTtcbnZhciBjb25maWcgPSByZXF1aXJlKCcuLi9jb25maWcnKTtcblxuLyoqXG4gKiAjIyMgLm9iakRpc3BsYXkgKG9iamVjdClcbiAqXG4gKiBEZXRlcm1pbmVzIGlmIGFuIG9iamVjdCBvciBhbiBhcnJheSBtYXRjaGVzXG4gKiBjcml0ZXJpYSB0byBiZSBpbnNwZWN0ZWQgaW4tbGluZSBmb3IgZXJyb3JcbiAqIG1lc3NhZ2VzIG9yIHNob3VsZCBiZSB0cnVuY2F0ZWQuXG4gKlxuICogQHBhcmFtIHtNaXhlZH0gamF2YXNjcmlwdCBvYmplY3QgdG8gaW5zcGVjdFxuICogQG5hbWUgb2JqRGlzcGxheVxuICogQG5hbWVzcGFjZSBVdGlsc1xuICogQGFwaSBwdWJsaWNcbiAqL1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChvYmopIHtcbiAgdmFyIHN0ciA9IGluc3BlY3Qob2JqKVxuICAgICwgdHlwZSA9IE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChvYmopO1xuXG4gIGlmIChjb25maWcudHJ1bmNhdGVUaHJlc2hvbGQgJiYgc3RyLmxlbmd0aCA+PSBjb25maWcudHJ1bmNhdGVUaHJlc2hvbGQpIHtcbiAgICBpZiAodHlwZSA9PT0gJ1tvYmplY3QgRnVuY3Rpb25dJykge1xuICAgICAgcmV0dXJuICFvYmoubmFtZSB8fCBvYmoubmFtZSA9PT0gJydcbiAgICAgICAgPyAnW0Z1bmN0aW9uXSdcbiAgICAgICAgOiAnW0Z1bmN0aW9uOiAnICsgb2JqLm5hbWUgKyAnXSc7XG4gICAgfSBlbHNlIGlmICh0eXBlID09PSAnW29iamVjdCBBcnJheV0nKSB7XG4gICAgICByZXR1cm4gJ1sgQXJyYXkoJyArIG9iai5sZW5ndGggKyAnKSBdJztcbiAgICB9IGVsc2UgaWYgKHR5cGUgPT09ICdbb2JqZWN0IE9iamVjdF0nKSB7XG4gICAgICB2YXIga2V5cyA9IE9iamVjdC5rZXlzKG9iailcbiAgICAgICAgLCBrc3RyID0ga2V5cy5sZW5ndGggPiAyXG4gICAgICAgICAgPyBrZXlzLnNwbGljZSgwLCAyKS5qb2luKCcsICcpICsgJywgLi4uJ1xuICAgICAgICAgIDoga2V5cy5qb2luKCcsICcpO1xuICAgICAgcmV0dXJuICd7IE9iamVjdCAoJyArIGtzdHIgKyAnKSB9JztcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHN0cjtcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIHN0cjtcbiAgfVxufTtcbiIsIi8qIVxuICogQ2hhaSAtIG92ZXJ3cml0ZUNoYWluYWJsZU1ldGhvZCB1dGlsaXR5XG4gKiBDb3B5cmlnaHQoYykgMjAxMi0yMDE0IEpha2UgTHVlciA8amFrZUBhbG9naWNhbHBhcmFkb3guY29tPlxuICogTUlUIExpY2Vuc2VkXG4gKi9cblxuLyoqXG4gKiAjIyMgb3ZlcndyaXRlQ2hhaW5hYmxlTWV0aG9kIChjdHgsIG5hbWUsIG1ldGhvZCwgY2hhaW5pbmdCZWhhdmlvcilcbiAqXG4gKiBPdmVyd2l0ZXMgYW4gYWxyZWFkeSBleGlzdGluZyBjaGFpbmFibGUgbWV0aG9kXG4gKiBhbmQgcHJvdmlkZXMgYWNjZXNzIHRvIHRoZSBwcmV2aW91cyBmdW5jdGlvbiBvclxuICogcHJvcGVydHkuICBNdXN0IHJldHVybiBmdW5jdGlvbnMgdG8gYmUgdXNlZCBmb3JcbiAqIG5hbWUuXG4gKlxuICogICAgIHV0aWxzLm92ZXJ3cml0ZUNoYWluYWJsZU1ldGhvZChjaGFpLkFzc2VydGlvbi5wcm90b3R5cGUsICdsZW5ndGgnLFxuICogICAgICAgZnVuY3Rpb24gKF9zdXBlcikge1xuICogICAgICAgfVxuICogICAgICwgZnVuY3Rpb24gKF9zdXBlcikge1xuICogICAgICAgfVxuICogICAgICk7XG4gKlxuICogQ2FuIGFsc28gYmUgYWNjZXNzZWQgZGlyZWN0bHkgZnJvbSBgY2hhaS5Bc3NlcnRpb25gLlxuICpcbiAqICAgICBjaGFpLkFzc2VydGlvbi5vdmVyd3JpdGVDaGFpbmFibGVNZXRob2QoJ2ZvbycsIGZuLCBmbik7XG4gKlxuICogVGhlbiBjYW4gYmUgdXNlZCBhcyBhbnkgb3RoZXIgYXNzZXJ0aW9uLlxuICpcbiAqICAgICBleHBlY3QobXlGb28pLnRvLmhhdmUubGVuZ3RoKDMpO1xuICogICAgIGV4cGVjdChteUZvbykudG8uaGF2ZS5sZW5ndGguYWJvdmUoMyk7XG4gKlxuICogQHBhcmFtIHtPYmplY3R9IGN0eCBvYmplY3Qgd2hvc2UgbWV0aG9kIC8gcHJvcGVydHkgaXMgdG8gYmUgb3ZlcndyaXR0ZW5cbiAqIEBwYXJhbSB7U3RyaW5nfSBuYW1lIG9mIG1ldGhvZCAvIHByb3BlcnR5IHRvIG92ZXJ3cml0ZVxuICogQHBhcmFtIHtGdW5jdGlvbn0gbWV0aG9kIGZ1bmN0aW9uIHRoYXQgcmV0dXJucyBhIGZ1bmN0aW9uIHRvIGJlIHVzZWQgZm9yIG5hbWVcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGNoYWluaW5nQmVoYXZpb3IgZnVuY3Rpb24gdGhhdCByZXR1cm5zIGEgZnVuY3Rpb24gdG8gYmUgdXNlZCBmb3IgcHJvcGVydHlcbiAqIEBuYW1lc3BhY2UgVXRpbHNcbiAqIEBuYW1lIG92ZXJ3cml0ZUNoYWluYWJsZU1ldGhvZFxuICogQGFwaSBwdWJsaWNcbiAqL1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjdHgsIG5hbWUsIG1ldGhvZCwgY2hhaW5pbmdCZWhhdmlvcikge1xuICB2YXIgY2hhaW5hYmxlQmVoYXZpb3IgPSBjdHguX19tZXRob2RzW25hbWVdO1xuXG4gIHZhciBfY2hhaW5pbmdCZWhhdmlvciA9IGNoYWluYWJsZUJlaGF2aW9yLmNoYWluaW5nQmVoYXZpb3I7XG4gIGNoYWluYWJsZUJlaGF2aW9yLmNoYWluaW5nQmVoYXZpb3IgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIHJlc3VsdCA9IGNoYWluaW5nQmVoYXZpb3IoX2NoYWluaW5nQmVoYXZpb3IpLmNhbGwodGhpcyk7XG4gICAgcmV0dXJuIHJlc3VsdCA9PT0gdW5kZWZpbmVkID8gdGhpcyA6IHJlc3VsdDtcbiAgfTtcblxuICB2YXIgX21ldGhvZCA9IGNoYWluYWJsZUJlaGF2aW9yLm1ldGhvZDtcbiAgY2hhaW5hYmxlQmVoYXZpb3IubWV0aG9kID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciByZXN1bHQgPSBtZXRob2QoX21ldGhvZCkuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICByZXR1cm4gcmVzdWx0ID09PSB1bmRlZmluZWQgPyB0aGlzIDogcmVzdWx0O1xuICB9O1xufTtcbiIsIi8qIVxuICogQ2hhaSAtIG92ZXJ3cml0ZU1ldGhvZCB1dGlsaXR5XG4gKiBDb3B5cmlnaHQoYykgMjAxMi0yMDE0IEpha2UgTHVlciA8amFrZUBhbG9naWNhbHBhcmFkb3guY29tPlxuICogTUlUIExpY2Vuc2VkXG4gKi9cblxuLyoqXG4gKiAjIyMgb3ZlcndyaXRlTWV0aG9kIChjdHgsIG5hbWUsIGZuKVxuICpcbiAqIE92ZXJ3aXRlcyBhbiBhbHJlYWR5IGV4aXN0aW5nIG1ldGhvZCBhbmQgcHJvdmlkZXNcbiAqIGFjY2VzcyB0byBwcmV2aW91cyBmdW5jdGlvbi4gTXVzdCByZXR1cm4gZnVuY3Rpb25cbiAqIHRvIGJlIHVzZWQgZm9yIG5hbWUuXG4gKlxuICogICAgIHV0aWxzLm92ZXJ3cml0ZU1ldGhvZChjaGFpLkFzc2VydGlvbi5wcm90b3R5cGUsICdlcXVhbCcsIGZ1bmN0aW9uIChfc3VwZXIpIHtcbiAqICAgICAgIHJldHVybiBmdW5jdGlvbiAoc3RyKSB7XG4gKiAgICAgICAgIHZhciBvYmogPSB1dGlscy5mbGFnKHRoaXMsICdvYmplY3QnKTtcbiAqICAgICAgICAgaWYgKG9iaiBpbnN0YW5jZW9mIEZvbykge1xuICogICAgICAgICAgIG5ldyBjaGFpLkFzc2VydGlvbihvYmoudmFsdWUpLnRvLmVxdWFsKHN0cik7XG4gKiAgICAgICAgIH0gZWxzZSB7XG4gKiAgICAgICAgICAgX3N1cGVyLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gKiAgICAgICAgIH1cbiAqICAgICAgIH1cbiAqICAgICB9KTtcbiAqXG4gKiBDYW4gYWxzbyBiZSBhY2Nlc3NlZCBkaXJlY3RseSBmcm9tIGBjaGFpLkFzc2VydGlvbmAuXG4gKlxuICogICAgIGNoYWkuQXNzZXJ0aW9uLm92ZXJ3cml0ZU1ldGhvZCgnZm9vJywgZm4pO1xuICpcbiAqIFRoZW4gY2FuIGJlIHVzZWQgYXMgYW55IG90aGVyIGFzc2VydGlvbi5cbiAqXG4gKiAgICAgZXhwZWN0KG15Rm9vKS50by5lcXVhbCgnYmFyJyk7XG4gKlxuICogQHBhcmFtIHtPYmplY3R9IGN0eCBvYmplY3Qgd2hvc2UgbWV0aG9kIGlzIHRvIGJlIG92ZXJ3cml0dGVuXG4gKiBAcGFyYW0ge1N0cmluZ30gbmFtZSBvZiBtZXRob2QgdG8gb3ZlcndyaXRlXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBtZXRob2QgZnVuY3Rpb24gdGhhdCByZXR1cm5zIGEgZnVuY3Rpb24gdG8gYmUgdXNlZCBmb3IgbmFtZVxuICogQG5hbWVzcGFjZSBVdGlsc1xuICogQG5hbWUgb3ZlcndyaXRlTWV0aG9kXG4gKiBAYXBpIHB1YmxpY1xuICovXG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGN0eCwgbmFtZSwgbWV0aG9kKSB7XG4gIHZhciBfbWV0aG9kID0gY3R4W25hbWVdXG4gICAgLCBfc3VwZXIgPSBmdW5jdGlvbiAoKSB7IHJldHVybiB0aGlzOyB9O1xuXG4gIGlmIChfbWV0aG9kICYmICdmdW5jdGlvbicgPT09IHR5cGVvZiBfbWV0aG9kKVxuICAgIF9zdXBlciA9IF9tZXRob2Q7XG5cbiAgY3R4W25hbWVdID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciByZXN1bHQgPSBtZXRob2QoX3N1cGVyKS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIHJldHVybiByZXN1bHQgPT09IHVuZGVmaW5lZCA/IHRoaXMgOiByZXN1bHQ7XG4gIH1cbn07XG4iLCIvKiFcbiAqIENoYWkgLSBvdmVyd3JpdGVQcm9wZXJ0eSB1dGlsaXR5XG4gKiBDb3B5cmlnaHQoYykgMjAxMi0yMDE0IEpha2UgTHVlciA8amFrZUBhbG9naWNhbHBhcmFkb3guY29tPlxuICogTUlUIExpY2Vuc2VkXG4gKi9cblxuLyoqXG4gKiAjIyMgb3ZlcndyaXRlUHJvcGVydHkgKGN0eCwgbmFtZSwgZm4pXG4gKlxuICogT3ZlcndpdGVzIGFuIGFscmVhZHkgZXhpc3RpbmcgcHJvcGVydHkgZ2V0dGVyIGFuZCBwcm92aWRlc1xuICogYWNjZXNzIHRvIHByZXZpb3VzIHZhbHVlLiBNdXN0IHJldHVybiBmdW5jdGlvbiB0byB1c2UgYXMgZ2V0dGVyLlxuICpcbiAqICAgICB1dGlscy5vdmVyd3JpdGVQcm9wZXJ0eShjaGFpLkFzc2VydGlvbi5wcm90b3R5cGUsICdvaycsIGZ1bmN0aW9uIChfc3VwZXIpIHtcbiAqICAgICAgIHJldHVybiBmdW5jdGlvbiAoKSB7XG4gKiAgICAgICAgIHZhciBvYmogPSB1dGlscy5mbGFnKHRoaXMsICdvYmplY3QnKTtcbiAqICAgICAgICAgaWYgKG9iaiBpbnN0YW5jZW9mIEZvbykge1xuICogICAgICAgICAgIG5ldyBjaGFpLkFzc2VydGlvbihvYmoubmFtZSkudG8uZXF1YWwoJ2JhcicpO1xuICogICAgICAgICB9IGVsc2Uge1xuICogICAgICAgICAgIF9zdXBlci5jYWxsKHRoaXMpO1xuICogICAgICAgICB9XG4gKiAgICAgICB9XG4gKiAgICAgfSk7XG4gKlxuICpcbiAqIENhbiBhbHNvIGJlIGFjY2Vzc2VkIGRpcmVjdGx5IGZyb20gYGNoYWkuQXNzZXJ0aW9uYC5cbiAqXG4gKiAgICAgY2hhaS5Bc3NlcnRpb24ub3ZlcndyaXRlUHJvcGVydHkoJ2ZvbycsIGZuKTtcbiAqXG4gKiBUaGVuIGNhbiBiZSB1c2VkIGFzIGFueSBvdGhlciBhc3NlcnRpb24uXG4gKlxuICogICAgIGV4cGVjdChteUZvbykudG8uYmUub2s7XG4gKlxuICogQHBhcmFtIHtPYmplY3R9IGN0eCBvYmplY3Qgd2hvc2UgcHJvcGVydHkgaXMgdG8gYmUgb3ZlcndyaXR0ZW5cbiAqIEBwYXJhbSB7U3RyaW5nfSBuYW1lIG9mIHByb3BlcnR5IHRvIG92ZXJ3cml0ZVxuICogQHBhcmFtIHtGdW5jdGlvbn0gZ2V0dGVyIGZ1bmN0aW9uIHRoYXQgcmV0dXJucyBhIGdldHRlciBmdW5jdGlvbiB0byBiZSB1c2VkIGZvciBuYW1lXG4gKiBAbmFtZXNwYWNlIFV0aWxzXG4gKiBAbmFtZSBvdmVyd3JpdGVQcm9wZXJ0eVxuICogQGFwaSBwdWJsaWNcbiAqL1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjdHgsIG5hbWUsIGdldHRlcikge1xuICB2YXIgX2dldCA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IoY3R4LCBuYW1lKVxuICAgICwgX3N1cGVyID0gZnVuY3Rpb24gKCkge307XG5cbiAgaWYgKF9nZXQgJiYgJ2Z1bmN0aW9uJyA9PT0gdHlwZW9mIF9nZXQuZ2V0KVxuICAgIF9zdXBlciA9IF9nZXQuZ2V0XG5cbiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KGN0eCwgbmFtZSxcbiAgICB7IGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgcmVzdWx0ID0gZ2V0dGVyKF9zdXBlcikuY2FsbCh0aGlzKTtcbiAgICAgICAgcmV0dXJuIHJlc3VsdCA9PT0gdW5kZWZpbmVkID8gdGhpcyA6IHJlc3VsdDtcbiAgICAgIH1cbiAgICAsIGNvbmZpZ3VyYWJsZTogdHJ1ZVxuICB9KTtcbn07XG4iLCIvKiFcbiAqIENoYWkgLSB0ZXN0IHV0aWxpdHlcbiAqIENvcHlyaWdodChjKSAyMDEyLTIwMTQgSmFrZSBMdWVyIDxqYWtlQGFsb2dpY2FscGFyYWRveC5jb20+XG4gKiBNSVQgTGljZW5zZWRcbiAqL1xuXG4vKiFcbiAqIE1vZHVsZSBkZXBlbmRhbmNpZXNcbiAqL1xuXG52YXIgZmxhZyA9IHJlcXVpcmUoJy4vZmxhZycpO1xuXG4vKipcbiAqICMgdGVzdChvYmplY3QsIGV4cHJlc3Npb24pXG4gKlxuICogVGVzdCBhbmQgb2JqZWN0IGZvciBleHByZXNzaW9uLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3QgKGNvbnN0cnVjdGVkIEFzc2VydGlvbilcbiAqIEBwYXJhbSB7QXJndW1lbnRzfSBjaGFpLkFzc2VydGlvbi5wcm90b3R5cGUuYXNzZXJ0IGFyZ3VtZW50c1xuICogQG5hbWVzcGFjZSBVdGlsc1xuICogQG5hbWUgdGVzdFxuICovXG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKG9iaiwgYXJncykge1xuICB2YXIgbmVnYXRlID0gZmxhZyhvYmosICduZWdhdGUnKVxuICAgICwgZXhwciA9IGFyZ3NbMF07XG4gIHJldHVybiBuZWdhdGUgPyAhZXhwciA6IGV4cHI7XG59O1xuIiwiLyohXG4gKiBDaGFpIC0gdHJhbnNmZXJGbGFncyB1dGlsaXR5XG4gKiBDb3B5cmlnaHQoYykgMjAxMi0yMDE0IEpha2UgTHVlciA8amFrZUBhbG9naWNhbHBhcmFkb3guY29tPlxuICogTUlUIExpY2Vuc2VkXG4gKi9cblxuLyoqXG4gKiAjIyMgdHJhbnNmZXJGbGFncyhhc3NlcnRpb24sIG9iamVjdCwgaW5jbHVkZUFsbCA9IHRydWUpXG4gKlxuICogVHJhbnNmZXIgYWxsIHRoZSBmbGFncyBmb3IgYGFzc2VydGlvbmAgdG8gYG9iamVjdGAuIElmXG4gKiBgaW5jbHVkZUFsbGAgaXMgc2V0IHRvIGBmYWxzZWAsIHRoZW4gdGhlIGJhc2UgQ2hhaVxuICogYXNzZXJ0aW9uIGZsYWdzIChuYW1lbHkgYG9iamVjdGAsIGBzc2ZpYCwgYW5kIGBtZXNzYWdlYClcbiAqIHdpbGwgbm90IGJlIHRyYW5zZmVycmVkLlxuICpcbiAqXG4gKiAgICAgdmFyIG5ld0Fzc2VydGlvbiA9IG5ldyBBc3NlcnRpb24oKTtcbiAqICAgICB1dGlscy50cmFuc2ZlckZsYWdzKGFzc2VydGlvbiwgbmV3QXNzZXJ0aW9uKTtcbiAqXG4gKiAgICAgdmFyIGFub3RoZXJBc3Nlcml0b24gPSBuZXcgQXNzZXJ0aW9uKG15T2JqKTtcbiAqICAgICB1dGlscy50cmFuc2ZlckZsYWdzKGFzc2VydGlvbiwgYW5vdGhlckFzc2VydGlvbiwgZmFsc2UpO1xuICpcbiAqIEBwYXJhbSB7QXNzZXJ0aW9ufSBhc3NlcnRpb24gdGhlIGFzc2VydGlvbiB0byB0cmFuc2ZlciB0aGUgZmxhZ3MgZnJvbVxuICogQHBhcmFtIHtPYmplY3R9IG9iamVjdCB0aGUgb2JqZWN0IHRvIHRyYW5zZmVyIHRoZSBmbGFncyB0bzsgdXN1YWxseSBhIG5ldyBhc3NlcnRpb25cbiAqIEBwYXJhbSB7Qm9vbGVhbn0gaW5jbHVkZUFsbFxuICogQG5hbWVzcGFjZSBVdGlsc1xuICogQG5hbWUgdHJhbnNmZXJGbGFnc1xuICogQGFwaSBwcml2YXRlXG4gKi9cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoYXNzZXJ0aW9uLCBvYmplY3QsIGluY2x1ZGVBbGwpIHtcbiAgdmFyIGZsYWdzID0gYXNzZXJ0aW9uLl9fZmxhZ3MgfHwgKGFzc2VydGlvbi5fX2ZsYWdzID0gT2JqZWN0LmNyZWF0ZShudWxsKSk7XG5cbiAgaWYgKCFvYmplY3QuX19mbGFncykge1xuICAgIG9iamVjdC5fX2ZsYWdzID0gT2JqZWN0LmNyZWF0ZShudWxsKTtcbiAgfVxuXG4gIGluY2x1ZGVBbGwgPSBhcmd1bWVudHMubGVuZ3RoID09PSAzID8gaW5jbHVkZUFsbCA6IHRydWU7XG5cbiAgZm9yICh2YXIgZmxhZyBpbiBmbGFncykge1xuICAgIGlmIChpbmNsdWRlQWxsIHx8XG4gICAgICAgIChmbGFnICE9PSAnb2JqZWN0JyAmJiBmbGFnICE9PSAnc3NmaScgJiYgZmxhZyAhPSAnbWVzc2FnZScpKSB7XG4gICAgICBvYmplY3QuX19mbGFnc1tmbGFnXSA9IGZsYWdzW2ZsYWddO1xuICAgIH1cbiAgfVxufTtcbiIsIm1vZHVsZS5leHBvcnRzID0gcmVxdWlyZSgnLi9saWIvZXFsJyk7XG4iLCIvKiFcbiAqIGRlZXAtZXFsXG4gKiBDb3B5cmlnaHQoYykgMjAxMyBKYWtlIEx1ZXIgPGpha2VAYWxvZ2ljYWxwYXJhZG94LmNvbT5cbiAqIE1JVCBMaWNlbnNlZFxuICovXG5cbi8qIVxuICogTW9kdWxlIGRlcGVuZGVuY2llc1xuICovXG5cbnZhciB0eXBlID0gcmVxdWlyZSgndHlwZS1kZXRlY3QnKTtcblxuLyohXG4gKiBCdWZmZXIuaXNCdWZmZXIgYnJvd3NlciBzaGltXG4gKi9cblxudmFyIEJ1ZmZlcjtcbnRyeSB7IEJ1ZmZlciA9IHJlcXVpcmUoJ2J1ZmZlcicpLkJ1ZmZlcjsgfVxuY2F0Y2goZXgpIHtcbiAgQnVmZmVyID0ge307XG4gIEJ1ZmZlci5pc0J1ZmZlciA9IGZ1bmN0aW9uKCkgeyByZXR1cm4gZmFsc2U7IH1cbn1cblxuLyohXG4gKiBQcmltYXJ5IEV4cG9ydFxuICovXG5cbm1vZHVsZS5leHBvcnRzID0gZGVlcEVxdWFsO1xuXG4vKipcbiAqIEFzc2VydCBzdXBlci1zdHJpY3QgKGVnYWwpIGVxdWFsaXR5IGJldHdlZW5cbiAqIHR3byBvYmplY3RzIG9mIGFueSB0eXBlLlxuICpcbiAqIEBwYXJhbSB7TWl4ZWR9IGFcbiAqIEBwYXJhbSB7TWl4ZWR9IGJcbiAqIEBwYXJhbSB7QXJyYXl9IG1lbW9pc2VkIChvcHRpb25hbClcbiAqIEByZXR1cm4ge0Jvb2xlYW59IGVxdWFsIG1hdGNoXG4gKi9cblxuZnVuY3Rpb24gZGVlcEVxdWFsKGEsIGIsIG0pIHtcbiAgaWYgKHNhbWVWYWx1ZShhLCBiKSkge1xuICAgIHJldHVybiB0cnVlO1xuICB9IGVsc2UgaWYgKCdkYXRlJyA9PT0gdHlwZShhKSkge1xuICAgIHJldHVybiBkYXRlRXF1YWwoYSwgYik7XG4gIH0gZWxzZSBpZiAoJ3JlZ2V4cCcgPT09IHR5cGUoYSkpIHtcbiAgICByZXR1cm4gcmVnZXhwRXF1YWwoYSwgYik7XG4gIH0gZWxzZSBpZiAoQnVmZmVyLmlzQnVmZmVyKGEpKSB7XG4gICAgcmV0dXJuIGJ1ZmZlckVxdWFsKGEsIGIpO1xuICB9IGVsc2UgaWYgKCdhcmd1bWVudHMnID09PSB0eXBlKGEpKSB7XG4gICAgcmV0dXJuIGFyZ3VtZW50c0VxdWFsKGEsIGIsIG0pO1xuICB9IGVsc2UgaWYgKCF0eXBlRXF1YWwoYSwgYikpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH0gZWxzZSBpZiAoKCdvYmplY3QnICE9PSB0eXBlKGEpICYmICdvYmplY3QnICE9PSB0eXBlKGIpKVxuICAmJiAoJ2FycmF5JyAhPT0gdHlwZShhKSAmJiAnYXJyYXknICE9PSB0eXBlKGIpKSkge1xuICAgIHJldHVybiBzYW1lVmFsdWUoYSwgYik7XG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIG9iamVjdEVxdWFsKGEsIGIsIG0pO1xuICB9XG59XG5cbi8qIVxuICogU3RyaWN0IChlZ2FsKSBlcXVhbGl0eSB0ZXN0LiBFbnN1cmVzIHRoYXQgTmFOIGFsd2F5c1xuICogZXF1YWxzIE5hTiBhbmQgYC0wYCBkb2VzIG5vdCBlcXVhbCBgKzBgLlxuICpcbiAqIEBwYXJhbSB7TWl4ZWR9IGFcbiAqIEBwYXJhbSB7TWl4ZWR9IGJcbiAqIEByZXR1cm4ge0Jvb2xlYW59IGVxdWFsIG1hdGNoXG4gKi9cblxuZnVuY3Rpb24gc2FtZVZhbHVlKGEsIGIpIHtcbiAgaWYgKGEgPT09IGIpIHJldHVybiBhICE9PSAwIHx8IDEgLyBhID09PSAxIC8gYjtcbiAgcmV0dXJuIGEgIT09IGEgJiYgYiAhPT0gYjtcbn1cblxuLyohXG4gKiBDb21wYXJlIHRoZSB0eXBlcyBvZiB0d28gZ2l2ZW4gb2JqZWN0cyBhbmRcbiAqIHJldHVybiBpZiB0aGV5IGFyZSBlcXVhbC4gTm90ZSB0aGF0IGFuIEFycmF5XG4gKiBoYXMgYSB0eXBlIG9mIGBhcnJheWAgKG5vdCBgb2JqZWN0YCkgYW5kIGFyZ3VtZW50c1xuICogaGF2ZSBhIHR5cGUgb2YgYGFyZ3VtZW50c2AgKG5vdCBgYXJyYXlgL2BvYmplY3RgKS5cbiAqXG4gKiBAcGFyYW0ge01peGVkfSBhXG4gKiBAcGFyYW0ge01peGVkfSBiXG4gKiBAcmV0dXJuIHtCb29sZWFufSByZXN1bHRcbiAqL1xuXG5mdW5jdGlvbiB0eXBlRXF1YWwoYSwgYikge1xuICByZXR1cm4gdHlwZShhKSA9PT0gdHlwZShiKTtcbn1cblxuLyohXG4gKiBDb21wYXJlIHR3byBEYXRlIG9iamVjdHMgYnkgYXNzZXJ0aW5nIHRoYXRcbiAqIHRoZSB0aW1lIHZhbHVlcyBhcmUgZXF1YWwgdXNpbmcgYHNhdmVWYWx1ZWAuXG4gKlxuICogQHBhcmFtIHtEYXRlfSBhXG4gKiBAcGFyYW0ge0RhdGV9IGJcbiAqIEByZXR1cm4ge0Jvb2xlYW59IHJlc3VsdFxuICovXG5cbmZ1bmN0aW9uIGRhdGVFcXVhbChhLCBiKSB7XG4gIGlmICgnZGF0ZScgIT09IHR5cGUoYikpIHJldHVybiBmYWxzZTtcbiAgcmV0dXJuIHNhbWVWYWx1ZShhLmdldFRpbWUoKSwgYi5nZXRUaW1lKCkpO1xufVxuXG4vKiFcbiAqIENvbXBhcmUgdHdvIHJlZ3VsYXIgZXhwcmVzc2lvbnMgYnkgY29udmVydGluZyB0aGVtXG4gKiB0byBzdHJpbmcgYW5kIGNoZWNraW5nIGZvciBgc2FtZVZhbHVlYC5cbiAqXG4gKiBAcGFyYW0ge1JlZ0V4cH0gYVxuICogQHBhcmFtIHtSZWdFeHB9IGJcbiAqIEByZXR1cm4ge0Jvb2xlYW59IHJlc3VsdFxuICovXG5cbmZ1bmN0aW9uIHJlZ2V4cEVxdWFsKGEsIGIpIHtcbiAgaWYgKCdyZWdleHAnICE9PSB0eXBlKGIpKSByZXR1cm4gZmFsc2U7XG4gIHJldHVybiBzYW1lVmFsdWUoYS50b1N0cmluZygpLCBiLnRvU3RyaW5nKCkpO1xufVxuXG4vKiFcbiAqIEFzc2VydCBkZWVwIGVxdWFsaXR5IG9mIHR3byBgYXJndW1lbnRzYCBvYmplY3RzLlxuICogVW5mb3J0dW5hdGVseSwgdGhlc2UgbXVzdCBiZSBzbGljZWQgdG8gYXJyYXlzXG4gKiBwcmlvciB0byB0ZXN0IHRvIGVuc3VyZSBubyBiYWQgYmVoYXZpb3IuXG4gKlxuICogQHBhcmFtIHtBcmd1bWVudHN9IGFcbiAqIEBwYXJhbSB7QXJndW1lbnRzfSBiXG4gKiBAcGFyYW0ge0FycmF5fSBtZW1vaXplIChvcHRpb25hbClcbiAqIEByZXR1cm4ge0Jvb2xlYW59IHJlc3VsdFxuICovXG5cbmZ1bmN0aW9uIGFyZ3VtZW50c0VxdWFsKGEsIGIsIG0pIHtcbiAgaWYgKCdhcmd1bWVudHMnICE9PSB0eXBlKGIpKSByZXR1cm4gZmFsc2U7XG4gIGEgPSBbXS5zbGljZS5jYWxsKGEpO1xuICBiID0gW10uc2xpY2UuY2FsbChiKTtcbiAgcmV0dXJuIGRlZXBFcXVhbChhLCBiLCBtKTtcbn1cblxuLyohXG4gKiBHZXQgZW51bWVyYWJsZSBwcm9wZXJ0aWVzIG9mIGEgZ2l2ZW4gb2JqZWN0LlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBhXG4gKiBAcmV0dXJuIHtBcnJheX0gcHJvcGVydHkgbmFtZXNcbiAqL1xuXG5mdW5jdGlvbiBlbnVtZXJhYmxlKGEpIHtcbiAgdmFyIHJlcyA9IFtdO1xuICBmb3IgKHZhciBrZXkgaW4gYSkgcmVzLnB1c2goa2V5KTtcbiAgcmV0dXJuIHJlcztcbn1cblxuLyohXG4gKiBTaW1wbGUgZXF1YWxpdHkgZm9yIGZsYXQgaXRlcmFibGUgb2JqZWN0c1xuICogc3VjaCBhcyBBcnJheXMgb3IgTm9kZS5qcyBidWZmZXJzLlxuICpcbiAqIEBwYXJhbSB7SXRlcmFibGV9IGFcbiAqIEBwYXJhbSB7SXRlcmFibGV9IGJcbiAqIEByZXR1cm4ge0Jvb2xlYW59IHJlc3VsdFxuICovXG5cbmZ1bmN0aW9uIGl0ZXJhYmxlRXF1YWwoYSwgYikge1xuICBpZiAoYS5sZW5ndGggIT09ICBiLmxlbmd0aCkgcmV0dXJuIGZhbHNlO1xuXG4gIHZhciBpID0gMDtcbiAgdmFyIG1hdGNoID0gdHJ1ZTtcblxuICBmb3IgKDsgaSA8IGEubGVuZ3RoOyBpKyspIHtcbiAgICBpZiAoYVtpXSAhPT0gYltpXSkge1xuICAgICAgbWF0Y2ggPSBmYWxzZTtcbiAgICAgIGJyZWFrO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBtYXRjaDtcbn1cblxuLyohXG4gKiBFeHRlbnNpb24gdG8gYGl0ZXJhYmxlRXF1YWxgIHNwZWNpZmljYWxseVxuICogZm9yIE5vZGUuanMgQnVmZmVycy5cbiAqXG4gKiBAcGFyYW0ge0J1ZmZlcn0gYVxuICogQHBhcmFtIHtNaXhlZH0gYlxuICogQHJldHVybiB7Qm9vbGVhbn0gcmVzdWx0XG4gKi9cblxuZnVuY3Rpb24gYnVmZmVyRXF1YWwoYSwgYikge1xuICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihiKSkgcmV0dXJuIGZhbHNlO1xuICByZXR1cm4gaXRlcmFibGVFcXVhbChhLCBiKTtcbn1cblxuLyohXG4gKiBCbG9jayBmb3IgYG9iamVjdEVxdWFsYCBlbnN1cmluZyBub24tZXhpc3RpbmdcbiAqIHZhbHVlcyBkb24ndCBnZXQgaW4uXG4gKlxuICogQHBhcmFtIHtNaXhlZH0gb2JqZWN0XG4gKiBAcmV0dXJuIHtCb29sZWFufSByZXN1bHRcbiAqL1xuXG5mdW5jdGlvbiBpc1ZhbHVlKGEpIHtcbiAgcmV0dXJuIGEgIT09IG51bGwgJiYgYSAhPT0gdW5kZWZpbmVkO1xufVxuXG4vKiFcbiAqIFJlY3Vyc2l2ZWx5IGNoZWNrIHRoZSBlcXVhbGl0eSBvZiB0d28gb2JqZWN0cy5cbiAqIE9uY2UgYmFzaWMgc2FtZW5lc3MgaGFzIGJlZW4gZXN0YWJsaXNoZWQgaXQgd2lsbFxuICogZGVmZXIgdG8gYGRlZXBFcXVhbGAgZm9yIGVhY2ggZW51bWVyYWJsZSBrZXlcbiAqIGluIHRoZSBvYmplY3QuXG4gKlxuICogQHBhcmFtIHtNaXhlZH0gYVxuICogQHBhcmFtIHtNaXhlZH0gYlxuICogQHJldHVybiB7Qm9vbGVhbn0gcmVzdWx0XG4gKi9cblxuZnVuY3Rpb24gb2JqZWN0RXF1YWwoYSwgYiwgbSkge1xuICBpZiAoIWlzVmFsdWUoYSkgfHwgIWlzVmFsdWUoYikpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBpZiAoYS5wcm90b3R5cGUgIT09IGIucHJvdG90eXBlKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgdmFyIGk7XG4gIGlmIChtKSB7XG4gICAgZm9yIChpID0gMDsgaSA8IG0ubGVuZ3RoOyBpKyspIHtcbiAgICAgIGlmICgobVtpXVswXSA9PT0gYSAmJiBtW2ldWzFdID09PSBiKVxuICAgICAgfHwgIChtW2ldWzBdID09PSBiICYmIG1baV1bMV0gPT09IGEpKSB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuICAgIH1cbiAgfSBlbHNlIHtcbiAgICBtID0gW107XG4gIH1cblxuICB0cnkge1xuICAgIHZhciBrYSA9IGVudW1lcmFibGUoYSk7XG4gICAgdmFyIGtiID0gZW51bWVyYWJsZShiKTtcbiAgfSBjYXRjaCAoZXgpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBrYS5zb3J0KCk7XG4gIGtiLnNvcnQoKTtcblxuICBpZiAoIWl0ZXJhYmxlRXF1YWwoa2EsIGtiKSkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIG0ucHVzaChbIGEsIGIgXSk7XG5cbiAgdmFyIGtleTtcbiAgZm9yIChpID0ga2EubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0pIHtcbiAgICBrZXkgPSBrYVtpXTtcbiAgICBpZiAoIWRlZXBFcXVhbChhW2tleV0sIGJba2V5XSwgbSkpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gdHJ1ZTtcbn1cbiIsIm1vZHVsZS5leHBvcnRzID0gcmVxdWlyZSgnLi9saWIvdHlwZScpO1xuIiwiLyohXG4gKiB0eXBlLWRldGVjdFxuICogQ29weXJpZ2h0KGMpIDIwMTMgamFrZSBsdWVyIDxqYWtlQGFsb2dpY2FscGFyYWRveC5jb20+XG4gKiBNSVQgTGljZW5zZWRcbiAqL1xuXG4vKiFcbiAqIFByaW1hcnkgRXhwb3J0c1xuICovXG5cbnZhciBleHBvcnRzID0gbW9kdWxlLmV4cG9ydHMgPSBnZXRUeXBlO1xuXG4vKiFcbiAqIERldGVjdGFibGUgamF2YXNjcmlwdCBuYXRpdmVzXG4gKi9cblxudmFyIG5hdGl2ZXMgPSB7XG4gICAgJ1tvYmplY3QgQXJyYXldJzogJ2FycmF5J1xuICAsICdbb2JqZWN0IFJlZ0V4cF0nOiAncmVnZXhwJ1xuICAsICdbb2JqZWN0IEZ1bmN0aW9uXSc6ICdmdW5jdGlvbidcbiAgLCAnW29iamVjdCBBcmd1bWVudHNdJzogJ2FyZ3VtZW50cydcbiAgLCAnW29iamVjdCBEYXRlXSc6ICdkYXRlJ1xufTtcblxuLyoqXG4gKiAjIyMgdHlwZU9mIChvYmopXG4gKlxuICogVXNlIHNldmVyYWwgZGlmZmVyZW50IHRlY2huaXF1ZXMgdG8gZGV0ZXJtaW5lXG4gKiB0aGUgdHlwZSBvZiBvYmplY3QgYmVpbmcgdGVzdGVkLlxuICpcbiAqXG4gKiBAcGFyYW0ge01peGVkfSBvYmplY3RcbiAqIEByZXR1cm4ge1N0cmluZ30gb2JqZWN0IHR5cGVcbiAqIEBhcGkgcHVibGljXG4gKi9cblxuZnVuY3Rpb24gZ2V0VHlwZSAob2JqKSB7XG4gIHZhciBzdHIgPSBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwob2JqKTtcbiAgaWYgKG5hdGl2ZXNbc3RyXSkgcmV0dXJuIG5hdGl2ZXNbc3RyXTtcbiAgaWYgKG9iaiA9PT0gbnVsbCkgcmV0dXJuICdudWxsJztcbiAgaWYgKG9iaiA9PT0gdW5kZWZpbmVkKSByZXR1cm4gJ3VuZGVmaW5lZCc7XG4gIGlmIChvYmogPT09IE9iamVjdChvYmopKSByZXR1cm4gJ29iamVjdCc7XG4gIHJldHVybiB0eXBlb2Ygb2JqO1xufVxuXG5leHBvcnRzLkxpYnJhcnkgPSBMaWJyYXJ5O1xuXG4vKipcbiAqICMjIyBMaWJyYXJ5XG4gKlxuICogQ3JlYXRlIGEgcmVwb3NpdG9yeSBmb3IgY3VzdG9tIHR5cGUgZGV0ZWN0aW9uLlxuICpcbiAqIGBgYGpzXG4gKiB2YXIgbGliID0gbmV3IHR5cGUuTGlicmFyeTtcbiAqIGBgYFxuICpcbiAqL1xuXG5mdW5jdGlvbiBMaWJyYXJ5ICgpIHtcbiAgdGhpcy50ZXN0cyA9IHt9O1xufVxuXG4vKipcbiAqICMjIyMgLm9mIChvYmopXG4gKlxuICogRXhwb3NlIHJlcGxhY2VtZW50IGB0eXBlb2ZgIGRldGVjdGlvbiB0byB0aGUgbGlicmFyeS5cbiAqXG4gKiBgYGBqc1xuICogaWYgKCdzdHJpbmcnID09PSBsaWIub2YoJ2hlbGxvIHdvcmxkJykpIHtcbiAqICAgLy8gLi4uXG4gKiB9XG4gKiBgYGBcbiAqXG4gKiBAcGFyYW0ge01peGVkfSBvYmplY3QgdG8gdGVzdFxuICogQHJldHVybiB7U3RyaW5nfSB0eXBlXG4gKi9cblxuTGlicmFyeS5wcm90b3R5cGUub2YgPSBnZXRUeXBlO1xuXG4vKipcbiAqICMjIyMgLmRlZmluZSAodHlwZSwgdGVzdClcbiAqXG4gKiBBZGQgYSB0ZXN0IHRvIGZvciB0aGUgYC50ZXN0KClgIGFzc2VydGlvbi5cbiAqXG4gKiBDYW4gYmUgZGVmaW5lZCBhcyBhIHJlZ3VsYXIgZXhwcmVzc2lvbjpcbiAqXG4gKiBgYGBqc1xuICogbGliLmRlZmluZSgnaW50JywgL15bMC05XSskLyk7XG4gKiBgYGBcbiAqXG4gKiAuLi4gb3IgYXMgYSBmdW5jdGlvbjpcbiAqXG4gKiBgYGBqc1xuICogbGliLmRlZmluZSgnYmxuJywgZnVuY3Rpb24gKG9iaikge1xuICogICBpZiAoJ2Jvb2xlYW4nID09PSBsaWIub2Yob2JqKSkgcmV0dXJuIHRydWU7XG4gKiAgIHZhciBibG5zID0gWyAneWVzJywgJ25vJywgJ3RydWUnLCAnZmFsc2UnLCAxLCAwIF07XG4gKiAgIGlmICgnc3RyaW5nJyA9PT0gbGliLm9mKG9iaikpIG9iaiA9IG9iai50b0xvd2VyQ2FzZSgpO1xuICogICByZXR1cm4gISEgfmJsbnMuaW5kZXhPZihvYmopO1xuICogfSk7XG4gKiBgYGBcbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gdHlwZVxuICogQHBhcmFtIHtSZWdFeHB8RnVuY3Rpb259IHRlc3RcbiAqIEBhcGkgcHVibGljXG4gKi9cblxuTGlicmFyeS5wcm90b3R5cGUuZGVmaW5lID0gZnVuY3Rpb24gKHR5cGUsIHRlc3QpIHtcbiAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPT09IDEpIHJldHVybiB0aGlzLnRlc3RzW3R5cGVdO1xuICB0aGlzLnRlc3RzW3R5cGVdID0gdGVzdDtcbiAgcmV0dXJuIHRoaXM7XG59O1xuXG4vKipcbiAqICMjIyMgLnRlc3QgKG9iaiwgdGVzdClcbiAqXG4gKiBBc3NlcnQgdGhhdCBhbiBvYmplY3QgaXMgb2YgdHlwZS4gV2lsbCBmaXJzdFxuICogY2hlY2sgbmF0aXZlcywgYW5kIGlmIHRoYXQgZG9lcyBub3QgcGFzcyBpdCB3aWxsXG4gKiB1c2UgdGhlIHVzZXIgZGVmaW5lZCBjdXN0b20gdGVzdHMuXG4gKlxuICogYGBganNcbiAqIGFzc2VydChsaWIudGVzdCgnMScsICdpbnQnKSk7XG4gKiBhc3NlcnQobGliLnRlc3QoJ3llcycsICdibG4nKSk7XG4gKiBgYGBcbiAqXG4gKiBAcGFyYW0ge01peGVkfSBvYmplY3RcbiAqIEBwYXJhbSB7U3RyaW5nfSB0eXBlXG4gKiBAcmV0dXJuIHtCb29sZWFufSByZXN1bHRcbiAqIEBhcGkgcHVibGljXG4gKi9cblxuTGlicmFyeS5wcm90b3R5cGUudGVzdCA9IGZ1bmN0aW9uIChvYmosIHR5cGUpIHtcbiAgaWYgKHR5cGUgPT09IGdldFR5cGUob2JqKSkgcmV0dXJuIHRydWU7XG4gIHZhciB0ZXN0ID0gdGhpcy50ZXN0c1t0eXBlXTtcblxuICBpZiAodGVzdCAmJiAncmVnZXhwJyA9PT0gZ2V0VHlwZSh0ZXN0KSkge1xuICAgIHJldHVybiB0ZXN0LnRlc3Qob2JqKTtcbiAgfSBlbHNlIGlmICh0ZXN0ICYmICdmdW5jdGlvbicgPT09IGdldFR5cGUodGVzdCkpIHtcbiAgICByZXR1cm4gdGVzdChvYmopO1xuICB9IGVsc2Uge1xuICAgIHRocm93IG5ldyBSZWZlcmVuY2VFcnJvcignVHlwZSB0ZXN0IFwiJyArIHR5cGUgKyAnXCIgbm90IGRlZmluZWQgb3IgaW52YWxpZC4nKTtcbiAgfVxufTtcbiIsImV4cG9ydHMucmVhZCA9IGZ1bmN0aW9uIChidWZmZXIsIG9mZnNldCwgaXNMRSwgbUxlbiwgbkJ5dGVzKSB7XG4gIHZhciBlLCBtXG4gIHZhciBlTGVuID0gbkJ5dGVzICogOCAtIG1MZW4gLSAxXG4gIHZhciBlTWF4ID0gKDEgPDwgZUxlbikgLSAxXG4gIHZhciBlQmlhcyA9IGVNYXggPj4gMVxuICB2YXIgbkJpdHMgPSAtN1xuICB2YXIgaSA9IGlzTEUgPyAobkJ5dGVzIC0gMSkgOiAwXG4gIHZhciBkID0gaXNMRSA/IC0xIDogMVxuICB2YXIgcyA9IGJ1ZmZlcltvZmZzZXQgKyBpXVxuXG4gIGkgKz0gZFxuXG4gIGUgPSBzICYgKCgxIDw8ICgtbkJpdHMpKSAtIDEpXG4gIHMgPj49ICgtbkJpdHMpXG4gIG5CaXRzICs9IGVMZW5cbiAgZm9yICg7IG5CaXRzID4gMDsgZSA9IGUgKiAyNTYgKyBidWZmZXJbb2Zmc2V0ICsgaV0sIGkgKz0gZCwgbkJpdHMgLT0gOCkge31cblxuICBtID0gZSAmICgoMSA8PCAoLW5CaXRzKSkgLSAxKVxuICBlID4+PSAoLW5CaXRzKVxuICBuQml0cyArPSBtTGVuXG4gIGZvciAoOyBuQml0cyA+IDA7IG0gPSBtICogMjU2ICsgYnVmZmVyW29mZnNldCArIGldLCBpICs9IGQsIG5CaXRzIC09IDgpIHt9XG5cbiAgaWYgKGUgPT09IDApIHtcbiAgICBlID0gMSAtIGVCaWFzXG4gIH0gZWxzZSBpZiAoZSA9PT0gZU1heCkge1xuICAgIHJldHVybiBtID8gTmFOIDogKChzID8gLTEgOiAxKSAqIEluZmluaXR5KVxuICB9IGVsc2Uge1xuICAgIG0gPSBtICsgTWF0aC5wb3coMiwgbUxlbilcbiAgICBlID0gZSAtIGVCaWFzXG4gIH1cbiAgcmV0dXJuIChzID8gLTEgOiAxKSAqIG0gKiBNYXRoLnBvdygyLCBlIC0gbUxlbilcbn1cblxuZXhwb3J0cy53cml0ZSA9IGZ1bmN0aW9uIChidWZmZXIsIHZhbHVlLCBvZmZzZXQsIGlzTEUsIG1MZW4sIG5CeXRlcykge1xuICB2YXIgZSwgbSwgY1xuICB2YXIgZUxlbiA9IG5CeXRlcyAqIDggLSBtTGVuIC0gMVxuICB2YXIgZU1heCA9ICgxIDw8IGVMZW4pIC0gMVxuICB2YXIgZUJpYXMgPSBlTWF4ID4+IDFcbiAgdmFyIHJ0ID0gKG1MZW4gPT09IDIzID8gTWF0aC5wb3coMiwgLTI0KSAtIE1hdGgucG93KDIsIC03NykgOiAwKVxuICB2YXIgaSA9IGlzTEUgPyAwIDogKG5CeXRlcyAtIDEpXG4gIHZhciBkID0gaXNMRSA/IDEgOiAtMVxuICB2YXIgcyA9IHZhbHVlIDwgMCB8fCAodmFsdWUgPT09IDAgJiYgMSAvIHZhbHVlIDwgMCkgPyAxIDogMFxuXG4gIHZhbHVlID0gTWF0aC5hYnModmFsdWUpXG5cbiAgaWYgKGlzTmFOKHZhbHVlKSB8fCB2YWx1ZSA9PT0gSW5maW5pdHkpIHtcbiAgICBtID0gaXNOYU4odmFsdWUpID8gMSA6IDBcbiAgICBlID0gZU1heFxuICB9IGVsc2Uge1xuICAgIGUgPSBNYXRoLmZsb29yKE1hdGgubG9nKHZhbHVlKSAvIE1hdGguTE4yKVxuICAgIGlmICh2YWx1ZSAqIChjID0gTWF0aC5wb3coMiwgLWUpKSA8IDEpIHtcbiAgICAgIGUtLVxuICAgICAgYyAqPSAyXG4gICAgfVxuICAgIGlmIChlICsgZUJpYXMgPj0gMSkge1xuICAgICAgdmFsdWUgKz0gcnQgLyBjXG4gICAgfSBlbHNlIHtcbiAgICAgIHZhbHVlICs9IHJ0ICogTWF0aC5wb3coMiwgMSAtIGVCaWFzKVxuICAgIH1cbiAgICBpZiAodmFsdWUgKiBjID49IDIpIHtcbiAgICAgIGUrK1xuICAgICAgYyAvPSAyXG4gICAgfVxuXG4gICAgaWYgKGUgKyBlQmlhcyA+PSBlTWF4KSB7XG4gICAgICBtID0gMFxuICAgICAgZSA9IGVNYXhcbiAgICB9IGVsc2UgaWYgKGUgKyBlQmlhcyA+PSAxKSB7XG4gICAgICBtID0gKHZhbHVlICogYyAtIDEpICogTWF0aC5wb3coMiwgbUxlbilcbiAgICAgIGUgPSBlICsgZUJpYXNcbiAgICB9IGVsc2Uge1xuICAgICAgbSA9IHZhbHVlICogTWF0aC5wb3coMiwgZUJpYXMgLSAxKSAqIE1hdGgucG93KDIsIG1MZW4pXG4gICAgICBlID0gMFxuICAgIH1cbiAgfVxuXG4gIGZvciAoOyBtTGVuID49IDg7IGJ1ZmZlcltvZmZzZXQgKyBpXSA9IG0gJiAweGZmLCBpICs9IGQsIG0gLz0gMjU2LCBtTGVuIC09IDgpIHt9XG5cbiAgZSA9IChlIDw8IG1MZW4pIHwgbVxuICBlTGVuICs9IG1MZW5cbiAgZm9yICg7IGVMZW4gPiAwOyBidWZmZXJbb2Zmc2V0ICsgaV0gPSBlICYgMHhmZiwgaSArPSBkLCBlIC89IDI1NiwgZUxlbiAtPSA4KSB7fVxuXG4gIGJ1ZmZlcltvZmZzZXQgKyBpIC0gZF0gfD0gcyAqIDEyOFxufVxuIiwidmFyIHRvU3RyaW5nID0ge30udG9TdHJpbmc7XG5cbm1vZHVsZS5leHBvcnRzID0gQXJyYXkuaXNBcnJheSB8fCBmdW5jdGlvbiAoYXJyKSB7XG4gIHJldHVybiB0b1N0cmluZy5jYWxsKGFycikgPT0gJ1tvYmplY3QgQXJyYXldJztcbn07XG4iLCIvKiFcbiAqIHR5cGUtZGV0ZWN0XG4gKiBDb3B5cmlnaHQoYykgMjAxMyBqYWtlIGx1ZXIgPGpha2VAYWxvZ2ljYWxwYXJhZG94LmNvbT5cbiAqIE1JVCBMaWNlbnNlZFxuICovXG5cbi8qIVxuICogUHJpbWFyeSBFeHBvcnRzXG4gKi9cblxudmFyIGV4cG9ydHMgPSBtb2R1bGUuZXhwb3J0cyA9IGdldFR5cGU7XG5cbi8qKlxuICogIyMjIHR5cGVPZiAob2JqKVxuICpcbiAqIFVzZSBzZXZlcmFsIGRpZmZlcmVudCB0ZWNobmlxdWVzIHRvIGRldGVybWluZVxuICogdGhlIHR5cGUgb2Ygb2JqZWN0IGJlaW5nIHRlc3RlZC5cbiAqXG4gKlxuICogQHBhcmFtIHtNaXhlZH0gb2JqZWN0XG4gKiBAcmV0dXJuIHtTdHJpbmd9IG9iamVjdCB0eXBlXG4gKiBAYXBpIHB1YmxpY1xuICovXG52YXIgb2JqZWN0VHlwZVJlZ2V4cCA9IC9eXFxbb2JqZWN0ICguKilcXF0kLztcblxuZnVuY3Rpb24gZ2V0VHlwZShvYmopIHtcbiAgdmFyIHR5cGUgPSBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwob2JqKS5tYXRjaChvYmplY3RUeXBlUmVnZXhwKVsxXS50b0xvd2VyQ2FzZSgpO1xuICAvLyBMZXQgXCJuZXcgU3RyaW5nKCcnKVwiIHJldHVybiAnb2JqZWN0J1xuICBpZiAodHlwZW9mIFByb21pc2UgPT09ICdmdW5jdGlvbicgJiYgb2JqIGluc3RhbmNlb2YgUHJvbWlzZSkgcmV0dXJuICdwcm9taXNlJztcbiAgLy8gUGhhbnRvbUpTIGhhcyB0eXBlIFwiRE9NV2luZG93XCIgZm9yIG51bGxcbiAgaWYgKG9iaiA9PT0gbnVsbCkgcmV0dXJuICdudWxsJztcbiAgLy8gUGhhbnRvbUpTIGhhcyB0eXBlIFwiRE9NV2luZG93XCIgZm9yIHVuZGVmaW5lZFxuICBpZiAob2JqID09PSB1bmRlZmluZWQpIHJldHVybiAndW5kZWZpbmVkJztcbiAgcmV0dXJuIHR5cGU7XG59XG5cbmV4cG9ydHMuTGlicmFyeSA9IExpYnJhcnk7XG5cbi8qKlxuICogIyMjIExpYnJhcnlcbiAqXG4gKiBDcmVhdGUgYSByZXBvc2l0b3J5IGZvciBjdXN0b20gdHlwZSBkZXRlY3Rpb24uXG4gKlxuICogYGBganNcbiAqIHZhciBsaWIgPSBuZXcgdHlwZS5MaWJyYXJ5O1xuICogYGBgXG4gKlxuICovXG5cbmZ1bmN0aW9uIExpYnJhcnkoKSB7XG4gIGlmICghKHRoaXMgaW5zdGFuY2VvZiBMaWJyYXJ5KSkgcmV0dXJuIG5ldyBMaWJyYXJ5KCk7XG4gIHRoaXMudGVzdHMgPSB7fTtcbn1cblxuLyoqXG4gKiAjIyMjIC5vZiAob2JqKVxuICpcbiAqIEV4cG9zZSByZXBsYWNlbWVudCBgdHlwZW9mYCBkZXRlY3Rpb24gdG8gdGhlIGxpYnJhcnkuXG4gKlxuICogYGBganNcbiAqIGlmICgnc3RyaW5nJyA9PT0gbGliLm9mKCdoZWxsbyB3b3JsZCcpKSB7XG4gKiAgIC8vIC4uLlxuICogfVxuICogYGBgXG4gKlxuICogQHBhcmFtIHtNaXhlZH0gb2JqZWN0IHRvIHRlc3RcbiAqIEByZXR1cm4ge1N0cmluZ30gdHlwZVxuICovXG5cbkxpYnJhcnkucHJvdG90eXBlLm9mID0gZ2V0VHlwZTtcblxuLyoqXG4gKiAjIyMjIC5kZWZpbmUgKHR5cGUsIHRlc3QpXG4gKlxuICogQWRkIGEgdGVzdCB0byBmb3IgdGhlIGAudGVzdCgpYCBhc3NlcnRpb24uXG4gKlxuICogQ2FuIGJlIGRlZmluZWQgYXMgYSByZWd1bGFyIGV4cHJlc3Npb246XG4gKlxuICogYGBganNcbiAqIGxpYi5kZWZpbmUoJ2ludCcsIC9eWzAtOV0rJC8pO1xuICogYGBgXG4gKlxuICogLi4uIG9yIGFzIGEgZnVuY3Rpb246XG4gKlxuICogYGBganNcbiAqIGxpYi5kZWZpbmUoJ2JsbicsIGZ1bmN0aW9uIChvYmopIHtcbiAqICAgaWYgKCdib29sZWFuJyA9PT0gbGliLm9mKG9iaikpIHJldHVybiB0cnVlO1xuICogICB2YXIgYmxucyA9IFsgJ3llcycsICdubycsICd0cnVlJywgJ2ZhbHNlJywgMSwgMCBdO1xuICogICBpZiAoJ3N0cmluZycgPT09IGxpYi5vZihvYmopKSBvYmogPSBvYmoudG9Mb3dlckNhc2UoKTtcbiAqICAgcmV0dXJuICEhIH5ibG5zLmluZGV4T2Yob2JqKTtcbiAqIH0pO1xuICogYGBgXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IHR5cGVcbiAqIEBwYXJhbSB7UmVnRXhwfEZ1bmN0aW9ufSB0ZXN0XG4gKiBAYXBpIHB1YmxpY1xuICovXG5cbkxpYnJhcnkucHJvdG90eXBlLmRlZmluZSA9IGZ1bmN0aW9uKHR5cGUsIHRlc3QpIHtcbiAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPT09IDEpIHJldHVybiB0aGlzLnRlc3RzW3R5cGVdO1xuICB0aGlzLnRlc3RzW3R5cGVdID0gdGVzdDtcbiAgcmV0dXJuIHRoaXM7XG59O1xuXG4vKipcbiAqICMjIyMgLnRlc3QgKG9iaiwgdGVzdClcbiAqXG4gKiBBc3NlcnQgdGhhdCBhbiBvYmplY3QgaXMgb2YgdHlwZS4gV2lsbCBmaXJzdFxuICogY2hlY2sgbmF0aXZlcywgYW5kIGlmIHRoYXQgZG9lcyBub3QgcGFzcyBpdCB3aWxsXG4gKiB1c2UgdGhlIHVzZXIgZGVmaW5lZCBjdXN0b20gdGVzdHMuXG4gKlxuICogYGBganNcbiAqIGFzc2VydChsaWIudGVzdCgnMScsICdpbnQnKSk7XG4gKiBhc3NlcnQobGliLnRlc3QoJ3llcycsICdibG4nKSk7XG4gKiBgYGBcbiAqXG4gKiBAcGFyYW0ge01peGVkfSBvYmplY3RcbiAqIEBwYXJhbSB7U3RyaW5nfSB0eXBlXG4gKiBAcmV0dXJuIHtCb29sZWFufSByZXN1bHRcbiAqIEBhcGkgcHVibGljXG4gKi9cblxuTGlicmFyeS5wcm90b3R5cGUudGVzdCA9IGZ1bmN0aW9uKG9iaiwgdHlwZSkge1xuICBpZiAodHlwZSA9PT0gZ2V0VHlwZShvYmopKSByZXR1cm4gdHJ1ZTtcbiAgdmFyIHRlc3QgPSB0aGlzLnRlc3RzW3R5cGVdO1xuXG4gIGlmICh0ZXN0ICYmICdyZWdleHAnID09PSBnZXRUeXBlKHRlc3QpKSB7XG4gICAgcmV0dXJuIHRlc3QudGVzdChvYmopO1xuICB9IGVsc2UgaWYgKHRlc3QgJiYgJ2Z1bmN0aW9uJyA9PT0gZ2V0VHlwZSh0ZXN0KSkge1xuICAgIHJldHVybiB0ZXN0KG9iaik7XG4gIH0gZWxzZSB7XG4gICAgdGhyb3cgbmV3IFJlZmVyZW5jZUVycm9yKCdUeXBlIHRlc3QgXCInICsgdHlwZSArICdcIiBub3QgZGVmaW5lZCBvciBpbnZhbGlkLicpO1xuICB9XG59O1xuIiwiLy8gICAgIFVuZGVyc2NvcmUuanMgMS44LjNcbi8vICAgICBodHRwOi8vdW5kZXJzY29yZWpzLm9yZ1xuLy8gICAgIChjKSAyMDA5LTIwMTUgSmVyZW15IEFzaGtlbmFzLCBEb2N1bWVudENsb3VkIGFuZCBJbnZlc3RpZ2F0aXZlIFJlcG9ydGVycyAmIEVkaXRvcnNcbi8vICAgICBVbmRlcnNjb3JlIG1heSBiZSBmcmVlbHkgZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuXG4oZnVuY3Rpb24oKSB7XG5cbiAgLy8gQmFzZWxpbmUgc2V0dXBcbiAgLy8gLS0tLS0tLS0tLS0tLS1cblxuICAvLyBFc3RhYmxpc2ggdGhlIHJvb3Qgb2JqZWN0LCBgd2luZG93YCBpbiB0aGUgYnJvd3Nlciwgb3IgYGV4cG9ydHNgIG9uIHRoZSBzZXJ2ZXIuXG4gIHZhciByb290ID0gdGhpcztcblxuICAvLyBTYXZlIHRoZSBwcmV2aW91cyB2YWx1ZSBvZiB0aGUgYF9gIHZhcmlhYmxlLlxuICB2YXIgcHJldmlvdXNVbmRlcnNjb3JlID0gcm9vdC5fO1xuXG4gIC8vIFNhdmUgYnl0ZXMgaW4gdGhlIG1pbmlmaWVkIChidXQgbm90IGd6aXBwZWQpIHZlcnNpb246XG4gIHZhciBBcnJheVByb3RvID0gQXJyYXkucHJvdG90eXBlLCBPYmpQcm90byA9IE9iamVjdC5wcm90b3R5cGUsIEZ1bmNQcm90byA9IEZ1bmN0aW9uLnByb3RvdHlwZTtcblxuICAvLyBDcmVhdGUgcXVpY2sgcmVmZXJlbmNlIHZhcmlhYmxlcyBmb3Igc3BlZWQgYWNjZXNzIHRvIGNvcmUgcHJvdG90eXBlcy5cbiAgdmFyXG4gICAgcHVzaCAgICAgICAgICAgICA9IEFycmF5UHJvdG8ucHVzaCxcbiAgICBzbGljZSAgICAgICAgICAgID0gQXJyYXlQcm90by5zbGljZSxcbiAgICB0b1N0cmluZyAgICAgICAgID0gT2JqUHJvdG8udG9TdHJpbmcsXG4gICAgaGFzT3duUHJvcGVydHkgICA9IE9ialByb3RvLmhhc093blByb3BlcnR5O1xuXG4gIC8vIEFsbCAqKkVDTUFTY3JpcHQgNSoqIG5hdGl2ZSBmdW5jdGlvbiBpbXBsZW1lbnRhdGlvbnMgdGhhdCB3ZSBob3BlIHRvIHVzZVxuICAvLyBhcmUgZGVjbGFyZWQgaGVyZS5cbiAgdmFyXG4gICAgbmF0aXZlSXNBcnJheSAgICAgID0gQXJyYXkuaXNBcnJheSxcbiAgICBuYXRpdmVLZXlzICAgICAgICAgPSBPYmplY3Qua2V5cyxcbiAgICBuYXRpdmVCaW5kICAgICAgICAgPSBGdW5jUHJvdG8uYmluZCxcbiAgICBuYXRpdmVDcmVhdGUgICAgICAgPSBPYmplY3QuY3JlYXRlO1xuXG4gIC8vIE5ha2VkIGZ1bmN0aW9uIHJlZmVyZW5jZSBmb3Igc3Vycm9nYXRlLXByb3RvdHlwZS1zd2FwcGluZy5cbiAgdmFyIEN0b3IgPSBmdW5jdGlvbigpe307XG5cbiAgLy8gQ3JlYXRlIGEgc2FmZSByZWZlcmVuY2UgdG8gdGhlIFVuZGVyc2NvcmUgb2JqZWN0IGZvciB1c2UgYmVsb3cuXG4gIHZhciBfID0gZnVuY3Rpb24ob2JqKSB7XG4gICAgaWYgKG9iaiBpbnN0YW5jZW9mIF8pIHJldHVybiBvYmo7XG4gICAgaWYgKCEodGhpcyBpbnN0YW5jZW9mIF8pKSByZXR1cm4gbmV3IF8ob2JqKTtcbiAgICB0aGlzLl93cmFwcGVkID0gb2JqO1xuICB9O1xuXG4gIC8vIEV4cG9ydCB0aGUgVW5kZXJzY29yZSBvYmplY3QgZm9yICoqTm9kZS5qcyoqLCB3aXRoXG4gIC8vIGJhY2t3YXJkcy1jb21wYXRpYmlsaXR5IGZvciB0aGUgb2xkIGByZXF1aXJlKClgIEFQSS4gSWYgd2UncmUgaW5cbiAgLy8gdGhlIGJyb3dzZXIsIGFkZCBgX2AgYXMgYSBnbG9iYWwgb2JqZWN0LlxuICBpZiAodHlwZW9mIGV4cG9ydHMgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgaWYgKHR5cGVvZiBtb2R1bGUgIT09ICd1bmRlZmluZWQnICYmIG1vZHVsZS5leHBvcnRzKSB7XG4gICAgICBleHBvcnRzID0gbW9kdWxlLmV4cG9ydHMgPSBfO1xuICAgIH1cbiAgICBleHBvcnRzLl8gPSBfO1xuICB9IGVsc2Uge1xuICAgIHJvb3QuXyA9IF87XG4gIH1cblxuICAvLyBDdXJyZW50IHZlcnNpb24uXG4gIF8uVkVSU0lPTiA9ICcxLjguMyc7XG5cbiAgLy8gSW50ZXJuYWwgZnVuY3Rpb24gdGhhdCByZXR1cm5zIGFuIGVmZmljaWVudCAoZm9yIGN1cnJlbnQgZW5naW5lcykgdmVyc2lvblxuICAvLyBvZiB0aGUgcGFzc2VkLWluIGNhbGxiYWNrLCB0byBiZSByZXBlYXRlZGx5IGFwcGxpZWQgaW4gb3RoZXIgVW5kZXJzY29yZVxuICAvLyBmdW5jdGlvbnMuXG4gIHZhciBvcHRpbWl6ZUNiID0gZnVuY3Rpb24oZnVuYywgY29udGV4dCwgYXJnQ291bnQpIHtcbiAgICBpZiAoY29udGV4dCA9PT0gdm9pZCAwKSByZXR1cm4gZnVuYztcbiAgICBzd2l0Y2ggKGFyZ0NvdW50ID09IG51bGwgPyAzIDogYXJnQ291bnQpIHtcbiAgICAgIGNhc2UgMTogcmV0dXJuIGZ1bmN0aW9uKHZhbHVlKSB7XG4gICAgICAgIHJldHVybiBmdW5jLmNhbGwoY29udGV4dCwgdmFsdWUpO1xuICAgICAgfTtcbiAgICAgIGNhc2UgMjogcmV0dXJuIGZ1bmN0aW9uKHZhbHVlLCBvdGhlcikge1xuICAgICAgICByZXR1cm4gZnVuYy5jYWxsKGNvbnRleHQsIHZhbHVlLCBvdGhlcik7XG4gICAgICB9O1xuICAgICAgY2FzZSAzOiByZXR1cm4gZnVuY3Rpb24odmFsdWUsIGluZGV4LCBjb2xsZWN0aW9uKSB7XG4gICAgICAgIHJldHVybiBmdW5jLmNhbGwoY29udGV4dCwgdmFsdWUsIGluZGV4LCBjb2xsZWN0aW9uKTtcbiAgICAgIH07XG4gICAgICBjYXNlIDQ6IHJldHVybiBmdW5jdGlvbihhY2N1bXVsYXRvciwgdmFsdWUsIGluZGV4LCBjb2xsZWN0aW9uKSB7XG4gICAgICAgIHJldHVybiBmdW5jLmNhbGwoY29udGV4dCwgYWNjdW11bGF0b3IsIHZhbHVlLCBpbmRleCwgY29sbGVjdGlvbik7XG4gICAgICB9O1xuICAgIH1cbiAgICByZXR1cm4gZnVuY3Rpb24oKSB7XG4gICAgICByZXR1cm4gZnVuYy5hcHBseShjb250ZXh0LCBhcmd1bWVudHMpO1xuICAgIH07XG4gIH07XG5cbiAgLy8gQSBtb3N0bHktaW50ZXJuYWwgZnVuY3Rpb24gdG8gZ2VuZXJhdGUgY2FsbGJhY2tzIHRoYXQgY2FuIGJlIGFwcGxpZWRcbiAgLy8gdG8gZWFjaCBlbGVtZW50IGluIGEgY29sbGVjdGlvbiwgcmV0dXJuaW5nIHRoZSBkZXNpcmVkIHJlc3VsdCDigJQgZWl0aGVyXG4gIC8vIGlkZW50aXR5LCBhbiBhcmJpdHJhcnkgY2FsbGJhY2ssIGEgcHJvcGVydHkgbWF0Y2hlciwgb3IgYSBwcm9wZXJ0eSBhY2Nlc3Nvci5cbiAgdmFyIGNiID0gZnVuY3Rpb24odmFsdWUsIGNvbnRleHQsIGFyZ0NvdW50KSB7XG4gICAgaWYgKHZhbHVlID09IG51bGwpIHJldHVybiBfLmlkZW50aXR5O1xuICAgIGlmIChfLmlzRnVuY3Rpb24odmFsdWUpKSByZXR1cm4gb3B0aW1pemVDYih2YWx1ZSwgY29udGV4dCwgYXJnQ291bnQpO1xuICAgIGlmIChfLmlzT2JqZWN0KHZhbHVlKSkgcmV0dXJuIF8ubWF0Y2hlcih2YWx1ZSk7XG4gICAgcmV0dXJuIF8ucHJvcGVydHkodmFsdWUpO1xuICB9O1xuICBfLml0ZXJhdGVlID0gZnVuY3Rpb24odmFsdWUsIGNvbnRleHQpIHtcbiAgICByZXR1cm4gY2IodmFsdWUsIGNvbnRleHQsIEluZmluaXR5KTtcbiAgfTtcblxuICAvLyBBbiBpbnRlcm5hbCBmdW5jdGlvbiBmb3IgY3JlYXRpbmcgYXNzaWduZXIgZnVuY3Rpb25zLlxuICB2YXIgY3JlYXRlQXNzaWduZXIgPSBmdW5jdGlvbihrZXlzRnVuYywgdW5kZWZpbmVkT25seSkge1xuICAgIHJldHVybiBmdW5jdGlvbihvYmopIHtcbiAgICAgIHZhciBsZW5ndGggPSBhcmd1bWVudHMubGVuZ3RoO1xuICAgICAgaWYgKGxlbmd0aCA8IDIgfHwgb2JqID09IG51bGwpIHJldHVybiBvYmo7XG4gICAgICBmb3IgKHZhciBpbmRleCA9IDE7IGluZGV4IDwgbGVuZ3RoOyBpbmRleCsrKSB7XG4gICAgICAgIHZhciBzb3VyY2UgPSBhcmd1bWVudHNbaW5kZXhdLFxuICAgICAgICAgICAga2V5cyA9IGtleXNGdW5jKHNvdXJjZSksXG4gICAgICAgICAgICBsID0ga2V5cy5sZW5ndGg7XG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbDsgaSsrKSB7XG4gICAgICAgICAgdmFyIGtleSA9IGtleXNbaV07XG4gICAgICAgICAgaWYgKCF1bmRlZmluZWRPbmx5IHx8IG9ialtrZXldID09PSB2b2lkIDApIG9ialtrZXldID0gc291cmNlW2tleV07XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiBvYmo7XG4gICAgfTtcbiAgfTtcblxuICAvLyBBbiBpbnRlcm5hbCBmdW5jdGlvbiBmb3IgY3JlYXRpbmcgYSBuZXcgb2JqZWN0IHRoYXQgaW5oZXJpdHMgZnJvbSBhbm90aGVyLlxuICB2YXIgYmFzZUNyZWF0ZSA9IGZ1bmN0aW9uKHByb3RvdHlwZSkge1xuICAgIGlmICghXy5pc09iamVjdChwcm90b3R5cGUpKSByZXR1cm4ge307XG4gICAgaWYgKG5hdGl2ZUNyZWF0ZSkgcmV0dXJuIG5hdGl2ZUNyZWF0ZShwcm90b3R5cGUpO1xuICAgIEN0b3IucHJvdG90eXBlID0gcHJvdG90eXBlO1xuICAgIHZhciByZXN1bHQgPSBuZXcgQ3RvcjtcbiAgICBDdG9yLnByb3RvdHlwZSA9IG51bGw7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfTtcblxuICB2YXIgcHJvcGVydHkgPSBmdW5jdGlvbihrZXkpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24ob2JqKSB7XG4gICAgICByZXR1cm4gb2JqID09IG51bGwgPyB2b2lkIDAgOiBvYmpba2V5XTtcbiAgICB9O1xuICB9O1xuXG4gIC8vIEhlbHBlciBmb3IgY29sbGVjdGlvbiBtZXRob2RzIHRvIGRldGVybWluZSB3aGV0aGVyIGEgY29sbGVjdGlvblxuICAvLyBzaG91bGQgYmUgaXRlcmF0ZWQgYXMgYW4gYXJyYXkgb3IgYXMgYW4gb2JqZWN0XG4gIC8vIFJlbGF0ZWQ6IGh0dHA6Ly9wZW9wbGUubW96aWxsYS5vcmcvfmpvcmVuZG9yZmYvZXM2LWRyYWZ0Lmh0bWwjc2VjLXRvbGVuZ3RoXG4gIC8vIEF2b2lkcyBhIHZlcnkgbmFzdHkgaU9TIDggSklUIGJ1ZyBvbiBBUk0tNjQuICMyMDk0XG4gIHZhciBNQVhfQVJSQVlfSU5ERVggPSBNYXRoLnBvdygyLCA1MykgLSAxO1xuICB2YXIgZ2V0TGVuZ3RoID0gcHJvcGVydHkoJ2xlbmd0aCcpO1xuICB2YXIgaXNBcnJheUxpa2UgPSBmdW5jdGlvbihjb2xsZWN0aW9uKSB7XG4gICAgdmFyIGxlbmd0aCA9IGdldExlbmd0aChjb2xsZWN0aW9uKTtcbiAgICByZXR1cm4gdHlwZW9mIGxlbmd0aCA9PSAnbnVtYmVyJyAmJiBsZW5ndGggPj0gMCAmJiBsZW5ndGggPD0gTUFYX0FSUkFZX0lOREVYO1xuICB9O1xuXG4gIC8vIENvbGxlY3Rpb24gRnVuY3Rpb25zXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgLy8gVGhlIGNvcm5lcnN0b25lLCBhbiBgZWFjaGAgaW1wbGVtZW50YXRpb24sIGFrYSBgZm9yRWFjaGAuXG4gIC8vIEhhbmRsZXMgcmF3IG9iamVjdHMgaW4gYWRkaXRpb24gdG8gYXJyYXktbGlrZXMuIFRyZWF0cyBhbGxcbiAgLy8gc3BhcnNlIGFycmF5LWxpa2VzIGFzIGlmIHRoZXkgd2VyZSBkZW5zZS5cbiAgXy5lYWNoID0gXy5mb3JFYWNoID0gZnVuY3Rpb24ob2JqLCBpdGVyYXRlZSwgY29udGV4dCkge1xuICAgIGl0ZXJhdGVlID0gb3B0aW1pemVDYihpdGVyYXRlZSwgY29udGV4dCk7XG4gICAgdmFyIGksIGxlbmd0aDtcbiAgICBpZiAoaXNBcnJheUxpa2Uob2JqKSkge1xuICAgICAgZm9yIChpID0gMCwgbGVuZ3RoID0gb2JqLmxlbmd0aDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGl0ZXJhdGVlKG9ialtpXSwgaSwgb2JqKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgdmFyIGtleXMgPSBfLmtleXMob2JqKTtcbiAgICAgIGZvciAoaSA9IDAsIGxlbmd0aCA9IGtleXMubGVuZ3RoOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgICAgaXRlcmF0ZWUob2JqW2tleXNbaV1dLCBrZXlzW2ldLCBvYmopO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gb2JqO1xuICB9O1xuXG4gIC8vIFJldHVybiB0aGUgcmVzdWx0cyBvZiBhcHBseWluZyB0aGUgaXRlcmF0ZWUgdG8gZWFjaCBlbGVtZW50LlxuICBfLm1hcCA9IF8uY29sbGVjdCA9IGZ1bmN0aW9uKG9iaiwgaXRlcmF0ZWUsIGNvbnRleHQpIHtcbiAgICBpdGVyYXRlZSA9IGNiKGl0ZXJhdGVlLCBjb250ZXh0KTtcbiAgICB2YXIga2V5cyA9ICFpc0FycmF5TGlrZShvYmopICYmIF8ua2V5cyhvYmopLFxuICAgICAgICBsZW5ndGggPSAoa2V5cyB8fCBvYmopLmxlbmd0aCxcbiAgICAgICAgcmVzdWx0cyA9IEFycmF5KGxlbmd0aCk7XG4gICAgZm9yICh2YXIgaW5kZXggPSAwOyBpbmRleCA8IGxlbmd0aDsgaW5kZXgrKykge1xuICAgICAgdmFyIGN1cnJlbnRLZXkgPSBrZXlzID8ga2V5c1tpbmRleF0gOiBpbmRleDtcbiAgICAgIHJlc3VsdHNbaW5kZXhdID0gaXRlcmF0ZWUob2JqW2N1cnJlbnRLZXldLCBjdXJyZW50S2V5LCBvYmopO1xuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0cztcbiAgfTtcblxuICAvLyBDcmVhdGUgYSByZWR1Y2luZyBmdW5jdGlvbiBpdGVyYXRpbmcgbGVmdCBvciByaWdodC5cbiAgZnVuY3Rpb24gY3JlYXRlUmVkdWNlKGRpcikge1xuICAgIC8vIE9wdGltaXplZCBpdGVyYXRvciBmdW5jdGlvbiBhcyB1c2luZyBhcmd1bWVudHMubGVuZ3RoXG4gICAgLy8gaW4gdGhlIG1haW4gZnVuY3Rpb24gd2lsbCBkZW9wdGltaXplIHRoZSwgc2VlICMxOTkxLlxuICAgIGZ1bmN0aW9uIGl0ZXJhdG9yKG9iaiwgaXRlcmF0ZWUsIG1lbW8sIGtleXMsIGluZGV4LCBsZW5ndGgpIHtcbiAgICAgIGZvciAoOyBpbmRleCA+PSAwICYmIGluZGV4IDwgbGVuZ3RoOyBpbmRleCArPSBkaXIpIHtcbiAgICAgICAgdmFyIGN1cnJlbnRLZXkgPSBrZXlzID8ga2V5c1tpbmRleF0gOiBpbmRleDtcbiAgICAgICAgbWVtbyA9IGl0ZXJhdGVlKG1lbW8sIG9ialtjdXJyZW50S2V5XSwgY3VycmVudEtleSwgb2JqKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBtZW1vO1xuICAgIH1cblxuICAgIHJldHVybiBmdW5jdGlvbihvYmosIGl0ZXJhdGVlLCBtZW1vLCBjb250ZXh0KSB7XG4gICAgICBpdGVyYXRlZSA9IG9wdGltaXplQ2IoaXRlcmF0ZWUsIGNvbnRleHQsIDQpO1xuICAgICAgdmFyIGtleXMgPSAhaXNBcnJheUxpa2Uob2JqKSAmJiBfLmtleXMob2JqKSxcbiAgICAgICAgICBsZW5ndGggPSAoa2V5cyB8fCBvYmopLmxlbmd0aCxcbiAgICAgICAgICBpbmRleCA9IGRpciA+IDAgPyAwIDogbGVuZ3RoIC0gMTtcbiAgICAgIC8vIERldGVybWluZSB0aGUgaW5pdGlhbCB2YWx1ZSBpZiBub25lIGlzIHByb3ZpZGVkLlxuICAgICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPCAzKSB7XG4gICAgICAgIG1lbW8gPSBvYmpba2V5cyA/IGtleXNbaW5kZXhdIDogaW5kZXhdO1xuICAgICAgICBpbmRleCArPSBkaXI7XG4gICAgICB9XG4gICAgICByZXR1cm4gaXRlcmF0b3Iob2JqLCBpdGVyYXRlZSwgbWVtbywga2V5cywgaW5kZXgsIGxlbmd0aCk7XG4gICAgfTtcbiAgfVxuXG4gIC8vICoqUmVkdWNlKiogYnVpbGRzIHVwIGEgc2luZ2xlIHJlc3VsdCBmcm9tIGEgbGlzdCBvZiB2YWx1ZXMsIGFrYSBgaW5qZWN0YCxcbiAgLy8gb3IgYGZvbGRsYC5cbiAgXy5yZWR1Y2UgPSBfLmZvbGRsID0gXy5pbmplY3QgPSBjcmVhdGVSZWR1Y2UoMSk7XG5cbiAgLy8gVGhlIHJpZ2h0LWFzc29jaWF0aXZlIHZlcnNpb24gb2YgcmVkdWNlLCBhbHNvIGtub3duIGFzIGBmb2xkcmAuXG4gIF8ucmVkdWNlUmlnaHQgPSBfLmZvbGRyID0gY3JlYXRlUmVkdWNlKC0xKTtcblxuICAvLyBSZXR1cm4gdGhlIGZpcnN0IHZhbHVlIHdoaWNoIHBhc3NlcyBhIHRydXRoIHRlc3QuIEFsaWFzZWQgYXMgYGRldGVjdGAuXG4gIF8uZmluZCA9IF8uZGV0ZWN0ID0gZnVuY3Rpb24ob2JqLCBwcmVkaWNhdGUsIGNvbnRleHQpIHtcbiAgICB2YXIga2V5O1xuICAgIGlmIChpc0FycmF5TGlrZShvYmopKSB7XG4gICAgICBrZXkgPSBfLmZpbmRJbmRleChvYmosIHByZWRpY2F0ZSwgY29udGV4dCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGtleSA9IF8uZmluZEtleShvYmosIHByZWRpY2F0ZSwgY29udGV4dCk7XG4gICAgfVxuICAgIGlmIChrZXkgIT09IHZvaWQgMCAmJiBrZXkgIT09IC0xKSByZXR1cm4gb2JqW2tleV07XG4gIH07XG5cbiAgLy8gUmV0dXJuIGFsbCB0aGUgZWxlbWVudHMgdGhhdCBwYXNzIGEgdHJ1dGggdGVzdC5cbiAgLy8gQWxpYXNlZCBhcyBgc2VsZWN0YC5cbiAgXy5maWx0ZXIgPSBfLnNlbGVjdCA9IGZ1bmN0aW9uKG9iaiwgcHJlZGljYXRlLCBjb250ZXh0KSB7XG4gICAgdmFyIHJlc3VsdHMgPSBbXTtcbiAgICBwcmVkaWNhdGUgPSBjYihwcmVkaWNhdGUsIGNvbnRleHQpO1xuICAgIF8uZWFjaChvYmosIGZ1bmN0aW9uKHZhbHVlLCBpbmRleCwgbGlzdCkge1xuICAgICAgaWYgKHByZWRpY2F0ZSh2YWx1ZSwgaW5kZXgsIGxpc3QpKSByZXN1bHRzLnB1c2godmFsdWUpO1xuICAgIH0pO1xuICAgIHJldHVybiByZXN1bHRzO1xuICB9O1xuXG4gIC8vIFJldHVybiBhbGwgdGhlIGVsZW1lbnRzIGZvciB3aGljaCBhIHRydXRoIHRlc3QgZmFpbHMuXG4gIF8ucmVqZWN0ID0gZnVuY3Rpb24ob2JqLCBwcmVkaWNhdGUsIGNvbnRleHQpIHtcbiAgICByZXR1cm4gXy5maWx0ZXIob2JqLCBfLm5lZ2F0ZShjYihwcmVkaWNhdGUpKSwgY29udGV4dCk7XG4gIH07XG5cbiAgLy8gRGV0ZXJtaW5lIHdoZXRoZXIgYWxsIG9mIHRoZSBlbGVtZW50cyBtYXRjaCBhIHRydXRoIHRlc3QuXG4gIC8vIEFsaWFzZWQgYXMgYGFsbGAuXG4gIF8uZXZlcnkgPSBfLmFsbCA9IGZ1bmN0aW9uKG9iaiwgcHJlZGljYXRlLCBjb250ZXh0KSB7XG4gICAgcHJlZGljYXRlID0gY2IocHJlZGljYXRlLCBjb250ZXh0KTtcbiAgICB2YXIga2V5cyA9ICFpc0FycmF5TGlrZShvYmopICYmIF8ua2V5cyhvYmopLFxuICAgICAgICBsZW5ndGggPSAoa2V5cyB8fCBvYmopLmxlbmd0aDtcbiAgICBmb3IgKHZhciBpbmRleCA9IDA7IGluZGV4IDwgbGVuZ3RoOyBpbmRleCsrKSB7XG4gICAgICB2YXIgY3VycmVudEtleSA9IGtleXMgPyBrZXlzW2luZGV4XSA6IGluZGV4O1xuICAgICAgaWYgKCFwcmVkaWNhdGUob2JqW2N1cnJlbnRLZXldLCBjdXJyZW50S2V5LCBvYmopKSByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIHJldHVybiB0cnVlO1xuICB9O1xuXG4gIC8vIERldGVybWluZSBpZiBhdCBsZWFzdCBvbmUgZWxlbWVudCBpbiB0aGUgb2JqZWN0IG1hdGNoZXMgYSB0cnV0aCB0ZXN0LlxuICAvLyBBbGlhc2VkIGFzIGBhbnlgLlxuICBfLnNvbWUgPSBfLmFueSA9IGZ1bmN0aW9uKG9iaiwgcHJlZGljYXRlLCBjb250ZXh0KSB7XG4gICAgcHJlZGljYXRlID0gY2IocHJlZGljYXRlLCBjb250ZXh0KTtcbiAgICB2YXIga2V5cyA9ICFpc0FycmF5TGlrZShvYmopICYmIF8ua2V5cyhvYmopLFxuICAgICAgICBsZW5ndGggPSAoa2V5cyB8fCBvYmopLmxlbmd0aDtcbiAgICBmb3IgKHZhciBpbmRleCA9IDA7IGluZGV4IDwgbGVuZ3RoOyBpbmRleCsrKSB7XG4gICAgICB2YXIgY3VycmVudEtleSA9IGtleXMgPyBrZXlzW2luZGV4XSA6IGluZGV4O1xuICAgICAgaWYgKHByZWRpY2F0ZShvYmpbY3VycmVudEtleV0sIGN1cnJlbnRLZXksIG9iaikpIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG4gIH07XG5cbiAgLy8gRGV0ZXJtaW5lIGlmIHRoZSBhcnJheSBvciBvYmplY3QgY29udGFpbnMgYSBnaXZlbiBpdGVtICh1c2luZyBgPT09YCkuXG4gIC8vIEFsaWFzZWQgYXMgYGluY2x1ZGVzYCBhbmQgYGluY2x1ZGVgLlxuICBfLmNvbnRhaW5zID0gXy5pbmNsdWRlcyA9IF8uaW5jbHVkZSA9IGZ1bmN0aW9uKG9iaiwgaXRlbSwgZnJvbUluZGV4LCBndWFyZCkge1xuICAgIGlmICghaXNBcnJheUxpa2Uob2JqKSkgb2JqID0gXy52YWx1ZXMob2JqKTtcbiAgICBpZiAodHlwZW9mIGZyb21JbmRleCAhPSAnbnVtYmVyJyB8fCBndWFyZCkgZnJvbUluZGV4ID0gMDtcbiAgICByZXR1cm4gXy5pbmRleE9mKG9iaiwgaXRlbSwgZnJvbUluZGV4KSA+PSAwO1xuICB9O1xuXG4gIC8vIEludm9rZSBhIG1ldGhvZCAod2l0aCBhcmd1bWVudHMpIG9uIGV2ZXJ5IGl0ZW0gaW4gYSBjb2xsZWN0aW9uLlxuICBfLmludm9rZSA9IGZ1bmN0aW9uKG9iaiwgbWV0aG9kKSB7XG4gICAgdmFyIGFyZ3MgPSBzbGljZS5jYWxsKGFyZ3VtZW50cywgMik7XG4gICAgdmFyIGlzRnVuYyA9IF8uaXNGdW5jdGlvbihtZXRob2QpO1xuICAgIHJldHVybiBfLm1hcChvYmosIGZ1bmN0aW9uKHZhbHVlKSB7XG4gICAgICB2YXIgZnVuYyA9IGlzRnVuYyA/IG1ldGhvZCA6IHZhbHVlW21ldGhvZF07XG4gICAgICByZXR1cm4gZnVuYyA9PSBudWxsID8gZnVuYyA6IGZ1bmMuYXBwbHkodmFsdWUsIGFyZ3MpO1xuICAgIH0pO1xuICB9O1xuXG4gIC8vIENvbnZlbmllbmNlIHZlcnNpb24gb2YgYSBjb21tb24gdXNlIGNhc2Ugb2YgYG1hcGA6IGZldGNoaW5nIGEgcHJvcGVydHkuXG4gIF8ucGx1Y2sgPSBmdW5jdGlvbihvYmosIGtleSkge1xuICAgIHJldHVybiBfLm1hcChvYmosIF8ucHJvcGVydHkoa2V5KSk7XG4gIH07XG5cbiAgLy8gQ29udmVuaWVuY2UgdmVyc2lvbiBvZiBhIGNvbW1vbiB1c2UgY2FzZSBvZiBgZmlsdGVyYDogc2VsZWN0aW5nIG9ubHkgb2JqZWN0c1xuICAvLyBjb250YWluaW5nIHNwZWNpZmljIGBrZXk6dmFsdWVgIHBhaXJzLlxuICBfLndoZXJlID0gZnVuY3Rpb24ob2JqLCBhdHRycykge1xuICAgIHJldHVybiBfLmZpbHRlcihvYmosIF8ubWF0Y2hlcihhdHRycykpO1xuICB9O1xuXG4gIC8vIENvbnZlbmllbmNlIHZlcnNpb24gb2YgYSBjb21tb24gdXNlIGNhc2Ugb2YgYGZpbmRgOiBnZXR0aW5nIHRoZSBmaXJzdCBvYmplY3RcbiAgLy8gY29udGFpbmluZyBzcGVjaWZpYyBga2V5OnZhbHVlYCBwYWlycy5cbiAgXy5maW5kV2hlcmUgPSBmdW5jdGlvbihvYmosIGF0dHJzKSB7XG4gICAgcmV0dXJuIF8uZmluZChvYmosIF8ubWF0Y2hlcihhdHRycykpO1xuICB9O1xuXG4gIC8vIFJldHVybiB0aGUgbWF4aW11bSBlbGVtZW50IChvciBlbGVtZW50LWJhc2VkIGNvbXB1dGF0aW9uKS5cbiAgXy5tYXggPSBmdW5jdGlvbihvYmosIGl0ZXJhdGVlLCBjb250ZXh0KSB7XG4gICAgdmFyIHJlc3VsdCA9IC1JbmZpbml0eSwgbGFzdENvbXB1dGVkID0gLUluZmluaXR5LFxuICAgICAgICB2YWx1ZSwgY29tcHV0ZWQ7XG4gICAgaWYgKGl0ZXJhdGVlID09IG51bGwgJiYgb2JqICE9IG51bGwpIHtcbiAgICAgIG9iaiA9IGlzQXJyYXlMaWtlKG9iaikgPyBvYmogOiBfLnZhbHVlcyhvYmopO1xuICAgICAgZm9yICh2YXIgaSA9IDAsIGxlbmd0aCA9IG9iai5sZW5ndGg7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgICAgICB2YWx1ZSA9IG9ialtpXTtcbiAgICAgICAgaWYgKHZhbHVlID4gcmVzdWx0KSB7XG4gICAgICAgICAgcmVzdWx0ID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgaXRlcmF0ZWUgPSBjYihpdGVyYXRlZSwgY29udGV4dCk7XG4gICAgICBfLmVhY2gob2JqLCBmdW5jdGlvbih2YWx1ZSwgaW5kZXgsIGxpc3QpIHtcbiAgICAgICAgY29tcHV0ZWQgPSBpdGVyYXRlZSh2YWx1ZSwgaW5kZXgsIGxpc3QpO1xuICAgICAgICBpZiAoY29tcHV0ZWQgPiBsYXN0Q29tcHV0ZWQgfHwgY29tcHV0ZWQgPT09IC1JbmZpbml0eSAmJiByZXN1bHQgPT09IC1JbmZpbml0eSkge1xuICAgICAgICAgIHJlc3VsdCA9IHZhbHVlO1xuICAgICAgICAgIGxhc3RDb21wdXRlZCA9IGNvbXB1dGVkO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfTtcblxuICAvLyBSZXR1cm4gdGhlIG1pbmltdW0gZWxlbWVudCAob3IgZWxlbWVudC1iYXNlZCBjb21wdXRhdGlvbikuXG4gIF8ubWluID0gZnVuY3Rpb24ob2JqLCBpdGVyYXRlZSwgY29udGV4dCkge1xuICAgIHZhciByZXN1bHQgPSBJbmZpbml0eSwgbGFzdENvbXB1dGVkID0gSW5maW5pdHksXG4gICAgICAgIHZhbHVlLCBjb21wdXRlZDtcbiAgICBpZiAoaXRlcmF0ZWUgPT0gbnVsbCAmJiBvYmogIT0gbnVsbCkge1xuICAgICAgb2JqID0gaXNBcnJheUxpa2Uob2JqKSA/IG9iaiA6IF8udmFsdWVzKG9iaik7XG4gICAgICBmb3IgKHZhciBpID0gMCwgbGVuZ3RoID0gb2JqLmxlbmd0aDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhbHVlID0gb2JqW2ldO1xuICAgICAgICBpZiAodmFsdWUgPCByZXN1bHQpIHtcbiAgICAgICAgICByZXN1bHQgPSB2YWx1ZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBpdGVyYXRlZSA9IGNiKGl0ZXJhdGVlLCBjb250ZXh0KTtcbiAgICAgIF8uZWFjaChvYmosIGZ1bmN0aW9uKHZhbHVlLCBpbmRleCwgbGlzdCkge1xuICAgICAgICBjb21wdXRlZCA9IGl0ZXJhdGVlKHZhbHVlLCBpbmRleCwgbGlzdCk7XG4gICAgICAgIGlmIChjb21wdXRlZCA8IGxhc3RDb21wdXRlZCB8fCBjb21wdXRlZCA9PT0gSW5maW5pdHkgJiYgcmVzdWx0ID09PSBJbmZpbml0eSkge1xuICAgICAgICAgIHJlc3VsdCA9IHZhbHVlO1xuICAgICAgICAgIGxhc3RDb21wdXRlZCA9IGNvbXB1dGVkO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfTtcblxuICAvLyBTaHVmZmxlIGEgY29sbGVjdGlvbiwgdXNpbmcgdGhlIG1vZGVybiB2ZXJzaW9uIG9mIHRoZVxuICAvLyBbRmlzaGVyLVlhdGVzIHNodWZmbGVdKGh0dHA6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvRmlzaGVy4oCTWWF0ZXNfc2h1ZmZsZSkuXG4gIF8uc2h1ZmZsZSA9IGZ1bmN0aW9uKG9iaikge1xuICAgIHZhciBzZXQgPSBpc0FycmF5TGlrZShvYmopID8gb2JqIDogXy52YWx1ZXMob2JqKTtcbiAgICB2YXIgbGVuZ3RoID0gc2V0Lmxlbmd0aDtcbiAgICB2YXIgc2h1ZmZsZWQgPSBBcnJheShsZW5ndGgpO1xuICAgIGZvciAodmFyIGluZGV4ID0gMCwgcmFuZDsgaW5kZXggPCBsZW5ndGg7IGluZGV4KyspIHtcbiAgICAgIHJhbmQgPSBfLnJhbmRvbSgwLCBpbmRleCk7XG4gICAgICBpZiAocmFuZCAhPT0gaW5kZXgpIHNodWZmbGVkW2luZGV4XSA9IHNodWZmbGVkW3JhbmRdO1xuICAgICAgc2h1ZmZsZWRbcmFuZF0gPSBzZXRbaW5kZXhdO1xuICAgIH1cbiAgICByZXR1cm4gc2h1ZmZsZWQ7XG4gIH07XG5cbiAgLy8gU2FtcGxlICoqbioqIHJhbmRvbSB2YWx1ZXMgZnJvbSBhIGNvbGxlY3Rpb24uXG4gIC8vIElmICoqbioqIGlzIG5vdCBzcGVjaWZpZWQsIHJldHVybnMgYSBzaW5nbGUgcmFuZG9tIGVsZW1lbnQuXG4gIC8vIFRoZSBpbnRlcm5hbCBgZ3VhcmRgIGFyZ3VtZW50IGFsbG93cyBpdCB0byB3b3JrIHdpdGggYG1hcGAuXG4gIF8uc2FtcGxlID0gZnVuY3Rpb24ob2JqLCBuLCBndWFyZCkge1xuICAgIGlmIChuID09IG51bGwgfHwgZ3VhcmQpIHtcbiAgICAgIGlmICghaXNBcnJheUxpa2Uob2JqKSkgb2JqID0gXy52YWx1ZXMob2JqKTtcbiAgICAgIHJldHVybiBvYmpbXy5yYW5kb20ob2JqLmxlbmd0aCAtIDEpXTtcbiAgICB9XG4gICAgcmV0dXJuIF8uc2h1ZmZsZShvYmopLnNsaWNlKDAsIE1hdGgubWF4KDAsIG4pKTtcbiAgfTtcblxuICAvLyBTb3J0IHRoZSBvYmplY3QncyB2YWx1ZXMgYnkgYSBjcml0ZXJpb24gcHJvZHVjZWQgYnkgYW4gaXRlcmF0ZWUuXG4gIF8uc29ydEJ5ID0gZnVuY3Rpb24ob2JqLCBpdGVyYXRlZSwgY29udGV4dCkge1xuICAgIGl0ZXJhdGVlID0gY2IoaXRlcmF0ZWUsIGNvbnRleHQpO1xuICAgIHJldHVybiBfLnBsdWNrKF8ubWFwKG9iaiwgZnVuY3Rpb24odmFsdWUsIGluZGV4LCBsaXN0KSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICB2YWx1ZTogdmFsdWUsXG4gICAgICAgIGluZGV4OiBpbmRleCxcbiAgICAgICAgY3JpdGVyaWE6IGl0ZXJhdGVlKHZhbHVlLCBpbmRleCwgbGlzdClcbiAgICAgIH07XG4gICAgfSkuc29ydChmdW5jdGlvbihsZWZ0LCByaWdodCkge1xuICAgICAgdmFyIGEgPSBsZWZ0LmNyaXRlcmlhO1xuICAgICAgdmFyIGIgPSByaWdodC5jcml0ZXJpYTtcbiAgICAgIGlmIChhICE9PSBiKSB7XG4gICAgICAgIGlmIChhID4gYiB8fCBhID09PSB2b2lkIDApIHJldHVybiAxO1xuICAgICAgICBpZiAoYSA8IGIgfHwgYiA9PT0gdm9pZCAwKSByZXR1cm4gLTE7XG4gICAgICB9XG4gICAgICByZXR1cm4gbGVmdC5pbmRleCAtIHJpZ2h0LmluZGV4O1xuICAgIH0pLCAndmFsdWUnKTtcbiAgfTtcblxuICAvLyBBbiBpbnRlcm5hbCBmdW5jdGlvbiB1c2VkIGZvciBhZ2dyZWdhdGUgXCJncm91cCBieVwiIG9wZXJhdGlvbnMuXG4gIHZhciBncm91cCA9IGZ1bmN0aW9uKGJlaGF2aW9yKSB7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKG9iaiwgaXRlcmF0ZWUsIGNvbnRleHQpIHtcbiAgICAgIHZhciByZXN1bHQgPSB7fTtcbiAgICAgIGl0ZXJhdGVlID0gY2IoaXRlcmF0ZWUsIGNvbnRleHQpO1xuICAgICAgXy5lYWNoKG9iaiwgZnVuY3Rpb24odmFsdWUsIGluZGV4KSB7XG4gICAgICAgIHZhciBrZXkgPSBpdGVyYXRlZSh2YWx1ZSwgaW5kZXgsIG9iaik7XG4gICAgICAgIGJlaGF2aW9yKHJlc3VsdCwgdmFsdWUsIGtleSk7XG4gICAgICB9KTtcbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfTtcbiAgfTtcblxuICAvLyBHcm91cHMgdGhlIG9iamVjdCdzIHZhbHVlcyBieSBhIGNyaXRlcmlvbi4gUGFzcyBlaXRoZXIgYSBzdHJpbmcgYXR0cmlidXRlXG4gIC8vIHRvIGdyb3VwIGJ5LCBvciBhIGZ1bmN0aW9uIHRoYXQgcmV0dXJucyB0aGUgY3JpdGVyaW9uLlxuICBfLmdyb3VwQnkgPSBncm91cChmdW5jdGlvbihyZXN1bHQsIHZhbHVlLCBrZXkpIHtcbiAgICBpZiAoXy5oYXMocmVzdWx0LCBrZXkpKSByZXN1bHRba2V5XS5wdXNoKHZhbHVlKTsgZWxzZSByZXN1bHRba2V5XSA9IFt2YWx1ZV07XG4gIH0pO1xuXG4gIC8vIEluZGV4ZXMgdGhlIG9iamVjdCdzIHZhbHVlcyBieSBhIGNyaXRlcmlvbiwgc2ltaWxhciB0byBgZ3JvdXBCeWAsIGJ1dCBmb3JcbiAgLy8gd2hlbiB5b3Uga25vdyB0aGF0IHlvdXIgaW5kZXggdmFsdWVzIHdpbGwgYmUgdW5pcXVlLlxuICBfLmluZGV4QnkgPSBncm91cChmdW5jdGlvbihyZXN1bHQsIHZhbHVlLCBrZXkpIHtcbiAgICByZXN1bHRba2V5XSA9IHZhbHVlO1xuICB9KTtcblxuICAvLyBDb3VudHMgaW5zdGFuY2VzIG9mIGFuIG9iamVjdCB0aGF0IGdyb3VwIGJ5IGEgY2VydGFpbiBjcml0ZXJpb24uIFBhc3NcbiAgLy8gZWl0aGVyIGEgc3RyaW5nIGF0dHJpYnV0ZSB0byBjb3VudCBieSwgb3IgYSBmdW5jdGlvbiB0aGF0IHJldHVybnMgdGhlXG4gIC8vIGNyaXRlcmlvbi5cbiAgXy5jb3VudEJ5ID0gZ3JvdXAoZnVuY3Rpb24ocmVzdWx0LCB2YWx1ZSwga2V5KSB7XG4gICAgaWYgKF8uaGFzKHJlc3VsdCwga2V5KSkgcmVzdWx0W2tleV0rKzsgZWxzZSByZXN1bHRba2V5XSA9IDE7XG4gIH0pO1xuXG4gIC8vIFNhZmVseSBjcmVhdGUgYSByZWFsLCBsaXZlIGFycmF5IGZyb20gYW55dGhpbmcgaXRlcmFibGUuXG4gIF8udG9BcnJheSA9IGZ1bmN0aW9uKG9iaikge1xuICAgIGlmICghb2JqKSByZXR1cm4gW107XG4gICAgaWYgKF8uaXNBcnJheShvYmopKSByZXR1cm4gc2xpY2UuY2FsbChvYmopO1xuICAgIGlmIChpc0FycmF5TGlrZShvYmopKSByZXR1cm4gXy5tYXAob2JqLCBfLmlkZW50aXR5KTtcbiAgICByZXR1cm4gXy52YWx1ZXMob2JqKTtcbiAgfTtcblxuICAvLyBSZXR1cm4gdGhlIG51bWJlciBvZiBlbGVtZW50cyBpbiBhbiBvYmplY3QuXG4gIF8uc2l6ZSA9IGZ1bmN0aW9uKG9iaikge1xuICAgIGlmIChvYmogPT0gbnVsbCkgcmV0dXJuIDA7XG4gICAgcmV0dXJuIGlzQXJyYXlMaWtlKG9iaikgPyBvYmoubGVuZ3RoIDogXy5rZXlzKG9iaikubGVuZ3RoO1xuICB9O1xuXG4gIC8vIFNwbGl0IGEgY29sbGVjdGlvbiBpbnRvIHR3byBhcnJheXM6IG9uZSB3aG9zZSBlbGVtZW50cyBhbGwgc2F0aXNmeSB0aGUgZ2l2ZW5cbiAgLy8gcHJlZGljYXRlLCBhbmQgb25lIHdob3NlIGVsZW1lbnRzIGFsbCBkbyBub3Qgc2F0aXNmeSB0aGUgcHJlZGljYXRlLlxuICBfLnBhcnRpdGlvbiA9IGZ1bmN0aW9uKG9iaiwgcHJlZGljYXRlLCBjb250ZXh0KSB7XG4gICAgcHJlZGljYXRlID0gY2IocHJlZGljYXRlLCBjb250ZXh0KTtcbiAgICB2YXIgcGFzcyA9IFtdLCBmYWlsID0gW107XG4gICAgXy5lYWNoKG9iaiwgZnVuY3Rpb24odmFsdWUsIGtleSwgb2JqKSB7XG4gICAgICAocHJlZGljYXRlKHZhbHVlLCBrZXksIG9iaikgPyBwYXNzIDogZmFpbCkucHVzaCh2YWx1ZSk7XG4gICAgfSk7XG4gICAgcmV0dXJuIFtwYXNzLCBmYWlsXTtcbiAgfTtcblxuICAvLyBBcnJheSBGdW5jdGlvbnNcbiAgLy8gLS0tLS0tLS0tLS0tLS0tXG5cbiAgLy8gR2V0IHRoZSBmaXJzdCBlbGVtZW50IG9mIGFuIGFycmF5LiBQYXNzaW5nICoqbioqIHdpbGwgcmV0dXJuIHRoZSBmaXJzdCBOXG4gIC8vIHZhbHVlcyBpbiB0aGUgYXJyYXkuIEFsaWFzZWQgYXMgYGhlYWRgIGFuZCBgdGFrZWAuIFRoZSAqKmd1YXJkKiogY2hlY2tcbiAgLy8gYWxsb3dzIGl0IHRvIHdvcmsgd2l0aCBgXy5tYXBgLlxuICBfLmZpcnN0ID0gXy5oZWFkID0gXy50YWtlID0gZnVuY3Rpb24oYXJyYXksIG4sIGd1YXJkKSB7XG4gICAgaWYgKGFycmF5ID09IG51bGwpIHJldHVybiB2b2lkIDA7XG4gICAgaWYgKG4gPT0gbnVsbCB8fCBndWFyZCkgcmV0dXJuIGFycmF5WzBdO1xuICAgIHJldHVybiBfLmluaXRpYWwoYXJyYXksIGFycmF5Lmxlbmd0aCAtIG4pO1xuICB9O1xuXG4gIC8vIFJldHVybnMgZXZlcnl0aGluZyBidXQgdGhlIGxhc3QgZW50cnkgb2YgdGhlIGFycmF5LiBFc3BlY2lhbGx5IHVzZWZ1bCBvblxuICAvLyB0aGUgYXJndW1lbnRzIG9iamVjdC4gUGFzc2luZyAqKm4qKiB3aWxsIHJldHVybiBhbGwgdGhlIHZhbHVlcyBpblxuICAvLyB0aGUgYXJyYXksIGV4Y2x1ZGluZyB0aGUgbGFzdCBOLlxuICBfLmluaXRpYWwgPSBmdW5jdGlvbihhcnJheSwgbiwgZ3VhcmQpIHtcbiAgICByZXR1cm4gc2xpY2UuY2FsbChhcnJheSwgMCwgTWF0aC5tYXgoMCwgYXJyYXkubGVuZ3RoIC0gKG4gPT0gbnVsbCB8fCBndWFyZCA/IDEgOiBuKSkpO1xuICB9O1xuXG4gIC8vIEdldCB0aGUgbGFzdCBlbGVtZW50IG9mIGFuIGFycmF5LiBQYXNzaW5nICoqbioqIHdpbGwgcmV0dXJuIHRoZSBsYXN0IE5cbiAgLy8gdmFsdWVzIGluIHRoZSBhcnJheS5cbiAgXy5sYXN0ID0gZnVuY3Rpb24oYXJyYXksIG4sIGd1YXJkKSB7XG4gICAgaWYgKGFycmF5ID09IG51bGwpIHJldHVybiB2b2lkIDA7XG4gICAgaWYgKG4gPT0gbnVsbCB8fCBndWFyZCkgcmV0dXJuIGFycmF5W2FycmF5Lmxlbmd0aCAtIDFdO1xuICAgIHJldHVybiBfLnJlc3QoYXJyYXksIE1hdGgubWF4KDAsIGFycmF5Lmxlbmd0aCAtIG4pKTtcbiAgfTtcblxuICAvLyBSZXR1cm5zIGV2ZXJ5dGhpbmcgYnV0IHRoZSBmaXJzdCBlbnRyeSBvZiB0aGUgYXJyYXkuIEFsaWFzZWQgYXMgYHRhaWxgIGFuZCBgZHJvcGAuXG4gIC8vIEVzcGVjaWFsbHkgdXNlZnVsIG9uIHRoZSBhcmd1bWVudHMgb2JqZWN0LiBQYXNzaW5nIGFuICoqbioqIHdpbGwgcmV0dXJuXG4gIC8vIHRoZSByZXN0IE4gdmFsdWVzIGluIHRoZSBhcnJheS5cbiAgXy5yZXN0ID0gXy50YWlsID0gXy5kcm9wID0gZnVuY3Rpb24oYXJyYXksIG4sIGd1YXJkKSB7XG4gICAgcmV0dXJuIHNsaWNlLmNhbGwoYXJyYXksIG4gPT0gbnVsbCB8fCBndWFyZCA/IDEgOiBuKTtcbiAgfTtcblxuICAvLyBUcmltIG91dCBhbGwgZmFsc3kgdmFsdWVzIGZyb20gYW4gYXJyYXkuXG4gIF8uY29tcGFjdCA9IGZ1bmN0aW9uKGFycmF5KSB7XG4gICAgcmV0dXJuIF8uZmlsdGVyKGFycmF5LCBfLmlkZW50aXR5KTtcbiAgfTtcblxuICAvLyBJbnRlcm5hbCBpbXBsZW1lbnRhdGlvbiBvZiBhIHJlY3Vyc2l2ZSBgZmxhdHRlbmAgZnVuY3Rpb24uXG4gIHZhciBmbGF0dGVuID0gZnVuY3Rpb24oaW5wdXQsIHNoYWxsb3csIHN0cmljdCwgc3RhcnRJbmRleCkge1xuICAgIHZhciBvdXRwdXQgPSBbXSwgaWR4ID0gMDtcbiAgICBmb3IgKHZhciBpID0gc3RhcnRJbmRleCB8fCAwLCBsZW5ndGggPSBnZXRMZW5ndGgoaW5wdXQpOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciB2YWx1ZSA9IGlucHV0W2ldO1xuICAgICAgaWYgKGlzQXJyYXlMaWtlKHZhbHVlKSAmJiAoXy5pc0FycmF5KHZhbHVlKSB8fCBfLmlzQXJndW1lbnRzKHZhbHVlKSkpIHtcbiAgICAgICAgLy9mbGF0dGVuIGN1cnJlbnQgbGV2ZWwgb2YgYXJyYXkgb3IgYXJndW1lbnRzIG9iamVjdFxuICAgICAgICBpZiAoIXNoYWxsb3cpIHZhbHVlID0gZmxhdHRlbih2YWx1ZSwgc2hhbGxvdywgc3RyaWN0KTtcbiAgICAgICAgdmFyIGogPSAwLCBsZW4gPSB2YWx1ZS5sZW5ndGg7XG4gICAgICAgIG91dHB1dC5sZW5ndGggKz0gbGVuO1xuICAgICAgICB3aGlsZSAoaiA8IGxlbikge1xuICAgICAgICAgIG91dHB1dFtpZHgrK10gPSB2YWx1ZVtqKytdO1xuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKCFzdHJpY3QpIHtcbiAgICAgICAgb3V0cHV0W2lkeCsrXSA9IHZhbHVlO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gb3V0cHV0O1xuICB9O1xuXG4gIC8vIEZsYXR0ZW4gb3V0IGFuIGFycmF5LCBlaXRoZXIgcmVjdXJzaXZlbHkgKGJ5IGRlZmF1bHQpLCBvciBqdXN0IG9uZSBsZXZlbC5cbiAgXy5mbGF0dGVuID0gZnVuY3Rpb24oYXJyYXksIHNoYWxsb3cpIHtcbiAgICByZXR1cm4gZmxhdHRlbihhcnJheSwgc2hhbGxvdywgZmFsc2UpO1xuICB9O1xuXG4gIC8vIFJldHVybiBhIHZlcnNpb24gb2YgdGhlIGFycmF5IHRoYXQgZG9lcyBub3QgY29udGFpbiB0aGUgc3BlY2lmaWVkIHZhbHVlKHMpLlxuICBfLndpdGhvdXQgPSBmdW5jdGlvbihhcnJheSkge1xuICAgIHJldHVybiBfLmRpZmZlcmVuY2UoYXJyYXksIHNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKSk7XG4gIH07XG5cbiAgLy8gUHJvZHVjZSBhIGR1cGxpY2F0ZS1mcmVlIHZlcnNpb24gb2YgdGhlIGFycmF5LiBJZiB0aGUgYXJyYXkgaGFzIGFscmVhZHlcbiAgLy8gYmVlbiBzb3J0ZWQsIHlvdSBoYXZlIHRoZSBvcHRpb24gb2YgdXNpbmcgYSBmYXN0ZXIgYWxnb3JpdGhtLlxuICAvLyBBbGlhc2VkIGFzIGB1bmlxdWVgLlxuICBfLnVuaXEgPSBfLnVuaXF1ZSA9IGZ1bmN0aW9uKGFycmF5LCBpc1NvcnRlZCwgaXRlcmF0ZWUsIGNvbnRleHQpIHtcbiAgICBpZiAoIV8uaXNCb29sZWFuKGlzU29ydGVkKSkge1xuICAgICAgY29udGV4dCA9IGl0ZXJhdGVlO1xuICAgICAgaXRlcmF0ZWUgPSBpc1NvcnRlZDtcbiAgICAgIGlzU29ydGVkID0gZmFsc2U7XG4gICAgfVxuICAgIGlmIChpdGVyYXRlZSAhPSBudWxsKSBpdGVyYXRlZSA9IGNiKGl0ZXJhdGVlLCBjb250ZXh0KTtcbiAgICB2YXIgcmVzdWx0ID0gW107XG4gICAgdmFyIHNlZW4gPSBbXTtcbiAgICBmb3IgKHZhciBpID0gMCwgbGVuZ3RoID0gZ2V0TGVuZ3RoKGFycmF5KTsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgdmFsdWUgPSBhcnJheVtpXSxcbiAgICAgICAgICBjb21wdXRlZCA9IGl0ZXJhdGVlID8gaXRlcmF0ZWUodmFsdWUsIGksIGFycmF5KSA6IHZhbHVlO1xuICAgICAgaWYgKGlzU29ydGVkKSB7XG4gICAgICAgIGlmICghaSB8fCBzZWVuICE9PSBjb21wdXRlZCkgcmVzdWx0LnB1c2godmFsdWUpO1xuICAgICAgICBzZWVuID0gY29tcHV0ZWQ7XG4gICAgICB9IGVsc2UgaWYgKGl0ZXJhdGVlKSB7XG4gICAgICAgIGlmICghXy5jb250YWlucyhzZWVuLCBjb21wdXRlZCkpIHtcbiAgICAgICAgICBzZWVuLnB1c2goY29tcHV0ZWQpO1xuICAgICAgICAgIHJlc3VsdC5wdXNoKHZhbHVlKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmICghXy5jb250YWlucyhyZXN1bHQsIHZhbHVlKSkge1xuICAgICAgICByZXN1bHQucHVzaCh2YWx1ZSk7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG4gIH07XG5cbiAgLy8gUHJvZHVjZSBhbiBhcnJheSB0aGF0IGNvbnRhaW5zIHRoZSB1bmlvbjogZWFjaCBkaXN0aW5jdCBlbGVtZW50IGZyb20gYWxsIG9mXG4gIC8vIHRoZSBwYXNzZWQtaW4gYXJyYXlzLlxuICBfLnVuaW9uID0gZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIF8udW5pcShmbGF0dGVuKGFyZ3VtZW50cywgdHJ1ZSwgdHJ1ZSkpO1xuICB9O1xuXG4gIC8vIFByb2R1Y2UgYW4gYXJyYXkgdGhhdCBjb250YWlucyBldmVyeSBpdGVtIHNoYXJlZCBiZXR3ZWVuIGFsbCB0aGVcbiAgLy8gcGFzc2VkLWluIGFycmF5cy5cbiAgXy5pbnRlcnNlY3Rpb24gPSBmdW5jdGlvbihhcnJheSkge1xuICAgIHZhciByZXN1bHQgPSBbXTtcbiAgICB2YXIgYXJnc0xlbmd0aCA9IGFyZ3VtZW50cy5sZW5ndGg7XG4gICAgZm9yICh2YXIgaSA9IDAsIGxlbmd0aCA9IGdldExlbmd0aChhcnJheSk7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgICAgdmFyIGl0ZW0gPSBhcnJheVtpXTtcbiAgICAgIGlmIChfLmNvbnRhaW5zKHJlc3VsdCwgaXRlbSkpIGNvbnRpbnVlO1xuICAgICAgZm9yICh2YXIgaiA9IDE7IGogPCBhcmdzTGVuZ3RoOyBqKyspIHtcbiAgICAgICAgaWYgKCFfLmNvbnRhaW5zKGFyZ3VtZW50c1tqXSwgaXRlbSkpIGJyZWFrO1xuICAgICAgfVxuICAgICAgaWYgKGogPT09IGFyZ3NMZW5ndGgpIHJlc3VsdC5wdXNoKGl0ZW0pO1xuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9O1xuXG4gIC8vIFRha2UgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiBvbmUgYXJyYXkgYW5kIGEgbnVtYmVyIG9mIG90aGVyIGFycmF5cy5cbiAgLy8gT25seSB0aGUgZWxlbWVudHMgcHJlc2VudCBpbiBqdXN0IHRoZSBmaXJzdCBhcnJheSB3aWxsIHJlbWFpbi5cbiAgXy5kaWZmZXJlbmNlID0gZnVuY3Rpb24oYXJyYXkpIHtcbiAgICB2YXIgcmVzdCA9IGZsYXR0ZW4oYXJndW1lbnRzLCB0cnVlLCB0cnVlLCAxKTtcbiAgICByZXR1cm4gXy5maWx0ZXIoYXJyYXksIGZ1bmN0aW9uKHZhbHVlKXtcbiAgICAgIHJldHVybiAhXy5jb250YWlucyhyZXN0LCB2YWx1ZSk7XG4gICAgfSk7XG4gIH07XG5cbiAgLy8gWmlwIHRvZ2V0aGVyIG11bHRpcGxlIGxpc3RzIGludG8gYSBzaW5nbGUgYXJyYXkgLS0gZWxlbWVudHMgdGhhdCBzaGFyZVxuICAvLyBhbiBpbmRleCBnbyB0b2dldGhlci5cbiAgXy56aXAgPSBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gXy51bnppcChhcmd1bWVudHMpO1xuICB9O1xuXG4gIC8vIENvbXBsZW1lbnQgb2YgXy56aXAuIFVuemlwIGFjY2VwdHMgYW4gYXJyYXkgb2YgYXJyYXlzIGFuZCBncm91cHNcbiAgLy8gZWFjaCBhcnJheSdzIGVsZW1lbnRzIG9uIHNoYXJlZCBpbmRpY2VzXG4gIF8udW56aXAgPSBmdW5jdGlvbihhcnJheSkge1xuICAgIHZhciBsZW5ndGggPSBhcnJheSAmJiBfLm1heChhcnJheSwgZ2V0TGVuZ3RoKS5sZW5ndGggfHwgMDtcbiAgICB2YXIgcmVzdWx0ID0gQXJyYXkobGVuZ3RoKTtcblxuICAgIGZvciAodmFyIGluZGV4ID0gMDsgaW5kZXggPCBsZW5ndGg7IGluZGV4KyspIHtcbiAgICAgIHJlc3VsdFtpbmRleF0gPSBfLnBsdWNrKGFycmF5LCBpbmRleCk7XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG4gIH07XG5cbiAgLy8gQ29udmVydHMgbGlzdHMgaW50byBvYmplY3RzLiBQYXNzIGVpdGhlciBhIHNpbmdsZSBhcnJheSBvZiBgW2tleSwgdmFsdWVdYFxuICAvLyBwYWlycywgb3IgdHdvIHBhcmFsbGVsIGFycmF5cyBvZiB0aGUgc2FtZSBsZW5ndGggLS0gb25lIG9mIGtleXMsIGFuZCBvbmUgb2ZcbiAgLy8gdGhlIGNvcnJlc3BvbmRpbmcgdmFsdWVzLlxuICBfLm9iamVjdCA9IGZ1bmN0aW9uKGxpc3QsIHZhbHVlcykge1xuICAgIHZhciByZXN1bHQgPSB7fTtcbiAgICBmb3IgKHZhciBpID0gMCwgbGVuZ3RoID0gZ2V0TGVuZ3RoKGxpc3QpOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgIGlmICh2YWx1ZXMpIHtcbiAgICAgICAgcmVzdWx0W2xpc3RbaV1dID0gdmFsdWVzW2ldO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmVzdWx0W2xpc3RbaV1bMF1dID0gbGlzdFtpXVsxXTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfTtcblxuICAvLyBHZW5lcmF0b3IgZnVuY3Rpb24gdG8gY3JlYXRlIHRoZSBmaW5kSW5kZXggYW5kIGZpbmRMYXN0SW5kZXggZnVuY3Rpb25zXG4gIGZ1bmN0aW9uIGNyZWF0ZVByZWRpY2F0ZUluZGV4RmluZGVyKGRpcikge1xuICAgIHJldHVybiBmdW5jdGlvbihhcnJheSwgcHJlZGljYXRlLCBjb250ZXh0KSB7XG4gICAgICBwcmVkaWNhdGUgPSBjYihwcmVkaWNhdGUsIGNvbnRleHQpO1xuICAgICAgdmFyIGxlbmd0aCA9IGdldExlbmd0aChhcnJheSk7XG4gICAgICB2YXIgaW5kZXggPSBkaXIgPiAwID8gMCA6IGxlbmd0aCAtIDE7XG4gICAgICBmb3IgKDsgaW5kZXggPj0gMCAmJiBpbmRleCA8IGxlbmd0aDsgaW5kZXggKz0gZGlyKSB7XG4gICAgICAgIGlmIChwcmVkaWNhdGUoYXJyYXlbaW5kZXhdLCBpbmRleCwgYXJyYXkpKSByZXR1cm4gaW5kZXg7XG4gICAgICB9XG4gICAgICByZXR1cm4gLTE7XG4gICAgfTtcbiAgfVxuXG4gIC8vIFJldHVybnMgdGhlIGZpcnN0IGluZGV4IG9uIGFuIGFycmF5LWxpa2UgdGhhdCBwYXNzZXMgYSBwcmVkaWNhdGUgdGVzdFxuICBfLmZpbmRJbmRleCA9IGNyZWF0ZVByZWRpY2F0ZUluZGV4RmluZGVyKDEpO1xuICBfLmZpbmRMYXN0SW5kZXggPSBjcmVhdGVQcmVkaWNhdGVJbmRleEZpbmRlcigtMSk7XG5cbiAgLy8gVXNlIGEgY29tcGFyYXRvciBmdW5jdGlvbiB0byBmaWd1cmUgb3V0IHRoZSBzbWFsbGVzdCBpbmRleCBhdCB3aGljaFxuICAvLyBhbiBvYmplY3Qgc2hvdWxkIGJlIGluc2VydGVkIHNvIGFzIHRvIG1haW50YWluIG9yZGVyLiBVc2VzIGJpbmFyeSBzZWFyY2guXG4gIF8uc29ydGVkSW5kZXggPSBmdW5jdGlvbihhcnJheSwgb2JqLCBpdGVyYXRlZSwgY29udGV4dCkge1xuICAgIGl0ZXJhdGVlID0gY2IoaXRlcmF0ZWUsIGNvbnRleHQsIDEpO1xuICAgIHZhciB2YWx1ZSA9IGl0ZXJhdGVlKG9iaik7XG4gICAgdmFyIGxvdyA9IDAsIGhpZ2ggPSBnZXRMZW5ndGgoYXJyYXkpO1xuICAgIHdoaWxlIChsb3cgPCBoaWdoKSB7XG4gICAgICB2YXIgbWlkID0gTWF0aC5mbG9vcigobG93ICsgaGlnaCkgLyAyKTtcbiAgICAgIGlmIChpdGVyYXRlZShhcnJheVttaWRdKSA8IHZhbHVlKSBsb3cgPSBtaWQgKyAxOyBlbHNlIGhpZ2ggPSBtaWQ7XG4gICAgfVxuICAgIHJldHVybiBsb3c7XG4gIH07XG5cbiAgLy8gR2VuZXJhdG9yIGZ1bmN0aW9uIHRvIGNyZWF0ZSB0aGUgaW5kZXhPZiBhbmQgbGFzdEluZGV4T2YgZnVuY3Rpb25zXG4gIGZ1bmN0aW9uIGNyZWF0ZUluZGV4RmluZGVyKGRpciwgcHJlZGljYXRlRmluZCwgc29ydGVkSW5kZXgpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24oYXJyYXksIGl0ZW0sIGlkeCkge1xuICAgICAgdmFyIGkgPSAwLCBsZW5ndGggPSBnZXRMZW5ndGgoYXJyYXkpO1xuICAgICAgaWYgKHR5cGVvZiBpZHggPT0gJ251bWJlcicpIHtcbiAgICAgICAgaWYgKGRpciA+IDApIHtcbiAgICAgICAgICAgIGkgPSBpZHggPj0gMCA/IGlkeCA6IE1hdGgubWF4KGlkeCArIGxlbmd0aCwgaSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBsZW5ndGggPSBpZHggPj0gMCA/IE1hdGgubWluKGlkeCArIDEsIGxlbmd0aCkgOiBpZHggKyBsZW5ndGggKyAxO1xuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKHNvcnRlZEluZGV4ICYmIGlkeCAmJiBsZW5ndGgpIHtcbiAgICAgICAgaWR4ID0gc29ydGVkSW5kZXgoYXJyYXksIGl0ZW0pO1xuICAgICAgICByZXR1cm4gYXJyYXlbaWR4XSA9PT0gaXRlbSA/IGlkeCA6IC0xO1xuICAgICAgfVxuICAgICAgaWYgKGl0ZW0gIT09IGl0ZW0pIHtcbiAgICAgICAgaWR4ID0gcHJlZGljYXRlRmluZChzbGljZS5jYWxsKGFycmF5LCBpLCBsZW5ndGgpLCBfLmlzTmFOKTtcbiAgICAgICAgcmV0dXJuIGlkeCA+PSAwID8gaWR4ICsgaSA6IC0xO1xuICAgICAgfVxuICAgICAgZm9yIChpZHggPSBkaXIgPiAwID8gaSA6IGxlbmd0aCAtIDE7IGlkeCA+PSAwICYmIGlkeCA8IGxlbmd0aDsgaWR4ICs9IGRpcikge1xuICAgICAgICBpZiAoYXJyYXlbaWR4XSA9PT0gaXRlbSkgcmV0dXJuIGlkeDtcbiAgICAgIH1cbiAgICAgIHJldHVybiAtMTtcbiAgICB9O1xuICB9XG5cbiAgLy8gUmV0dXJuIHRoZSBwb3NpdGlvbiBvZiB0aGUgZmlyc3Qgb2NjdXJyZW5jZSBvZiBhbiBpdGVtIGluIGFuIGFycmF5LFxuICAvLyBvciAtMSBpZiB0aGUgaXRlbSBpcyBub3QgaW5jbHVkZWQgaW4gdGhlIGFycmF5LlxuICAvLyBJZiB0aGUgYXJyYXkgaXMgbGFyZ2UgYW5kIGFscmVhZHkgaW4gc29ydCBvcmRlciwgcGFzcyBgdHJ1ZWBcbiAgLy8gZm9yICoqaXNTb3J0ZWQqKiB0byB1c2UgYmluYXJ5IHNlYXJjaC5cbiAgXy5pbmRleE9mID0gY3JlYXRlSW5kZXhGaW5kZXIoMSwgXy5maW5kSW5kZXgsIF8uc29ydGVkSW5kZXgpO1xuICBfLmxhc3RJbmRleE9mID0gY3JlYXRlSW5kZXhGaW5kZXIoLTEsIF8uZmluZExhc3RJbmRleCk7XG5cbiAgLy8gR2VuZXJhdGUgYW4gaW50ZWdlciBBcnJheSBjb250YWluaW5nIGFuIGFyaXRobWV0aWMgcHJvZ3Jlc3Npb24uIEEgcG9ydCBvZlxuICAvLyB0aGUgbmF0aXZlIFB5dGhvbiBgcmFuZ2UoKWAgZnVuY3Rpb24uIFNlZVxuICAvLyBbdGhlIFB5dGhvbiBkb2N1bWVudGF0aW9uXShodHRwOi8vZG9jcy5weXRob24ub3JnL2xpYnJhcnkvZnVuY3Rpb25zLmh0bWwjcmFuZ2UpLlxuICBfLnJhbmdlID0gZnVuY3Rpb24oc3RhcnQsIHN0b3AsIHN0ZXApIHtcbiAgICBpZiAoc3RvcCA9PSBudWxsKSB7XG4gICAgICBzdG9wID0gc3RhcnQgfHwgMDtcbiAgICAgIHN0YXJ0ID0gMDtcbiAgICB9XG4gICAgc3RlcCA9IHN0ZXAgfHwgMTtcblxuICAgIHZhciBsZW5ndGggPSBNYXRoLm1heChNYXRoLmNlaWwoKHN0b3AgLSBzdGFydCkgLyBzdGVwKSwgMCk7XG4gICAgdmFyIHJhbmdlID0gQXJyYXkobGVuZ3RoKTtcblxuICAgIGZvciAodmFyIGlkeCA9IDA7IGlkeCA8IGxlbmd0aDsgaWR4KyssIHN0YXJ0ICs9IHN0ZXApIHtcbiAgICAgIHJhbmdlW2lkeF0gPSBzdGFydDtcbiAgICB9XG5cbiAgICByZXR1cm4gcmFuZ2U7XG4gIH07XG5cbiAgLy8gRnVuY3Rpb24gKGFoZW0pIEZ1bmN0aW9uc1xuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS1cblxuICAvLyBEZXRlcm1pbmVzIHdoZXRoZXIgdG8gZXhlY3V0ZSBhIGZ1bmN0aW9uIGFzIGEgY29uc3RydWN0b3JcbiAgLy8gb3IgYSBub3JtYWwgZnVuY3Rpb24gd2l0aCB0aGUgcHJvdmlkZWQgYXJndW1lbnRzXG4gIHZhciBleGVjdXRlQm91bmQgPSBmdW5jdGlvbihzb3VyY2VGdW5jLCBib3VuZEZ1bmMsIGNvbnRleHQsIGNhbGxpbmdDb250ZXh0LCBhcmdzKSB7XG4gICAgaWYgKCEoY2FsbGluZ0NvbnRleHQgaW5zdGFuY2VvZiBib3VuZEZ1bmMpKSByZXR1cm4gc291cmNlRnVuYy5hcHBseShjb250ZXh0LCBhcmdzKTtcbiAgICB2YXIgc2VsZiA9IGJhc2VDcmVhdGUoc291cmNlRnVuYy5wcm90b3R5cGUpO1xuICAgIHZhciByZXN1bHQgPSBzb3VyY2VGdW5jLmFwcGx5KHNlbGYsIGFyZ3MpO1xuICAgIGlmIChfLmlzT2JqZWN0KHJlc3VsdCkpIHJldHVybiByZXN1bHQ7XG4gICAgcmV0dXJuIHNlbGY7XG4gIH07XG5cbiAgLy8gQ3JlYXRlIGEgZnVuY3Rpb24gYm91bmQgdG8gYSBnaXZlbiBvYmplY3QgKGFzc2lnbmluZyBgdGhpc2AsIGFuZCBhcmd1bWVudHMsXG4gIC8vIG9wdGlvbmFsbHkpLiBEZWxlZ2F0ZXMgdG8gKipFQ01BU2NyaXB0IDUqKidzIG5hdGl2ZSBgRnVuY3Rpb24uYmluZGAgaWZcbiAgLy8gYXZhaWxhYmxlLlxuICBfLmJpbmQgPSBmdW5jdGlvbihmdW5jLCBjb250ZXh0KSB7XG4gICAgaWYgKG5hdGl2ZUJpbmQgJiYgZnVuYy5iaW5kID09PSBuYXRpdmVCaW5kKSByZXR1cm4gbmF0aXZlQmluZC5hcHBseShmdW5jLCBzbGljZS5jYWxsKGFyZ3VtZW50cywgMSkpO1xuICAgIGlmICghXy5pc0Z1bmN0aW9uKGZ1bmMpKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdCaW5kIG11c3QgYmUgY2FsbGVkIG9uIGEgZnVuY3Rpb24nKTtcbiAgICB2YXIgYXJncyA9IHNsaWNlLmNhbGwoYXJndW1lbnRzLCAyKTtcbiAgICB2YXIgYm91bmQgPSBmdW5jdGlvbigpIHtcbiAgICAgIHJldHVybiBleGVjdXRlQm91bmQoZnVuYywgYm91bmQsIGNvbnRleHQsIHRoaXMsIGFyZ3MuY29uY2F0KHNsaWNlLmNhbGwoYXJndW1lbnRzKSkpO1xuICAgIH07XG4gICAgcmV0dXJuIGJvdW5kO1xuICB9O1xuXG4gIC8vIFBhcnRpYWxseSBhcHBseSBhIGZ1bmN0aW9uIGJ5IGNyZWF0aW5nIGEgdmVyc2lvbiB0aGF0IGhhcyBoYWQgc29tZSBvZiBpdHNcbiAgLy8gYXJndW1lbnRzIHByZS1maWxsZWQsIHdpdGhvdXQgY2hhbmdpbmcgaXRzIGR5bmFtaWMgYHRoaXNgIGNvbnRleHQuIF8gYWN0c1xuICAvLyBhcyBhIHBsYWNlaG9sZGVyLCBhbGxvd2luZyBhbnkgY29tYmluYXRpb24gb2YgYXJndW1lbnRzIHRvIGJlIHByZS1maWxsZWQuXG4gIF8ucGFydGlhbCA9IGZ1bmN0aW9uKGZ1bmMpIHtcbiAgICB2YXIgYm91bmRBcmdzID0gc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpO1xuICAgIHZhciBib3VuZCA9IGZ1bmN0aW9uKCkge1xuICAgICAgdmFyIHBvc2l0aW9uID0gMCwgbGVuZ3RoID0gYm91bmRBcmdzLmxlbmd0aDtcbiAgICAgIHZhciBhcmdzID0gQXJyYXkobGVuZ3RoKTtcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgICAgYXJnc1tpXSA9IGJvdW5kQXJnc1tpXSA9PT0gXyA/IGFyZ3VtZW50c1twb3NpdGlvbisrXSA6IGJvdW5kQXJnc1tpXTtcbiAgICAgIH1cbiAgICAgIHdoaWxlIChwb3NpdGlvbiA8IGFyZ3VtZW50cy5sZW5ndGgpIGFyZ3MucHVzaChhcmd1bWVudHNbcG9zaXRpb24rK10pO1xuICAgICAgcmV0dXJuIGV4ZWN1dGVCb3VuZChmdW5jLCBib3VuZCwgdGhpcywgdGhpcywgYXJncyk7XG4gICAgfTtcbiAgICByZXR1cm4gYm91bmQ7XG4gIH07XG5cbiAgLy8gQmluZCBhIG51bWJlciBvZiBhbiBvYmplY3QncyBtZXRob2RzIHRvIHRoYXQgb2JqZWN0LiBSZW1haW5pbmcgYXJndW1lbnRzXG4gIC8vIGFyZSB0aGUgbWV0aG9kIG5hbWVzIHRvIGJlIGJvdW5kLiBVc2VmdWwgZm9yIGVuc3VyaW5nIHRoYXQgYWxsIGNhbGxiYWNrc1xuICAvLyBkZWZpbmVkIG9uIGFuIG9iamVjdCBiZWxvbmcgdG8gaXQuXG4gIF8uYmluZEFsbCA9IGZ1bmN0aW9uKG9iaikge1xuICAgIHZhciBpLCBsZW5ndGggPSBhcmd1bWVudHMubGVuZ3RoLCBrZXk7XG4gICAgaWYgKGxlbmd0aCA8PSAxKSB0aHJvdyBuZXcgRXJyb3IoJ2JpbmRBbGwgbXVzdCBiZSBwYXNzZWQgZnVuY3Rpb24gbmFtZXMnKTtcbiAgICBmb3IgKGkgPSAxOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgIGtleSA9IGFyZ3VtZW50c1tpXTtcbiAgICAgIG9ialtrZXldID0gXy5iaW5kKG9ialtrZXldLCBvYmopO1xuICAgIH1cbiAgICByZXR1cm4gb2JqO1xuICB9O1xuXG4gIC8vIE1lbW9pemUgYW4gZXhwZW5zaXZlIGZ1bmN0aW9uIGJ5IHN0b3JpbmcgaXRzIHJlc3VsdHMuXG4gIF8ubWVtb2l6ZSA9IGZ1bmN0aW9uKGZ1bmMsIGhhc2hlcikge1xuICAgIHZhciBtZW1vaXplID0gZnVuY3Rpb24oa2V5KSB7XG4gICAgICB2YXIgY2FjaGUgPSBtZW1vaXplLmNhY2hlO1xuICAgICAgdmFyIGFkZHJlc3MgPSAnJyArIChoYXNoZXIgPyBoYXNoZXIuYXBwbHkodGhpcywgYXJndW1lbnRzKSA6IGtleSk7XG4gICAgICBpZiAoIV8uaGFzKGNhY2hlLCBhZGRyZXNzKSkgY2FjaGVbYWRkcmVzc10gPSBmdW5jLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICByZXR1cm4gY2FjaGVbYWRkcmVzc107XG4gICAgfTtcbiAgICBtZW1vaXplLmNhY2hlID0ge307XG4gICAgcmV0dXJuIG1lbW9pemU7XG4gIH07XG5cbiAgLy8gRGVsYXlzIGEgZnVuY3Rpb24gZm9yIHRoZSBnaXZlbiBudW1iZXIgb2YgbWlsbGlzZWNvbmRzLCBhbmQgdGhlbiBjYWxsc1xuICAvLyBpdCB3aXRoIHRoZSBhcmd1bWVudHMgc3VwcGxpZWQuXG4gIF8uZGVsYXkgPSBmdW5jdGlvbihmdW5jLCB3YWl0KSB7XG4gICAgdmFyIGFyZ3MgPSBzbGljZS5jYWxsKGFyZ3VtZW50cywgMik7XG4gICAgcmV0dXJuIHNldFRpbWVvdXQoZnVuY3Rpb24oKXtcbiAgICAgIHJldHVybiBmdW5jLmFwcGx5KG51bGwsIGFyZ3MpO1xuICAgIH0sIHdhaXQpO1xuICB9O1xuXG4gIC8vIERlZmVycyBhIGZ1bmN0aW9uLCBzY2hlZHVsaW5nIGl0IHRvIHJ1biBhZnRlciB0aGUgY3VycmVudCBjYWxsIHN0YWNrIGhhc1xuICAvLyBjbGVhcmVkLlxuICBfLmRlZmVyID0gXy5wYXJ0aWFsKF8uZGVsYXksIF8sIDEpO1xuXG4gIC8vIFJldHVybnMgYSBmdW5jdGlvbiwgdGhhdCwgd2hlbiBpbnZva2VkLCB3aWxsIG9ubHkgYmUgdHJpZ2dlcmVkIGF0IG1vc3Qgb25jZVxuICAvLyBkdXJpbmcgYSBnaXZlbiB3aW5kb3cgb2YgdGltZS4gTm9ybWFsbHksIHRoZSB0aHJvdHRsZWQgZnVuY3Rpb24gd2lsbCBydW5cbiAgLy8gYXMgbXVjaCBhcyBpdCBjYW4sIHdpdGhvdXQgZXZlciBnb2luZyBtb3JlIHRoYW4gb25jZSBwZXIgYHdhaXRgIGR1cmF0aW9uO1xuICAvLyBidXQgaWYgeW91J2QgbGlrZSB0byBkaXNhYmxlIHRoZSBleGVjdXRpb24gb24gdGhlIGxlYWRpbmcgZWRnZSwgcGFzc1xuICAvLyBge2xlYWRpbmc6IGZhbHNlfWAuIFRvIGRpc2FibGUgZXhlY3V0aW9uIG9uIHRoZSB0cmFpbGluZyBlZGdlLCBkaXR0by5cbiAgXy50aHJvdHRsZSA9IGZ1bmN0aW9uKGZ1bmMsIHdhaXQsIG9wdGlvbnMpIHtcbiAgICB2YXIgY29udGV4dCwgYXJncywgcmVzdWx0O1xuICAgIHZhciB0aW1lb3V0ID0gbnVsbDtcbiAgICB2YXIgcHJldmlvdXMgPSAwO1xuICAgIGlmICghb3B0aW9ucykgb3B0aW9ucyA9IHt9O1xuICAgIHZhciBsYXRlciA9IGZ1bmN0aW9uKCkge1xuICAgICAgcHJldmlvdXMgPSBvcHRpb25zLmxlYWRpbmcgPT09IGZhbHNlID8gMCA6IF8ubm93KCk7XG4gICAgICB0aW1lb3V0ID0gbnVsbDtcbiAgICAgIHJlc3VsdCA9IGZ1bmMuYXBwbHkoY29udGV4dCwgYXJncyk7XG4gICAgICBpZiAoIXRpbWVvdXQpIGNvbnRleHQgPSBhcmdzID0gbnVsbDtcbiAgICB9O1xuICAgIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICAgIHZhciBub3cgPSBfLm5vdygpO1xuICAgICAgaWYgKCFwcmV2aW91cyAmJiBvcHRpb25zLmxlYWRpbmcgPT09IGZhbHNlKSBwcmV2aW91cyA9IG5vdztcbiAgICAgIHZhciByZW1haW5pbmcgPSB3YWl0IC0gKG5vdyAtIHByZXZpb3VzKTtcbiAgICAgIGNvbnRleHQgPSB0aGlzO1xuICAgICAgYXJncyA9IGFyZ3VtZW50cztcbiAgICAgIGlmIChyZW1haW5pbmcgPD0gMCB8fCByZW1haW5pbmcgPiB3YWl0KSB7XG4gICAgICAgIGlmICh0aW1lb3V0KSB7XG4gICAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVvdXQpO1xuICAgICAgICAgIHRpbWVvdXQgPSBudWxsO1xuICAgICAgICB9XG4gICAgICAgIHByZXZpb3VzID0gbm93O1xuICAgICAgICByZXN1bHQgPSBmdW5jLmFwcGx5KGNvbnRleHQsIGFyZ3MpO1xuICAgICAgICBpZiAoIXRpbWVvdXQpIGNvbnRleHQgPSBhcmdzID0gbnVsbDtcbiAgICAgIH0gZWxzZSBpZiAoIXRpbWVvdXQgJiYgb3B0aW9ucy50cmFpbGluZyAhPT0gZmFsc2UpIHtcbiAgICAgICAgdGltZW91dCA9IHNldFRpbWVvdXQobGF0ZXIsIHJlbWFpbmluZyk7XG4gICAgICB9XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH07XG4gIH07XG5cbiAgLy8gUmV0dXJucyBhIGZ1bmN0aW9uLCB0aGF0LCBhcyBsb25nIGFzIGl0IGNvbnRpbnVlcyB0byBiZSBpbnZva2VkLCB3aWxsIG5vdFxuICAvLyBiZSB0cmlnZ2VyZWQuIFRoZSBmdW5jdGlvbiB3aWxsIGJlIGNhbGxlZCBhZnRlciBpdCBzdG9wcyBiZWluZyBjYWxsZWQgZm9yXG4gIC8vIE4gbWlsbGlzZWNvbmRzLiBJZiBgaW1tZWRpYXRlYCBpcyBwYXNzZWQsIHRyaWdnZXIgdGhlIGZ1bmN0aW9uIG9uIHRoZVxuICAvLyBsZWFkaW5nIGVkZ2UsIGluc3RlYWQgb2YgdGhlIHRyYWlsaW5nLlxuICBfLmRlYm91bmNlID0gZnVuY3Rpb24oZnVuYywgd2FpdCwgaW1tZWRpYXRlKSB7XG4gICAgdmFyIHRpbWVvdXQsIGFyZ3MsIGNvbnRleHQsIHRpbWVzdGFtcCwgcmVzdWx0O1xuXG4gICAgdmFyIGxhdGVyID0gZnVuY3Rpb24oKSB7XG4gICAgICB2YXIgbGFzdCA9IF8ubm93KCkgLSB0aW1lc3RhbXA7XG5cbiAgICAgIGlmIChsYXN0IDwgd2FpdCAmJiBsYXN0ID49IDApIHtcbiAgICAgICAgdGltZW91dCA9IHNldFRpbWVvdXQobGF0ZXIsIHdhaXQgLSBsYXN0KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRpbWVvdXQgPSBudWxsO1xuICAgICAgICBpZiAoIWltbWVkaWF0ZSkge1xuICAgICAgICAgIHJlc3VsdCA9IGZ1bmMuYXBwbHkoY29udGV4dCwgYXJncyk7XG4gICAgICAgICAgaWYgKCF0aW1lb3V0KSBjb250ZXh0ID0gYXJncyA9IG51bGw7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuXG4gICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgICAgY29udGV4dCA9IHRoaXM7XG4gICAgICBhcmdzID0gYXJndW1lbnRzO1xuICAgICAgdGltZXN0YW1wID0gXy5ub3coKTtcbiAgICAgIHZhciBjYWxsTm93ID0gaW1tZWRpYXRlICYmICF0aW1lb3V0O1xuICAgICAgaWYgKCF0aW1lb3V0KSB0aW1lb3V0ID0gc2V0VGltZW91dChsYXRlciwgd2FpdCk7XG4gICAgICBpZiAoY2FsbE5vdykge1xuICAgICAgICByZXN1bHQgPSBmdW5jLmFwcGx5KGNvbnRleHQsIGFyZ3MpO1xuICAgICAgICBjb250ZXh0ID0gYXJncyA9IG51bGw7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfTtcbiAgfTtcblxuICAvLyBSZXR1cm5zIHRoZSBmaXJzdCBmdW5jdGlvbiBwYXNzZWQgYXMgYW4gYXJndW1lbnQgdG8gdGhlIHNlY29uZCxcbiAgLy8gYWxsb3dpbmcgeW91IHRvIGFkanVzdCBhcmd1bWVudHMsIHJ1biBjb2RlIGJlZm9yZSBhbmQgYWZ0ZXIsIGFuZFxuICAvLyBjb25kaXRpb25hbGx5IGV4ZWN1dGUgdGhlIG9yaWdpbmFsIGZ1bmN0aW9uLlxuICBfLndyYXAgPSBmdW5jdGlvbihmdW5jLCB3cmFwcGVyKSB7XG4gICAgcmV0dXJuIF8ucGFydGlhbCh3cmFwcGVyLCBmdW5jKTtcbiAgfTtcblxuICAvLyBSZXR1cm5zIGEgbmVnYXRlZCB2ZXJzaW9uIG9mIHRoZSBwYXNzZWQtaW4gcHJlZGljYXRlLlxuICBfLm5lZ2F0ZSA9IGZ1bmN0aW9uKHByZWRpY2F0ZSkge1xuICAgIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICAgIHJldHVybiAhcHJlZGljYXRlLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgfTtcbiAgfTtcblxuICAvLyBSZXR1cm5zIGEgZnVuY3Rpb24gdGhhdCBpcyB0aGUgY29tcG9zaXRpb24gb2YgYSBsaXN0IG9mIGZ1bmN0aW9ucywgZWFjaFxuICAvLyBjb25zdW1pbmcgdGhlIHJldHVybiB2YWx1ZSBvZiB0aGUgZnVuY3Rpb24gdGhhdCBmb2xsb3dzLlxuICBfLmNvbXBvc2UgPSBmdW5jdGlvbigpIHtcbiAgICB2YXIgYXJncyA9IGFyZ3VtZW50cztcbiAgICB2YXIgc3RhcnQgPSBhcmdzLmxlbmd0aCAtIDE7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgICAgdmFyIGkgPSBzdGFydDtcbiAgICAgIHZhciByZXN1bHQgPSBhcmdzW3N0YXJ0XS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgd2hpbGUgKGktLSkgcmVzdWx0ID0gYXJnc1tpXS5jYWxsKHRoaXMsIHJlc3VsdCk7XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH07XG4gIH07XG5cbiAgLy8gUmV0dXJucyBhIGZ1bmN0aW9uIHRoYXQgd2lsbCBvbmx5IGJlIGV4ZWN1dGVkIG9uIGFuZCBhZnRlciB0aGUgTnRoIGNhbGwuXG4gIF8uYWZ0ZXIgPSBmdW5jdGlvbih0aW1lcywgZnVuYykge1xuICAgIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICAgIGlmICgtLXRpbWVzIDwgMSkge1xuICAgICAgICByZXR1cm4gZnVuYy5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgfVxuICAgIH07XG4gIH07XG5cbiAgLy8gUmV0dXJucyBhIGZ1bmN0aW9uIHRoYXQgd2lsbCBvbmx5IGJlIGV4ZWN1dGVkIHVwIHRvIChidXQgbm90IGluY2x1ZGluZykgdGhlIE50aCBjYWxsLlxuICBfLmJlZm9yZSA9IGZ1bmN0aW9uKHRpbWVzLCBmdW5jKSB7XG4gICAgdmFyIG1lbW87XG4gICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgICAgaWYgKC0tdGltZXMgPiAwKSB7XG4gICAgICAgIG1lbW8gPSBmdW5jLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICB9XG4gICAgICBpZiAodGltZXMgPD0gMSkgZnVuYyA9IG51bGw7XG4gICAgICByZXR1cm4gbWVtbztcbiAgICB9O1xuICB9O1xuXG4gIC8vIFJldHVybnMgYSBmdW5jdGlvbiB0aGF0IHdpbGwgYmUgZXhlY3V0ZWQgYXQgbW9zdCBvbmUgdGltZSwgbm8gbWF0dGVyIGhvd1xuICAvLyBvZnRlbiB5b3UgY2FsbCBpdC4gVXNlZnVsIGZvciBsYXp5IGluaXRpYWxpemF0aW9uLlxuICBfLm9uY2UgPSBfLnBhcnRpYWwoXy5iZWZvcmUsIDIpO1xuXG4gIC8vIE9iamVjdCBGdW5jdGlvbnNcbiAgLy8gLS0tLS0tLS0tLS0tLS0tLVxuXG4gIC8vIEtleXMgaW4gSUUgPCA5IHRoYXQgd29uJ3QgYmUgaXRlcmF0ZWQgYnkgYGZvciBrZXkgaW4gLi4uYCBhbmQgdGh1cyBtaXNzZWQuXG4gIHZhciBoYXNFbnVtQnVnID0gIXt0b1N0cmluZzogbnVsbH0ucHJvcGVydHlJc0VudW1lcmFibGUoJ3RvU3RyaW5nJyk7XG4gIHZhciBub25FbnVtZXJhYmxlUHJvcHMgPSBbJ3ZhbHVlT2YnLCAnaXNQcm90b3R5cGVPZicsICd0b1N0cmluZycsXG4gICAgICAgICAgICAgICAgICAgICAgJ3Byb3BlcnR5SXNFbnVtZXJhYmxlJywgJ2hhc093blByb3BlcnR5JywgJ3RvTG9jYWxlU3RyaW5nJ107XG5cbiAgZnVuY3Rpb24gY29sbGVjdE5vbkVudW1Qcm9wcyhvYmosIGtleXMpIHtcbiAgICB2YXIgbm9uRW51bUlkeCA9IG5vbkVudW1lcmFibGVQcm9wcy5sZW5ndGg7XG4gICAgdmFyIGNvbnN0cnVjdG9yID0gb2JqLmNvbnN0cnVjdG9yO1xuICAgIHZhciBwcm90byA9IChfLmlzRnVuY3Rpb24oY29uc3RydWN0b3IpICYmIGNvbnN0cnVjdG9yLnByb3RvdHlwZSkgfHwgT2JqUHJvdG87XG5cbiAgICAvLyBDb25zdHJ1Y3RvciBpcyBhIHNwZWNpYWwgY2FzZS5cbiAgICB2YXIgcHJvcCA9ICdjb25zdHJ1Y3Rvcic7XG4gICAgaWYgKF8uaGFzKG9iaiwgcHJvcCkgJiYgIV8uY29udGFpbnMoa2V5cywgcHJvcCkpIGtleXMucHVzaChwcm9wKTtcblxuICAgIHdoaWxlIChub25FbnVtSWR4LS0pIHtcbiAgICAgIHByb3AgPSBub25FbnVtZXJhYmxlUHJvcHNbbm9uRW51bUlkeF07XG4gICAgICBpZiAocHJvcCBpbiBvYmogJiYgb2JqW3Byb3BdICE9PSBwcm90b1twcm9wXSAmJiAhXy5jb250YWlucyhrZXlzLCBwcm9wKSkge1xuICAgICAgICBrZXlzLnB1c2gocHJvcCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gUmV0cmlldmUgdGhlIG5hbWVzIG9mIGFuIG9iamVjdCdzIG93biBwcm9wZXJ0aWVzLlxuICAvLyBEZWxlZ2F0ZXMgdG8gKipFQ01BU2NyaXB0IDUqKidzIG5hdGl2ZSBgT2JqZWN0LmtleXNgXG4gIF8ua2V5cyA9IGZ1bmN0aW9uKG9iaikge1xuICAgIGlmICghXy5pc09iamVjdChvYmopKSByZXR1cm4gW107XG4gICAgaWYgKG5hdGl2ZUtleXMpIHJldHVybiBuYXRpdmVLZXlzKG9iaik7XG4gICAgdmFyIGtleXMgPSBbXTtcbiAgICBmb3IgKHZhciBrZXkgaW4gb2JqKSBpZiAoXy5oYXMob2JqLCBrZXkpKSBrZXlzLnB1c2goa2V5KTtcbiAgICAvLyBBaGVtLCBJRSA8IDkuXG4gICAgaWYgKGhhc0VudW1CdWcpIGNvbGxlY3ROb25FbnVtUHJvcHMob2JqLCBrZXlzKTtcbiAgICByZXR1cm4ga2V5cztcbiAgfTtcblxuICAvLyBSZXRyaWV2ZSBhbGwgdGhlIHByb3BlcnR5IG5hbWVzIG9mIGFuIG9iamVjdC5cbiAgXy5hbGxLZXlzID0gZnVuY3Rpb24ob2JqKSB7XG4gICAgaWYgKCFfLmlzT2JqZWN0KG9iaikpIHJldHVybiBbXTtcbiAgICB2YXIga2V5cyA9IFtdO1xuICAgIGZvciAodmFyIGtleSBpbiBvYmopIGtleXMucHVzaChrZXkpO1xuICAgIC8vIEFoZW0sIElFIDwgOS5cbiAgICBpZiAoaGFzRW51bUJ1ZykgY29sbGVjdE5vbkVudW1Qcm9wcyhvYmosIGtleXMpO1xuICAgIHJldHVybiBrZXlzO1xuICB9O1xuXG4gIC8vIFJldHJpZXZlIHRoZSB2YWx1ZXMgb2YgYW4gb2JqZWN0J3MgcHJvcGVydGllcy5cbiAgXy52YWx1ZXMgPSBmdW5jdGlvbihvYmopIHtcbiAgICB2YXIga2V5cyA9IF8ua2V5cyhvYmopO1xuICAgIHZhciBsZW5ndGggPSBrZXlzLmxlbmd0aDtcbiAgICB2YXIgdmFsdWVzID0gQXJyYXkobGVuZ3RoKTtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgICB2YWx1ZXNbaV0gPSBvYmpba2V5c1tpXV07XG4gICAgfVxuICAgIHJldHVybiB2YWx1ZXM7XG4gIH07XG5cbiAgLy8gUmV0dXJucyB0aGUgcmVzdWx0cyBvZiBhcHBseWluZyB0aGUgaXRlcmF0ZWUgdG8gZWFjaCBlbGVtZW50IG9mIHRoZSBvYmplY3RcbiAgLy8gSW4gY29udHJhc3QgdG8gXy5tYXAgaXQgcmV0dXJucyBhbiBvYmplY3RcbiAgXy5tYXBPYmplY3QgPSBmdW5jdGlvbihvYmosIGl0ZXJhdGVlLCBjb250ZXh0KSB7XG4gICAgaXRlcmF0ZWUgPSBjYihpdGVyYXRlZSwgY29udGV4dCk7XG4gICAgdmFyIGtleXMgPSAgXy5rZXlzKG9iaiksXG4gICAgICAgICAgbGVuZ3RoID0ga2V5cy5sZW5ndGgsXG4gICAgICAgICAgcmVzdWx0cyA9IHt9LFxuICAgICAgICAgIGN1cnJlbnRLZXk7XG4gICAgICBmb3IgKHZhciBpbmRleCA9IDA7IGluZGV4IDwgbGVuZ3RoOyBpbmRleCsrKSB7XG4gICAgICAgIGN1cnJlbnRLZXkgPSBrZXlzW2luZGV4XTtcbiAgICAgICAgcmVzdWx0c1tjdXJyZW50S2V5XSA9IGl0ZXJhdGVlKG9ialtjdXJyZW50S2V5XSwgY3VycmVudEtleSwgb2JqKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXN1bHRzO1xuICB9O1xuXG4gIC8vIENvbnZlcnQgYW4gb2JqZWN0IGludG8gYSBsaXN0IG9mIGBba2V5LCB2YWx1ZV1gIHBhaXJzLlxuICBfLnBhaXJzID0gZnVuY3Rpb24ob2JqKSB7XG4gICAgdmFyIGtleXMgPSBfLmtleXMob2JqKTtcbiAgICB2YXIgbGVuZ3RoID0ga2V5cy5sZW5ndGg7XG4gICAgdmFyIHBhaXJzID0gQXJyYXkobGVuZ3RoKTtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgICBwYWlyc1tpXSA9IFtrZXlzW2ldLCBvYmpba2V5c1tpXV1dO1xuICAgIH1cbiAgICByZXR1cm4gcGFpcnM7XG4gIH07XG5cbiAgLy8gSW52ZXJ0IHRoZSBrZXlzIGFuZCB2YWx1ZXMgb2YgYW4gb2JqZWN0LiBUaGUgdmFsdWVzIG11c3QgYmUgc2VyaWFsaXphYmxlLlxuICBfLmludmVydCA9IGZ1bmN0aW9uKG9iaikge1xuICAgIHZhciByZXN1bHQgPSB7fTtcbiAgICB2YXIga2V5cyA9IF8ua2V5cyhvYmopO1xuICAgIGZvciAodmFyIGkgPSAwLCBsZW5ndGggPSBrZXlzLmxlbmd0aDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgICByZXN1bHRbb2JqW2tleXNbaV1dXSA9IGtleXNbaV07XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG4gIH07XG5cbiAgLy8gUmV0dXJuIGEgc29ydGVkIGxpc3Qgb2YgdGhlIGZ1bmN0aW9uIG5hbWVzIGF2YWlsYWJsZSBvbiB0aGUgb2JqZWN0LlxuICAvLyBBbGlhc2VkIGFzIGBtZXRob2RzYFxuICBfLmZ1bmN0aW9ucyA9IF8ubWV0aG9kcyA9IGZ1bmN0aW9uKG9iaikge1xuICAgIHZhciBuYW1lcyA9IFtdO1xuICAgIGZvciAodmFyIGtleSBpbiBvYmopIHtcbiAgICAgIGlmIChfLmlzRnVuY3Rpb24ob2JqW2tleV0pKSBuYW1lcy5wdXNoKGtleSk7XG4gICAgfVxuICAgIHJldHVybiBuYW1lcy5zb3J0KCk7XG4gIH07XG5cbiAgLy8gRXh0ZW5kIGEgZ2l2ZW4gb2JqZWN0IHdpdGggYWxsIHRoZSBwcm9wZXJ0aWVzIGluIHBhc3NlZC1pbiBvYmplY3QocykuXG4gIF8uZXh0ZW5kID0gY3JlYXRlQXNzaWduZXIoXy5hbGxLZXlzKTtcblxuICAvLyBBc3NpZ25zIGEgZ2l2ZW4gb2JqZWN0IHdpdGggYWxsIHRoZSBvd24gcHJvcGVydGllcyBpbiB0aGUgcGFzc2VkLWluIG9iamVjdChzKVxuICAvLyAoaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvT2JqZWN0L2Fzc2lnbilcbiAgXy5leHRlbmRPd24gPSBfLmFzc2lnbiA9IGNyZWF0ZUFzc2lnbmVyKF8ua2V5cyk7XG5cbiAgLy8gUmV0dXJucyB0aGUgZmlyc3Qga2V5IG9uIGFuIG9iamVjdCB0aGF0IHBhc3NlcyBhIHByZWRpY2F0ZSB0ZXN0XG4gIF8uZmluZEtleSA9IGZ1bmN0aW9uKG9iaiwgcHJlZGljYXRlLCBjb250ZXh0KSB7XG4gICAgcHJlZGljYXRlID0gY2IocHJlZGljYXRlLCBjb250ZXh0KTtcbiAgICB2YXIga2V5cyA9IF8ua2V5cyhvYmopLCBrZXk7XG4gICAgZm9yICh2YXIgaSA9IDAsIGxlbmd0aCA9IGtleXMubGVuZ3RoOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgIGtleSA9IGtleXNbaV07XG4gICAgICBpZiAocHJlZGljYXRlKG9ialtrZXldLCBrZXksIG9iaikpIHJldHVybiBrZXk7XG4gICAgfVxuICB9O1xuXG4gIC8vIFJldHVybiBhIGNvcHkgb2YgdGhlIG9iamVjdCBvbmx5IGNvbnRhaW5pbmcgdGhlIHdoaXRlbGlzdGVkIHByb3BlcnRpZXMuXG4gIF8ucGljayA9IGZ1bmN0aW9uKG9iamVjdCwgb2l0ZXJhdGVlLCBjb250ZXh0KSB7XG4gICAgdmFyIHJlc3VsdCA9IHt9LCBvYmogPSBvYmplY3QsIGl0ZXJhdGVlLCBrZXlzO1xuICAgIGlmIChvYmogPT0gbnVsbCkgcmV0dXJuIHJlc3VsdDtcbiAgICBpZiAoXy5pc0Z1bmN0aW9uKG9pdGVyYXRlZSkpIHtcbiAgICAgIGtleXMgPSBfLmFsbEtleXMob2JqKTtcbiAgICAgIGl0ZXJhdGVlID0gb3B0aW1pemVDYihvaXRlcmF0ZWUsIGNvbnRleHQpO1xuICAgIH0gZWxzZSB7XG4gICAgICBrZXlzID0gZmxhdHRlbihhcmd1bWVudHMsIGZhbHNlLCBmYWxzZSwgMSk7XG4gICAgICBpdGVyYXRlZSA9IGZ1bmN0aW9uKHZhbHVlLCBrZXksIG9iaikgeyByZXR1cm4ga2V5IGluIG9iajsgfTtcbiAgICAgIG9iaiA9IE9iamVjdChvYmopO1xuICAgIH1cbiAgICBmb3IgKHZhciBpID0gMCwgbGVuZ3RoID0ga2V5cy5sZW5ndGg7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgICAgdmFyIGtleSA9IGtleXNbaV07XG4gICAgICB2YXIgdmFsdWUgPSBvYmpba2V5XTtcbiAgICAgIGlmIChpdGVyYXRlZSh2YWx1ZSwga2V5LCBvYmopKSByZXN1bHRba2V5XSA9IHZhbHVlO1xuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9O1xuXG4gICAvLyBSZXR1cm4gYSBjb3B5IG9mIHRoZSBvYmplY3Qgd2l0aG91dCB0aGUgYmxhY2tsaXN0ZWQgcHJvcGVydGllcy5cbiAgXy5vbWl0ID0gZnVuY3Rpb24ob2JqLCBpdGVyYXRlZSwgY29udGV4dCkge1xuICAgIGlmIChfLmlzRnVuY3Rpb24oaXRlcmF0ZWUpKSB7XG4gICAgICBpdGVyYXRlZSA9IF8ubmVnYXRlKGl0ZXJhdGVlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdmFyIGtleXMgPSBfLm1hcChmbGF0dGVuKGFyZ3VtZW50cywgZmFsc2UsIGZhbHNlLCAxKSwgU3RyaW5nKTtcbiAgICAgIGl0ZXJhdGVlID0gZnVuY3Rpb24odmFsdWUsIGtleSkge1xuICAgICAgICByZXR1cm4gIV8uY29udGFpbnMoa2V5cywga2V5KTtcbiAgICAgIH07XG4gICAgfVxuICAgIHJldHVybiBfLnBpY2sob2JqLCBpdGVyYXRlZSwgY29udGV4dCk7XG4gIH07XG5cbiAgLy8gRmlsbCBpbiBhIGdpdmVuIG9iamVjdCB3aXRoIGRlZmF1bHQgcHJvcGVydGllcy5cbiAgXy5kZWZhdWx0cyA9IGNyZWF0ZUFzc2lnbmVyKF8uYWxsS2V5cywgdHJ1ZSk7XG5cbiAgLy8gQ3JlYXRlcyBhbiBvYmplY3QgdGhhdCBpbmhlcml0cyBmcm9tIHRoZSBnaXZlbiBwcm90b3R5cGUgb2JqZWN0LlxuICAvLyBJZiBhZGRpdGlvbmFsIHByb3BlcnRpZXMgYXJlIHByb3ZpZGVkIHRoZW4gdGhleSB3aWxsIGJlIGFkZGVkIHRvIHRoZVxuICAvLyBjcmVhdGVkIG9iamVjdC5cbiAgXy5jcmVhdGUgPSBmdW5jdGlvbihwcm90b3R5cGUsIHByb3BzKSB7XG4gICAgdmFyIHJlc3VsdCA9IGJhc2VDcmVhdGUocHJvdG90eXBlKTtcbiAgICBpZiAocHJvcHMpIF8uZXh0ZW5kT3duKHJlc3VsdCwgcHJvcHMpO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH07XG5cbiAgLy8gQ3JlYXRlIGEgKHNoYWxsb3ctY2xvbmVkKSBkdXBsaWNhdGUgb2YgYW4gb2JqZWN0LlxuICBfLmNsb25lID0gZnVuY3Rpb24ob2JqKSB7XG4gICAgaWYgKCFfLmlzT2JqZWN0KG9iaikpIHJldHVybiBvYmo7XG4gICAgcmV0dXJuIF8uaXNBcnJheShvYmopID8gb2JqLnNsaWNlKCkgOiBfLmV4dGVuZCh7fSwgb2JqKTtcbiAgfTtcblxuICAvLyBJbnZva2VzIGludGVyY2VwdG9yIHdpdGggdGhlIG9iaiwgYW5kIHRoZW4gcmV0dXJucyBvYmouXG4gIC8vIFRoZSBwcmltYXJ5IHB1cnBvc2Ugb2YgdGhpcyBtZXRob2QgaXMgdG8gXCJ0YXAgaW50b1wiIGEgbWV0aG9kIGNoYWluLCBpblxuICAvLyBvcmRlciB0byBwZXJmb3JtIG9wZXJhdGlvbnMgb24gaW50ZXJtZWRpYXRlIHJlc3VsdHMgd2l0aGluIHRoZSBjaGFpbi5cbiAgXy50YXAgPSBmdW5jdGlvbihvYmosIGludGVyY2VwdG9yKSB7XG4gICAgaW50ZXJjZXB0b3Iob2JqKTtcbiAgICByZXR1cm4gb2JqO1xuICB9O1xuXG4gIC8vIFJldHVybnMgd2hldGhlciBhbiBvYmplY3QgaGFzIGEgZ2l2ZW4gc2V0IG9mIGBrZXk6dmFsdWVgIHBhaXJzLlxuICBfLmlzTWF0Y2ggPSBmdW5jdGlvbihvYmplY3QsIGF0dHJzKSB7XG4gICAgdmFyIGtleXMgPSBfLmtleXMoYXR0cnMpLCBsZW5ndGggPSBrZXlzLmxlbmd0aDtcbiAgICBpZiAob2JqZWN0ID09IG51bGwpIHJldHVybiAhbGVuZ3RoO1xuICAgIHZhciBvYmogPSBPYmplY3Qob2JqZWN0KTtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIga2V5ID0ga2V5c1tpXTtcbiAgICAgIGlmIChhdHRyc1trZXldICE9PSBvYmpba2V5XSB8fCAhKGtleSBpbiBvYmopKSByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIHJldHVybiB0cnVlO1xuICB9O1xuXG5cbiAgLy8gSW50ZXJuYWwgcmVjdXJzaXZlIGNvbXBhcmlzb24gZnVuY3Rpb24gZm9yIGBpc0VxdWFsYC5cbiAgdmFyIGVxID0gZnVuY3Rpb24oYSwgYiwgYVN0YWNrLCBiU3RhY2spIHtcbiAgICAvLyBJZGVudGljYWwgb2JqZWN0cyBhcmUgZXF1YWwuIGAwID09PSAtMGAsIGJ1dCB0aGV5IGFyZW4ndCBpZGVudGljYWwuXG4gICAgLy8gU2VlIHRoZSBbSGFybW9ueSBgZWdhbGAgcHJvcG9zYWxdKGh0dHA6Ly93aWtpLmVjbWFzY3JpcHQub3JnL2Rva3UucGhwP2lkPWhhcm1vbnk6ZWdhbCkuXG4gICAgaWYgKGEgPT09IGIpIHJldHVybiBhICE9PSAwIHx8IDEgLyBhID09PSAxIC8gYjtcbiAgICAvLyBBIHN0cmljdCBjb21wYXJpc29uIGlzIG5lY2Vzc2FyeSBiZWNhdXNlIGBudWxsID09IHVuZGVmaW5lZGAuXG4gICAgaWYgKGEgPT0gbnVsbCB8fCBiID09IG51bGwpIHJldHVybiBhID09PSBiO1xuICAgIC8vIFVud3JhcCBhbnkgd3JhcHBlZCBvYmplY3RzLlxuICAgIGlmIChhIGluc3RhbmNlb2YgXykgYSA9IGEuX3dyYXBwZWQ7XG4gICAgaWYgKGIgaW5zdGFuY2VvZiBfKSBiID0gYi5fd3JhcHBlZDtcbiAgICAvLyBDb21wYXJlIGBbW0NsYXNzXV1gIG5hbWVzLlxuICAgIHZhciBjbGFzc05hbWUgPSB0b1N0cmluZy5jYWxsKGEpO1xuICAgIGlmIChjbGFzc05hbWUgIT09IHRvU3RyaW5nLmNhbGwoYikpIHJldHVybiBmYWxzZTtcbiAgICBzd2l0Y2ggKGNsYXNzTmFtZSkge1xuICAgICAgLy8gU3RyaW5ncywgbnVtYmVycywgcmVndWxhciBleHByZXNzaW9ucywgZGF0ZXMsIGFuZCBib29sZWFucyBhcmUgY29tcGFyZWQgYnkgdmFsdWUuXG4gICAgICBjYXNlICdbb2JqZWN0IFJlZ0V4cF0nOlxuICAgICAgLy8gUmVnRXhwcyBhcmUgY29lcmNlZCB0byBzdHJpbmdzIGZvciBjb21wYXJpc29uIChOb3RlOiAnJyArIC9hL2kgPT09ICcvYS9pJylcbiAgICAgIGNhc2UgJ1tvYmplY3QgU3RyaW5nXSc6XG4gICAgICAgIC8vIFByaW1pdGl2ZXMgYW5kIHRoZWlyIGNvcnJlc3BvbmRpbmcgb2JqZWN0IHdyYXBwZXJzIGFyZSBlcXVpdmFsZW50OyB0aHVzLCBgXCI1XCJgIGlzXG4gICAgICAgIC8vIGVxdWl2YWxlbnQgdG8gYG5ldyBTdHJpbmcoXCI1XCIpYC5cbiAgICAgICAgcmV0dXJuICcnICsgYSA9PT0gJycgKyBiO1xuICAgICAgY2FzZSAnW29iamVjdCBOdW1iZXJdJzpcbiAgICAgICAgLy8gYE5hTmBzIGFyZSBlcXVpdmFsZW50LCBidXQgbm9uLXJlZmxleGl2ZS5cbiAgICAgICAgLy8gT2JqZWN0KE5hTikgaXMgZXF1aXZhbGVudCB0byBOYU5cbiAgICAgICAgaWYgKCthICE9PSArYSkgcmV0dXJuICtiICE9PSArYjtcbiAgICAgICAgLy8gQW4gYGVnYWxgIGNvbXBhcmlzb24gaXMgcGVyZm9ybWVkIGZvciBvdGhlciBudW1lcmljIHZhbHVlcy5cbiAgICAgICAgcmV0dXJuICthID09PSAwID8gMSAvICthID09PSAxIC8gYiA6ICthID09PSArYjtcbiAgICAgIGNhc2UgJ1tvYmplY3QgRGF0ZV0nOlxuICAgICAgY2FzZSAnW29iamVjdCBCb29sZWFuXSc6XG4gICAgICAgIC8vIENvZXJjZSBkYXRlcyBhbmQgYm9vbGVhbnMgdG8gbnVtZXJpYyBwcmltaXRpdmUgdmFsdWVzLiBEYXRlcyBhcmUgY29tcGFyZWQgYnkgdGhlaXJcbiAgICAgICAgLy8gbWlsbGlzZWNvbmQgcmVwcmVzZW50YXRpb25zLiBOb3RlIHRoYXQgaW52YWxpZCBkYXRlcyB3aXRoIG1pbGxpc2Vjb25kIHJlcHJlc2VudGF0aW9uc1xuICAgICAgICAvLyBvZiBgTmFOYCBhcmUgbm90IGVxdWl2YWxlbnQuXG4gICAgICAgIHJldHVybiArYSA9PT0gK2I7XG4gICAgfVxuXG4gICAgdmFyIGFyZUFycmF5cyA9IGNsYXNzTmFtZSA9PT0gJ1tvYmplY3QgQXJyYXldJztcbiAgICBpZiAoIWFyZUFycmF5cykge1xuICAgICAgaWYgKHR5cGVvZiBhICE9ICdvYmplY3QnIHx8IHR5cGVvZiBiICE9ICdvYmplY3QnKSByZXR1cm4gZmFsc2U7XG5cbiAgICAgIC8vIE9iamVjdHMgd2l0aCBkaWZmZXJlbnQgY29uc3RydWN0b3JzIGFyZSBub3QgZXF1aXZhbGVudCwgYnV0IGBPYmplY3RgcyBvciBgQXJyYXlgc1xuICAgICAgLy8gZnJvbSBkaWZmZXJlbnQgZnJhbWVzIGFyZS5cbiAgICAgIHZhciBhQ3RvciA9IGEuY29uc3RydWN0b3IsIGJDdG9yID0gYi5jb25zdHJ1Y3RvcjtcbiAgICAgIGlmIChhQ3RvciAhPT0gYkN0b3IgJiYgIShfLmlzRnVuY3Rpb24oYUN0b3IpICYmIGFDdG9yIGluc3RhbmNlb2YgYUN0b3IgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBfLmlzRnVuY3Rpb24oYkN0b3IpICYmIGJDdG9yIGluc3RhbmNlb2YgYkN0b3IpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICYmICgnY29uc3RydWN0b3InIGluIGEgJiYgJ2NvbnN0cnVjdG9yJyBpbiBiKSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgfVxuICAgIC8vIEFzc3VtZSBlcXVhbGl0eSBmb3IgY3ljbGljIHN0cnVjdHVyZXMuIFRoZSBhbGdvcml0aG0gZm9yIGRldGVjdGluZyBjeWNsaWNcbiAgICAvLyBzdHJ1Y3R1cmVzIGlzIGFkYXB0ZWQgZnJvbSBFUyA1LjEgc2VjdGlvbiAxNS4xMi4zLCBhYnN0cmFjdCBvcGVyYXRpb24gYEpPYC5cblxuICAgIC8vIEluaXRpYWxpemluZyBzdGFjayBvZiB0cmF2ZXJzZWQgb2JqZWN0cy5cbiAgICAvLyBJdCdzIGRvbmUgaGVyZSBzaW5jZSB3ZSBvbmx5IG5lZWQgdGhlbSBmb3Igb2JqZWN0cyBhbmQgYXJyYXlzIGNvbXBhcmlzb24uXG4gICAgYVN0YWNrID0gYVN0YWNrIHx8IFtdO1xuICAgIGJTdGFjayA9IGJTdGFjayB8fCBbXTtcbiAgICB2YXIgbGVuZ3RoID0gYVN0YWNrLmxlbmd0aDtcbiAgICB3aGlsZSAobGVuZ3RoLS0pIHtcbiAgICAgIC8vIExpbmVhciBzZWFyY2guIFBlcmZvcm1hbmNlIGlzIGludmVyc2VseSBwcm9wb3J0aW9uYWwgdG8gdGhlIG51bWJlciBvZlxuICAgICAgLy8gdW5pcXVlIG5lc3RlZCBzdHJ1Y3R1cmVzLlxuICAgICAgaWYgKGFTdGFja1tsZW5ndGhdID09PSBhKSByZXR1cm4gYlN0YWNrW2xlbmd0aF0gPT09IGI7XG4gICAgfVxuXG4gICAgLy8gQWRkIHRoZSBmaXJzdCBvYmplY3QgdG8gdGhlIHN0YWNrIG9mIHRyYXZlcnNlZCBvYmplY3RzLlxuICAgIGFTdGFjay5wdXNoKGEpO1xuICAgIGJTdGFjay5wdXNoKGIpO1xuXG4gICAgLy8gUmVjdXJzaXZlbHkgY29tcGFyZSBvYmplY3RzIGFuZCBhcnJheXMuXG4gICAgaWYgKGFyZUFycmF5cykge1xuICAgICAgLy8gQ29tcGFyZSBhcnJheSBsZW5ndGhzIHRvIGRldGVybWluZSBpZiBhIGRlZXAgY29tcGFyaXNvbiBpcyBuZWNlc3NhcnkuXG4gICAgICBsZW5ndGggPSBhLmxlbmd0aDtcbiAgICAgIGlmIChsZW5ndGggIT09IGIubGVuZ3RoKSByZXR1cm4gZmFsc2U7XG4gICAgICAvLyBEZWVwIGNvbXBhcmUgdGhlIGNvbnRlbnRzLCBpZ25vcmluZyBub24tbnVtZXJpYyBwcm9wZXJ0aWVzLlxuICAgICAgd2hpbGUgKGxlbmd0aC0tKSB7XG4gICAgICAgIGlmICghZXEoYVtsZW5ndGhdLCBiW2xlbmd0aF0sIGFTdGFjaywgYlN0YWNrKSkgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICAvLyBEZWVwIGNvbXBhcmUgb2JqZWN0cy5cbiAgICAgIHZhciBrZXlzID0gXy5rZXlzKGEpLCBrZXk7XG4gICAgICBsZW5ndGggPSBrZXlzLmxlbmd0aDtcbiAgICAgIC8vIEVuc3VyZSB0aGF0IGJvdGggb2JqZWN0cyBjb250YWluIHRoZSBzYW1lIG51bWJlciBvZiBwcm9wZXJ0aWVzIGJlZm9yZSBjb21wYXJpbmcgZGVlcCBlcXVhbGl0eS5cbiAgICAgIGlmIChfLmtleXMoYikubGVuZ3RoICE9PSBsZW5ndGgpIHJldHVybiBmYWxzZTtcbiAgICAgIHdoaWxlIChsZW5ndGgtLSkge1xuICAgICAgICAvLyBEZWVwIGNvbXBhcmUgZWFjaCBtZW1iZXJcbiAgICAgICAga2V5ID0ga2V5c1tsZW5ndGhdO1xuICAgICAgICBpZiAoIShfLmhhcyhiLCBrZXkpICYmIGVxKGFba2V5XSwgYltrZXldLCBhU3RhY2ssIGJTdGFjaykpKSByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgfVxuICAgIC8vIFJlbW92ZSB0aGUgZmlyc3Qgb2JqZWN0IGZyb20gdGhlIHN0YWNrIG9mIHRyYXZlcnNlZCBvYmplY3RzLlxuICAgIGFTdGFjay5wb3AoKTtcbiAgICBiU3RhY2sucG9wKCk7XG4gICAgcmV0dXJuIHRydWU7XG4gIH07XG5cbiAgLy8gUGVyZm9ybSBhIGRlZXAgY29tcGFyaXNvbiB0byBjaGVjayBpZiB0d28gb2JqZWN0cyBhcmUgZXF1YWwuXG4gIF8uaXNFcXVhbCA9IGZ1bmN0aW9uKGEsIGIpIHtcbiAgICByZXR1cm4gZXEoYSwgYik7XG4gIH07XG5cbiAgLy8gSXMgYSBnaXZlbiBhcnJheSwgc3RyaW5nLCBvciBvYmplY3QgZW1wdHk/XG4gIC8vIEFuIFwiZW1wdHlcIiBvYmplY3QgaGFzIG5vIGVudW1lcmFibGUgb3duLXByb3BlcnRpZXMuXG4gIF8uaXNFbXB0eSA9IGZ1bmN0aW9uKG9iaikge1xuICAgIGlmIChvYmogPT0gbnVsbCkgcmV0dXJuIHRydWU7XG4gICAgaWYgKGlzQXJyYXlMaWtlKG9iaikgJiYgKF8uaXNBcnJheShvYmopIHx8IF8uaXNTdHJpbmcob2JqKSB8fCBfLmlzQXJndW1lbnRzKG9iaikpKSByZXR1cm4gb2JqLmxlbmd0aCA9PT0gMDtcbiAgICByZXR1cm4gXy5rZXlzKG9iaikubGVuZ3RoID09PSAwO1xuICB9O1xuXG4gIC8vIElzIGEgZ2l2ZW4gdmFsdWUgYSBET00gZWxlbWVudD9cbiAgXy5pc0VsZW1lbnQgPSBmdW5jdGlvbihvYmopIHtcbiAgICByZXR1cm4gISEob2JqICYmIG9iai5ub2RlVHlwZSA9PT0gMSk7XG4gIH07XG5cbiAgLy8gSXMgYSBnaXZlbiB2YWx1ZSBhbiBhcnJheT9cbiAgLy8gRGVsZWdhdGVzIHRvIEVDTUE1J3MgbmF0aXZlIEFycmF5LmlzQXJyYXlcbiAgXy5pc0FycmF5ID0gbmF0aXZlSXNBcnJheSB8fCBmdW5jdGlvbihvYmopIHtcbiAgICByZXR1cm4gdG9TdHJpbmcuY2FsbChvYmopID09PSAnW29iamVjdCBBcnJheV0nO1xuICB9O1xuXG4gIC8vIElzIGEgZ2l2ZW4gdmFyaWFibGUgYW4gb2JqZWN0P1xuICBfLmlzT2JqZWN0ID0gZnVuY3Rpb24ob2JqKSB7XG4gICAgdmFyIHR5cGUgPSB0eXBlb2Ygb2JqO1xuICAgIHJldHVybiB0eXBlID09PSAnZnVuY3Rpb24nIHx8IHR5cGUgPT09ICdvYmplY3QnICYmICEhb2JqO1xuICB9O1xuXG4gIC8vIEFkZCBzb21lIGlzVHlwZSBtZXRob2RzOiBpc0FyZ3VtZW50cywgaXNGdW5jdGlvbiwgaXNTdHJpbmcsIGlzTnVtYmVyLCBpc0RhdGUsIGlzUmVnRXhwLCBpc0Vycm9yLlxuICBfLmVhY2goWydBcmd1bWVudHMnLCAnRnVuY3Rpb24nLCAnU3RyaW5nJywgJ051bWJlcicsICdEYXRlJywgJ1JlZ0V4cCcsICdFcnJvciddLCBmdW5jdGlvbihuYW1lKSB7XG4gICAgX1snaXMnICsgbmFtZV0gPSBmdW5jdGlvbihvYmopIHtcbiAgICAgIHJldHVybiB0b1N0cmluZy5jYWxsKG9iaikgPT09ICdbb2JqZWN0ICcgKyBuYW1lICsgJ10nO1xuICAgIH07XG4gIH0pO1xuXG4gIC8vIERlZmluZSBhIGZhbGxiYWNrIHZlcnNpb24gb2YgdGhlIG1ldGhvZCBpbiBicm93c2VycyAoYWhlbSwgSUUgPCA5KSwgd2hlcmVcbiAgLy8gdGhlcmUgaXNuJ3QgYW55IGluc3BlY3RhYmxlIFwiQXJndW1lbnRzXCIgdHlwZS5cbiAgaWYgKCFfLmlzQXJndW1lbnRzKGFyZ3VtZW50cykpIHtcbiAgICBfLmlzQXJndW1lbnRzID0gZnVuY3Rpb24ob2JqKSB7XG4gICAgICByZXR1cm4gXy5oYXMob2JqLCAnY2FsbGVlJyk7XG4gICAgfTtcbiAgfVxuXG4gIC8vIE9wdGltaXplIGBpc0Z1bmN0aW9uYCBpZiBhcHByb3ByaWF0ZS4gV29yayBhcm91bmQgc29tZSB0eXBlb2YgYnVncyBpbiBvbGQgdjgsXG4gIC8vIElFIDExICgjMTYyMSksIGFuZCBpbiBTYWZhcmkgOCAoIzE5MjkpLlxuICBpZiAodHlwZW9mIC8uLyAhPSAnZnVuY3Rpb24nICYmIHR5cGVvZiBJbnQ4QXJyYXkgIT0gJ29iamVjdCcpIHtcbiAgICBfLmlzRnVuY3Rpb24gPSBmdW5jdGlvbihvYmopIHtcbiAgICAgIHJldHVybiB0eXBlb2Ygb2JqID09ICdmdW5jdGlvbicgfHwgZmFsc2U7XG4gICAgfTtcbiAgfVxuXG4gIC8vIElzIGEgZ2l2ZW4gb2JqZWN0IGEgZmluaXRlIG51bWJlcj9cbiAgXy5pc0Zpbml0ZSA9IGZ1bmN0aW9uKG9iaikge1xuICAgIHJldHVybiBpc0Zpbml0ZShvYmopICYmICFpc05hTihwYXJzZUZsb2F0KG9iaikpO1xuICB9O1xuXG4gIC8vIElzIHRoZSBnaXZlbiB2YWx1ZSBgTmFOYD8gKE5hTiBpcyB0aGUgb25seSBudW1iZXIgd2hpY2ggZG9lcyBub3QgZXF1YWwgaXRzZWxmKS5cbiAgXy5pc05hTiA9IGZ1bmN0aW9uKG9iaikge1xuICAgIHJldHVybiBfLmlzTnVtYmVyKG9iaikgJiYgb2JqICE9PSArb2JqO1xuICB9O1xuXG4gIC8vIElzIGEgZ2l2ZW4gdmFsdWUgYSBib29sZWFuP1xuICBfLmlzQm9vbGVhbiA9IGZ1bmN0aW9uKG9iaikge1xuICAgIHJldHVybiBvYmogPT09IHRydWUgfHwgb2JqID09PSBmYWxzZSB8fCB0b1N0cmluZy5jYWxsKG9iaikgPT09ICdbb2JqZWN0IEJvb2xlYW5dJztcbiAgfTtcblxuICAvLyBJcyBhIGdpdmVuIHZhbHVlIGVxdWFsIHRvIG51bGw/XG4gIF8uaXNOdWxsID0gZnVuY3Rpb24ob2JqKSB7XG4gICAgcmV0dXJuIG9iaiA9PT0gbnVsbDtcbiAgfTtcblxuICAvLyBJcyBhIGdpdmVuIHZhcmlhYmxlIHVuZGVmaW5lZD9cbiAgXy5pc1VuZGVmaW5lZCA9IGZ1bmN0aW9uKG9iaikge1xuICAgIHJldHVybiBvYmogPT09IHZvaWQgMDtcbiAgfTtcblxuICAvLyBTaG9ydGN1dCBmdW5jdGlvbiBmb3IgY2hlY2tpbmcgaWYgYW4gb2JqZWN0IGhhcyBhIGdpdmVuIHByb3BlcnR5IGRpcmVjdGx5XG4gIC8vIG9uIGl0c2VsZiAoaW4gb3RoZXIgd29yZHMsIG5vdCBvbiBhIHByb3RvdHlwZSkuXG4gIF8uaGFzID0gZnVuY3Rpb24ob2JqLCBrZXkpIHtcbiAgICByZXR1cm4gb2JqICE9IG51bGwgJiYgaGFzT3duUHJvcGVydHkuY2FsbChvYmosIGtleSk7XG4gIH07XG5cbiAgLy8gVXRpbGl0eSBGdW5jdGlvbnNcbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS1cblxuICAvLyBSdW4gVW5kZXJzY29yZS5qcyBpbiAqbm9Db25mbGljdCogbW9kZSwgcmV0dXJuaW5nIHRoZSBgX2AgdmFyaWFibGUgdG8gaXRzXG4gIC8vIHByZXZpb3VzIG93bmVyLiBSZXR1cm5zIGEgcmVmZXJlbmNlIHRvIHRoZSBVbmRlcnNjb3JlIG9iamVjdC5cbiAgXy5ub0NvbmZsaWN0ID0gZnVuY3Rpb24oKSB7XG4gICAgcm9vdC5fID0gcHJldmlvdXNVbmRlcnNjb3JlO1xuICAgIHJldHVybiB0aGlzO1xuICB9O1xuXG4gIC8vIEtlZXAgdGhlIGlkZW50aXR5IGZ1bmN0aW9uIGFyb3VuZCBmb3IgZGVmYXVsdCBpdGVyYXRlZXMuXG4gIF8uaWRlbnRpdHkgPSBmdW5jdGlvbih2YWx1ZSkge1xuICAgIHJldHVybiB2YWx1ZTtcbiAgfTtcblxuICAvLyBQcmVkaWNhdGUtZ2VuZXJhdGluZyBmdW5jdGlvbnMuIE9mdGVuIHVzZWZ1bCBvdXRzaWRlIG9mIFVuZGVyc2NvcmUuXG4gIF8uY29uc3RhbnQgPSBmdW5jdGlvbih2YWx1ZSkge1xuICAgIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICAgIHJldHVybiB2YWx1ZTtcbiAgICB9O1xuICB9O1xuXG4gIF8ubm9vcCA9IGZ1bmN0aW9uKCl7fTtcblxuICBfLnByb3BlcnR5ID0gcHJvcGVydHk7XG5cbiAgLy8gR2VuZXJhdGVzIGEgZnVuY3Rpb24gZm9yIGEgZ2l2ZW4gb2JqZWN0IHRoYXQgcmV0dXJucyBhIGdpdmVuIHByb3BlcnR5LlxuICBfLnByb3BlcnR5T2YgPSBmdW5jdGlvbihvYmopIHtcbiAgICByZXR1cm4gb2JqID09IG51bGwgPyBmdW5jdGlvbigpe30gOiBmdW5jdGlvbihrZXkpIHtcbiAgICAgIHJldHVybiBvYmpba2V5XTtcbiAgICB9O1xuICB9O1xuXG4gIC8vIFJldHVybnMgYSBwcmVkaWNhdGUgZm9yIGNoZWNraW5nIHdoZXRoZXIgYW4gb2JqZWN0IGhhcyBhIGdpdmVuIHNldCBvZlxuICAvLyBga2V5OnZhbHVlYCBwYWlycy5cbiAgXy5tYXRjaGVyID0gXy5tYXRjaGVzID0gZnVuY3Rpb24oYXR0cnMpIHtcbiAgICBhdHRycyA9IF8uZXh0ZW5kT3duKHt9LCBhdHRycyk7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKG9iaikge1xuICAgICAgcmV0dXJuIF8uaXNNYXRjaChvYmosIGF0dHJzKTtcbiAgICB9O1xuICB9O1xuXG4gIC8vIFJ1biBhIGZ1bmN0aW9uICoqbioqIHRpbWVzLlxuICBfLnRpbWVzID0gZnVuY3Rpb24obiwgaXRlcmF0ZWUsIGNvbnRleHQpIHtcbiAgICB2YXIgYWNjdW0gPSBBcnJheShNYXRoLm1heCgwLCBuKSk7XG4gICAgaXRlcmF0ZWUgPSBvcHRpbWl6ZUNiKGl0ZXJhdGVlLCBjb250ZXh0LCAxKTtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IG47IGkrKykgYWNjdW1baV0gPSBpdGVyYXRlZShpKTtcbiAgICByZXR1cm4gYWNjdW07XG4gIH07XG5cbiAgLy8gUmV0dXJuIGEgcmFuZG9tIGludGVnZXIgYmV0d2VlbiBtaW4gYW5kIG1heCAoaW5jbHVzaXZlKS5cbiAgXy5yYW5kb20gPSBmdW5jdGlvbihtaW4sIG1heCkge1xuICAgIGlmIChtYXggPT0gbnVsbCkge1xuICAgICAgbWF4ID0gbWluO1xuICAgICAgbWluID0gMDtcbiAgICB9XG4gICAgcmV0dXJuIG1pbiArIE1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIChtYXggLSBtaW4gKyAxKSk7XG4gIH07XG5cbiAgLy8gQSAocG9zc2libHkgZmFzdGVyKSB3YXkgdG8gZ2V0IHRoZSBjdXJyZW50IHRpbWVzdGFtcCBhcyBhbiBpbnRlZ2VyLlxuICBfLm5vdyA9IERhdGUubm93IHx8IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcbiAgfTtcblxuICAgLy8gTGlzdCBvZiBIVE1MIGVudGl0aWVzIGZvciBlc2NhcGluZy5cbiAgdmFyIGVzY2FwZU1hcCA9IHtcbiAgICAnJic6ICcmYW1wOycsXG4gICAgJzwnOiAnJmx0OycsXG4gICAgJz4nOiAnJmd0OycsXG4gICAgJ1wiJzogJyZxdW90OycsXG4gICAgXCInXCI6ICcmI3gyNzsnLFxuICAgICdgJzogJyYjeDYwOydcbiAgfTtcbiAgdmFyIHVuZXNjYXBlTWFwID0gXy5pbnZlcnQoZXNjYXBlTWFwKTtcblxuICAvLyBGdW5jdGlvbnMgZm9yIGVzY2FwaW5nIGFuZCB1bmVzY2FwaW5nIHN0cmluZ3MgdG8vZnJvbSBIVE1MIGludGVycG9sYXRpb24uXG4gIHZhciBjcmVhdGVFc2NhcGVyID0gZnVuY3Rpb24obWFwKSB7XG4gICAgdmFyIGVzY2FwZXIgPSBmdW5jdGlvbihtYXRjaCkge1xuICAgICAgcmV0dXJuIG1hcFttYXRjaF07XG4gICAgfTtcbiAgICAvLyBSZWdleGVzIGZvciBpZGVudGlmeWluZyBhIGtleSB0aGF0IG5lZWRzIHRvIGJlIGVzY2FwZWRcbiAgICB2YXIgc291cmNlID0gJyg/OicgKyBfLmtleXMobWFwKS5qb2luKCd8JykgKyAnKSc7XG4gICAgdmFyIHRlc3RSZWdleHAgPSBSZWdFeHAoc291cmNlKTtcbiAgICB2YXIgcmVwbGFjZVJlZ2V4cCA9IFJlZ0V4cChzb3VyY2UsICdnJyk7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKHN0cmluZykge1xuICAgICAgc3RyaW5nID0gc3RyaW5nID09IG51bGwgPyAnJyA6ICcnICsgc3RyaW5nO1xuICAgICAgcmV0dXJuIHRlc3RSZWdleHAudGVzdChzdHJpbmcpID8gc3RyaW5nLnJlcGxhY2UocmVwbGFjZVJlZ2V4cCwgZXNjYXBlcikgOiBzdHJpbmc7XG4gICAgfTtcbiAgfTtcbiAgXy5lc2NhcGUgPSBjcmVhdGVFc2NhcGVyKGVzY2FwZU1hcCk7XG4gIF8udW5lc2NhcGUgPSBjcmVhdGVFc2NhcGVyKHVuZXNjYXBlTWFwKTtcblxuICAvLyBJZiB0aGUgdmFsdWUgb2YgdGhlIG5hbWVkIGBwcm9wZXJ0eWAgaXMgYSBmdW5jdGlvbiB0aGVuIGludm9rZSBpdCB3aXRoIHRoZVxuICAvLyBgb2JqZWN0YCBhcyBjb250ZXh0OyBvdGhlcndpc2UsIHJldHVybiBpdC5cbiAgXy5yZXN1bHQgPSBmdW5jdGlvbihvYmplY3QsIHByb3BlcnR5LCBmYWxsYmFjaykge1xuICAgIHZhciB2YWx1ZSA9IG9iamVjdCA9PSBudWxsID8gdm9pZCAwIDogb2JqZWN0W3Byb3BlcnR5XTtcbiAgICBpZiAodmFsdWUgPT09IHZvaWQgMCkge1xuICAgICAgdmFsdWUgPSBmYWxsYmFjaztcbiAgICB9XG4gICAgcmV0dXJuIF8uaXNGdW5jdGlvbih2YWx1ZSkgPyB2YWx1ZS5jYWxsKG9iamVjdCkgOiB2YWx1ZTtcbiAgfTtcblxuICAvLyBHZW5lcmF0ZSBhIHVuaXF1ZSBpbnRlZ2VyIGlkICh1bmlxdWUgd2l0aGluIHRoZSBlbnRpcmUgY2xpZW50IHNlc3Npb24pLlxuICAvLyBVc2VmdWwgZm9yIHRlbXBvcmFyeSBET00gaWRzLlxuICB2YXIgaWRDb3VudGVyID0gMDtcbiAgXy51bmlxdWVJZCA9IGZ1bmN0aW9uKHByZWZpeCkge1xuICAgIHZhciBpZCA9ICsraWRDb3VudGVyICsgJyc7XG4gICAgcmV0dXJuIHByZWZpeCA/IHByZWZpeCArIGlkIDogaWQ7XG4gIH07XG5cbiAgLy8gQnkgZGVmYXVsdCwgVW5kZXJzY29yZSB1c2VzIEVSQi1zdHlsZSB0ZW1wbGF0ZSBkZWxpbWl0ZXJzLCBjaGFuZ2UgdGhlXG4gIC8vIGZvbGxvd2luZyB0ZW1wbGF0ZSBzZXR0aW5ncyB0byB1c2UgYWx0ZXJuYXRpdmUgZGVsaW1pdGVycy5cbiAgXy50ZW1wbGF0ZVNldHRpbmdzID0ge1xuICAgIGV2YWx1YXRlICAgIDogLzwlKFtcXHNcXFNdKz8pJT4vZyxcbiAgICBpbnRlcnBvbGF0ZSA6IC88JT0oW1xcc1xcU10rPyklPi9nLFxuICAgIGVzY2FwZSAgICAgIDogLzwlLShbXFxzXFxTXSs/KSU+L2dcbiAgfTtcblxuICAvLyBXaGVuIGN1c3RvbWl6aW5nIGB0ZW1wbGF0ZVNldHRpbmdzYCwgaWYgeW91IGRvbid0IHdhbnQgdG8gZGVmaW5lIGFuXG4gIC8vIGludGVycG9sYXRpb24sIGV2YWx1YXRpb24gb3IgZXNjYXBpbmcgcmVnZXgsIHdlIG5lZWQgb25lIHRoYXQgaXNcbiAgLy8gZ3VhcmFudGVlZCBub3QgdG8gbWF0Y2guXG4gIHZhciBub01hdGNoID0gLyguKV4vO1xuXG4gIC8vIENlcnRhaW4gY2hhcmFjdGVycyBuZWVkIHRvIGJlIGVzY2FwZWQgc28gdGhhdCB0aGV5IGNhbiBiZSBwdXQgaW50byBhXG4gIC8vIHN0cmluZyBsaXRlcmFsLlxuICB2YXIgZXNjYXBlcyA9IHtcbiAgICBcIidcIjogICAgICBcIidcIixcbiAgICAnXFxcXCc6ICAgICAnXFxcXCcsXG4gICAgJ1xccic6ICAgICAncicsXG4gICAgJ1xcbic6ICAgICAnbicsXG4gICAgJ1xcdTIwMjgnOiAndTIwMjgnLFxuICAgICdcXHUyMDI5JzogJ3UyMDI5J1xuICB9O1xuXG4gIHZhciBlc2NhcGVyID0gL1xcXFx8J3xcXHJ8XFxufFxcdTIwMjh8XFx1MjAyOS9nO1xuXG4gIHZhciBlc2NhcGVDaGFyID0gZnVuY3Rpb24obWF0Y2gpIHtcbiAgICByZXR1cm4gJ1xcXFwnICsgZXNjYXBlc1ttYXRjaF07XG4gIH07XG5cbiAgLy8gSmF2YVNjcmlwdCBtaWNyby10ZW1wbGF0aW5nLCBzaW1pbGFyIHRvIEpvaG4gUmVzaWcncyBpbXBsZW1lbnRhdGlvbi5cbiAgLy8gVW5kZXJzY29yZSB0ZW1wbGF0aW5nIGhhbmRsZXMgYXJiaXRyYXJ5IGRlbGltaXRlcnMsIHByZXNlcnZlcyB3aGl0ZXNwYWNlLFxuICAvLyBhbmQgY29ycmVjdGx5IGVzY2FwZXMgcXVvdGVzIHdpdGhpbiBpbnRlcnBvbGF0ZWQgY29kZS5cbiAgLy8gTkI6IGBvbGRTZXR0aW5nc2Agb25seSBleGlzdHMgZm9yIGJhY2t3YXJkcyBjb21wYXRpYmlsaXR5LlxuICBfLnRlbXBsYXRlID0gZnVuY3Rpb24odGV4dCwgc2V0dGluZ3MsIG9sZFNldHRpbmdzKSB7XG4gICAgaWYgKCFzZXR0aW5ncyAmJiBvbGRTZXR0aW5ncykgc2V0dGluZ3MgPSBvbGRTZXR0aW5ncztcbiAgICBzZXR0aW5ncyA9IF8uZGVmYXVsdHMoe30sIHNldHRpbmdzLCBfLnRlbXBsYXRlU2V0dGluZ3MpO1xuXG4gICAgLy8gQ29tYmluZSBkZWxpbWl0ZXJzIGludG8gb25lIHJlZ3VsYXIgZXhwcmVzc2lvbiB2aWEgYWx0ZXJuYXRpb24uXG4gICAgdmFyIG1hdGNoZXIgPSBSZWdFeHAoW1xuICAgICAgKHNldHRpbmdzLmVzY2FwZSB8fCBub01hdGNoKS5zb3VyY2UsXG4gICAgICAoc2V0dGluZ3MuaW50ZXJwb2xhdGUgfHwgbm9NYXRjaCkuc291cmNlLFxuICAgICAgKHNldHRpbmdzLmV2YWx1YXRlIHx8IG5vTWF0Y2gpLnNvdXJjZVxuICAgIF0uam9pbignfCcpICsgJ3wkJywgJ2cnKTtcblxuICAgIC8vIENvbXBpbGUgdGhlIHRlbXBsYXRlIHNvdXJjZSwgZXNjYXBpbmcgc3RyaW5nIGxpdGVyYWxzIGFwcHJvcHJpYXRlbHkuXG4gICAgdmFyIGluZGV4ID0gMDtcbiAgICB2YXIgc291cmNlID0gXCJfX3ArPSdcIjtcbiAgICB0ZXh0LnJlcGxhY2UobWF0Y2hlciwgZnVuY3Rpb24obWF0Y2gsIGVzY2FwZSwgaW50ZXJwb2xhdGUsIGV2YWx1YXRlLCBvZmZzZXQpIHtcbiAgICAgIHNvdXJjZSArPSB0ZXh0LnNsaWNlKGluZGV4LCBvZmZzZXQpLnJlcGxhY2UoZXNjYXBlciwgZXNjYXBlQ2hhcik7XG4gICAgICBpbmRleCA9IG9mZnNldCArIG1hdGNoLmxlbmd0aDtcblxuICAgICAgaWYgKGVzY2FwZSkge1xuICAgICAgICBzb3VyY2UgKz0gXCInK1xcbigoX190PShcIiArIGVzY2FwZSArIFwiKSk9PW51bGw/Jyc6Xy5lc2NhcGUoX190KSkrXFxuJ1wiO1xuICAgICAgfSBlbHNlIGlmIChpbnRlcnBvbGF0ZSkge1xuICAgICAgICBzb3VyY2UgKz0gXCInK1xcbigoX190PShcIiArIGludGVycG9sYXRlICsgXCIpKT09bnVsbD8nJzpfX3QpK1xcbidcIjtcbiAgICAgIH0gZWxzZSBpZiAoZXZhbHVhdGUpIHtcbiAgICAgICAgc291cmNlICs9IFwiJztcXG5cIiArIGV2YWx1YXRlICsgXCJcXG5fX3ArPSdcIjtcbiAgICAgIH1cblxuICAgICAgLy8gQWRvYmUgVk1zIG5lZWQgdGhlIG1hdGNoIHJldHVybmVkIHRvIHByb2R1Y2UgdGhlIGNvcnJlY3Qgb2ZmZXN0LlxuICAgICAgcmV0dXJuIG1hdGNoO1xuICAgIH0pO1xuICAgIHNvdXJjZSArPSBcIic7XFxuXCI7XG5cbiAgICAvLyBJZiBhIHZhcmlhYmxlIGlzIG5vdCBzcGVjaWZpZWQsIHBsYWNlIGRhdGEgdmFsdWVzIGluIGxvY2FsIHNjb3BlLlxuICAgIGlmICghc2V0dGluZ3MudmFyaWFibGUpIHNvdXJjZSA9ICd3aXRoKG9ianx8e30pe1xcbicgKyBzb3VyY2UgKyAnfVxcbic7XG5cbiAgICBzb3VyY2UgPSBcInZhciBfX3QsX19wPScnLF9faj1BcnJheS5wcm90b3R5cGUuam9pbixcIiArXG4gICAgICBcInByaW50PWZ1bmN0aW9uKCl7X19wKz1fX2ouY2FsbChhcmd1bWVudHMsJycpO307XFxuXCIgK1xuICAgICAgc291cmNlICsgJ3JldHVybiBfX3A7XFxuJztcblxuICAgIHRyeSB7XG4gICAgICB2YXIgcmVuZGVyID0gbmV3IEZ1bmN0aW9uKHNldHRpbmdzLnZhcmlhYmxlIHx8ICdvYmonLCAnXycsIHNvdXJjZSk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgZS5zb3VyY2UgPSBzb3VyY2U7XG4gICAgICB0aHJvdyBlO1xuICAgIH1cblxuICAgIHZhciB0ZW1wbGF0ZSA9IGZ1bmN0aW9uKGRhdGEpIHtcbiAgICAgIHJldHVybiByZW5kZXIuY2FsbCh0aGlzLCBkYXRhLCBfKTtcbiAgICB9O1xuXG4gICAgLy8gUHJvdmlkZSB0aGUgY29tcGlsZWQgc291cmNlIGFzIGEgY29udmVuaWVuY2UgZm9yIHByZWNvbXBpbGF0aW9uLlxuICAgIHZhciBhcmd1bWVudCA9IHNldHRpbmdzLnZhcmlhYmxlIHx8ICdvYmonO1xuICAgIHRlbXBsYXRlLnNvdXJjZSA9ICdmdW5jdGlvbignICsgYXJndW1lbnQgKyAnKXtcXG4nICsgc291cmNlICsgJ30nO1xuXG4gICAgcmV0dXJuIHRlbXBsYXRlO1xuICB9O1xuXG4gIC8vIEFkZCBhIFwiY2hhaW5cIiBmdW5jdGlvbi4gU3RhcnQgY2hhaW5pbmcgYSB3cmFwcGVkIFVuZGVyc2NvcmUgb2JqZWN0LlxuICBfLmNoYWluID0gZnVuY3Rpb24ob2JqKSB7XG4gICAgdmFyIGluc3RhbmNlID0gXyhvYmopO1xuICAgIGluc3RhbmNlLl9jaGFpbiA9IHRydWU7XG4gICAgcmV0dXJuIGluc3RhbmNlO1xuICB9O1xuXG4gIC8vIE9PUFxuICAvLyAtLS0tLS0tLS0tLS0tLS1cbiAgLy8gSWYgVW5kZXJzY29yZSBpcyBjYWxsZWQgYXMgYSBmdW5jdGlvbiwgaXQgcmV0dXJucyBhIHdyYXBwZWQgb2JqZWN0IHRoYXRcbiAgLy8gY2FuIGJlIHVzZWQgT08tc3R5bGUuIFRoaXMgd3JhcHBlciBob2xkcyBhbHRlcmVkIHZlcnNpb25zIG9mIGFsbCB0aGVcbiAgLy8gdW5kZXJzY29yZSBmdW5jdGlvbnMuIFdyYXBwZWQgb2JqZWN0cyBtYXkgYmUgY2hhaW5lZC5cblxuICAvLyBIZWxwZXIgZnVuY3Rpb24gdG8gY29udGludWUgY2hhaW5pbmcgaW50ZXJtZWRpYXRlIHJlc3VsdHMuXG4gIHZhciByZXN1bHQgPSBmdW5jdGlvbihpbnN0YW5jZSwgb2JqKSB7XG4gICAgcmV0dXJuIGluc3RhbmNlLl9jaGFpbiA/IF8ob2JqKS5jaGFpbigpIDogb2JqO1xuICB9O1xuXG4gIC8vIEFkZCB5b3VyIG93biBjdXN0b20gZnVuY3Rpb25zIHRvIHRoZSBVbmRlcnNjb3JlIG9iamVjdC5cbiAgXy5taXhpbiA9IGZ1bmN0aW9uKG9iaikge1xuICAgIF8uZWFjaChfLmZ1bmN0aW9ucyhvYmopLCBmdW5jdGlvbihuYW1lKSB7XG4gICAgICB2YXIgZnVuYyA9IF9bbmFtZV0gPSBvYmpbbmFtZV07XG4gICAgICBfLnByb3RvdHlwZVtuYW1lXSA9IGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgYXJncyA9IFt0aGlzLl93cmFwcGVkXTtcbiAgICAgICAgcHVzaC5hcHBseShhcmdzLCBhcmd1bWVudHMpO1xuICAgICAgICByZXR1cm4gcmVzdWx0KHRoaXMsIGZ1bmMuYXBwbHkoXywgYXJncykpO1xuICAgICAgfTtcbiAgICB9KTtcbiAgfTtcblxuICAvLyBBZGQgYWxsIG9mIHRoZSBVbmRlcnNjb3JlIGZ1bmN0aW9ucyB0byB0aGUgd3JhcHBlciBvYmplY3QuXG4gIF8ubWl4aW4oXyk7XG5cbiAgLy8gQWRkIGFsbCBtdXRhdG9yIEFycmF5IGZ1bmN0aW9ucyB0byB0aGUgd3JhcHBlci5cbiAgXy5lYWNoKFsncG9wJywgJ3B1c2gnLCAncmV2ZXJzZScsICdzaGlmdCcsICdzb3J0JywgJ3NwbGljZScsICd1bnNoaWZ0J10sIGZ1bmN0aW9uKG5hbWUpIHtcbiAgICB2YXIgbWV0aG9kID0gQXJyYXlQcm90b1tuYW1lXTtcbiAgICBfLnByb3RvdHlwZVtuYW1lXSA9IGZ1bmN0aW9uKCkge1xuICAgICAgdmFyIG9iaiA9IHRoaXMuX3dyYXBwZWQ7XG4gICAgICBtZXRob2QuYXBwbHkob2JqLCBhcmd1bWVudHMpO1xuICAgICAgaWYgKChuYW1lID09PSAnc2hpZnQnIHx8IG5hbWUgPT09ICdzcGxpY2UnKSAmJiBvYmoubGVuZ3RoID09PSAwKSBkZWxldGUgb2JqWzBdO1xuICAgICAgcmV0dXJuIHJlc3VsdCh0aGlzLCBvYmopO1xuICAgIH07XG4gIH0pO1xuXG4gIC8vIEFkZCBhbGwgYWNjZXNzb3IgQXJyYXkgZnVuY3Rpb25zIHRvIHRoZSB3cmFwcGVyLlxuICBfLmVhY2goWydjb25jYXQnLCAnam9pbicsICdzbGljZSddLCBmdW5jdGlvbihuYW1lKSB7XG4gICAgdmFyIG1ldGhvZCA9IEFycmF5UHJvdG9bbmFtZV07XG4gICAgXy5wcm90b3R5cGVbbmFtZV0gPSBmdW5jdGlvbigpIHtcbiAgICAgIHJldHVybiByZXN1bHQodGhpcywgbWV0aG9kLmFwcGx5KHRoaXMuX3dyYXBwZWQsIGFyZ3VtZW50cykpO1xuICAgIH07XG4gIH0pO1xuXG4gIC8vIEV4dHJhY3RzIHRoZSByZXN1bHQgZnJvbSBhIHdyYXBwZWQgYW5kIGNoYWluZWQgb2JqZWN0LlxuICBfLnByb3RvdHlwZS52YWx1ZSA9IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiB0aGlzLl93cmFwcGVkO1xuICB9O1xuXG4gIC8vIFByb3ZpZGUgdW53cmFwcGluZyBwcm94eSBmb3Igc29tZSBtZXRob2RzIHVzZWQgaW4gZW5naW5lIG9wZXJhdGlvbnNcbiAgLy8gc3VjaCBhcyBhcml0aG1ldGljIGFuZCBKU09OIHN0cmluZ2lmaWNhdGlvbi5cbiAgXy5wcm90b3R5cGUudmFsdWVPZiA9IF8ucHJvdG90eXBlLnRvSlNPTiA9IF8ucHJvdG90eXBlLnZhbHVlO1xuXG4gIF8ucHJvdG90eXBlLnRvU3RyaW5nID0gZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuICcnICsgdGhpcy5fd3JhcHBlZDtcbiAgfTtcblxuICAvLyBBTUQgcmVnaXN0cmF0aW9uIGhhcHBlbnMgYXQgdGhlIGVuZCBmb3IgY29tcGF0aWJpbGl0eSB3aXRoIEFNRCBsb2FkZXJzXG4gIC8vIHRoYXQgbWF5IG5vdCBlbmZvcmNlIG5leHQtdHVybiBzZW1hbnRpY3Mgb24gbW9kdWxlcy4gRXZlbiB0aG91Z2ggZ2VuZXJhbFxuICAvLyBwcmFjdGljZSBmb3IgQU1EIHJlZ2lzdHJhdGlvbiBpcyB0byBiZSBhbm9ueW1vdXMsIHVuZGVyc2NvcmUgcmVnaXN0ZXJzXG4gIC8vIGFzIGEgbmFtZWQgbW9kdWxlIGJlY2F1c2UsIGxpa2UgalF1ZXJ5LCBpdCBpcyBhIGJhc2UgbGlicmFyeSB0aGF0IGlzXG4gIC8vIHBvcHVsYXIgZW5vdWdoIHRvIGJlIGJ1bmRsZWQgaW4gYSB0aGlyZCBwYXJ0eSBsaWIsIGJ1dCBub3QgYmUgcGFydCBvZlxuICAvLyBhbiBBTUQgbG9hZCByZXF1ZXN0LiBUaG9zZSBjYXNlcyBjb3VsZCBnZW5lcmF0ZSBhbiBlcnJvciB3aGVuIGFuXG4gIC8vIGFub255bW91cyBkZWZpbmUoKSBpcyBjYWxsZWQgb3V0c2lkZSBvZiBhIGxvYWRlciByZXF1ZXN0LlxuICBpZiAodHlwZW9mIGRlZmluZSA9PT0gJ2Z1bmN0aW9uJyAmJiBkZWZpbmUuYW1kKSB7XG4gICAgZGVmaW5lKCd1bmRlcnNjb3JlJywgW10sIGZ1bmN0aW9uKCkge1xuICAgICAgcmV0dXJuIF87XG4gICAgfSk7XG4gIH1cbn0uY2FsbCh0aGlzKSk7XG4iLCIndXNlIHN0cmljdCc7XG5cbmNvbnN0IHhhcGlFcnJvckxldmVscyA9IE9iamVjdC5mcmVlemUoe1xuICBNQVlfVklPTEFUSU9OOiAgICAnTUFZX1ZJT0xBVElPTicsXG4gIE1VU1RfVklPTEFUSU9OOiAgICdNVVNUX1ZJT0xBVElPTicsXG4gIFNIT1VMRF9WSU9MQVRJT046ICdTSE9VTERfVklPTEFUSU9OJ1xufSk7XG5cbmNvbnN0IHhhcGlWYWxpZGF0aW9uRXJyb3JzID0gT2JqZWN0LmZyZWV6ZSh7XG4gIEFDVElWSVRJRVNfTVVTVF9OT1RfQkVfTlVMTF9NQVBfT0JKRUNUUzogICAgICAgICAgJ0FjdGl2aXRpZXMgbXVzdCBiZSBub24tbnVsbCBtYXAgb2JqZWN0cycsXG4gIEFDVE9SX01VU1RfQkVfUFJPVklERUQ6ICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0FjdG9yIG11c3QgYmUgcHJvdmlkZWQuJyxcbiAgQUdFTlRfSUZJX1BST1BFUlRJRVNfTVVTVF9CRV9TUEVDSUZJRUQ6ICAgICAgICAgICAnRXhhY3RseSBvbmUgSW52ZXJzZSBGdW5jdGlvbmFsIElkZW50aWZpZXIgcHJvcGVydHkgbXVzdCBiZSBzcGVjaWZpZWQgZm9yIGFuIFwiYWdlbnRcIi4nLFxuICBBR0VOVF9NVVNUX0JFX05PTl9OVUxMX01BUF9PQkpFQ1Q6ICAgICAgICAgICAgICAgICdcImFnZW50XCIgbXVzdCBiZSBhIG5vbi1udWxsIG1hcCBvYmplY3QnLFxuICBBR0VOVF9NVVNUX05PVF9IQVZFX0dST1VQX0NIQVJBQ1RFUklTVElDUzogICAgICAgICdJbnZhbGlkIG9iamVjdCB3aXRoIGNoYXJhY3RlcmlzdGljcyBvZiBhIEdyb3VwIHdoZW4gYW4gQWdlbnQgd2FzIGV4cGVjdGVkLicsXG4gIEFUVEFDSE1FTlRTX01VU1RfQkVfTk9UX05VTExfQVJSQVk6ICAgICAgICAgICAgICAgJ1wiYXR0YWNobWVudHNcIiBtdXN0IGJlIGEgbm9uLW51bGwgQXJyYXkuJyxcbiAgQVRUQUNITUVOVFNfTVVTVF9OT1RfQkVfTlVMTF9NQVBfT0JKRUNUUzogICAgICAgICAnXCJhdHRhY2htZW50XCIgaW5zdGFuY2VzIG11c3QgYmUgbm9uLW51bGwgbWFwIG9iamVjdHMuJyxcbiAgQVVUSE9SSVRZX01VU1RfQkVfTk9OX05VTExfTUFQX09CSkVDVDogICAgICAgICAgICAnSWYgcHJlc2VudCwgdGhlIFwiYXV0aG9yaXR5XCIgcHJvcGVydHkgbXVzdCBiZSBhIG5vbi1udWxsIG1hcCBvYmplY3QuJyxcbiAgQ09OVEVYVF9BQ1RJVklUSUVTX01VU1RfQkVfQVJSQVlfT1JfQUNUSVZJVFlfT0JKOiAnQ29udGV4dCBBY3Rpdml0aWVzIHByb3BlcnR5IHZhbHVlcyBtdXN0IGJlIGFuIGFycmF5IG9mIEFjdGl2aXR5IE9iamVjdHMgb3IgYSBzaW5nbGUgQWN0aXZpdHkgT2JqZWN0LicsXG4gIENPTlRFWFRfQUNUSVZJVElFU19NVVNUX0JFX05PTl9OVUxMX01BUF9PQkpFQ1Q6ICAgJ1RoZSBDb250ZXh0IEFjdGl2aXRpZXMgaW5zdGFuY2VzIG11c3QgYmUgYSBub24tbnVsbCBtYXAgb2JqZWN0LicsXG4gIENPTlRFWFRfQUNUSVZJVElFU19NVVNUX05PVF9CRV9OVUxMOiAgICAgICAgICAgICAgJ1wiQ29udGV4dCBBY3Rpdml0aWVzXCIgcHJvcGVydHkgdmFsdWVzIG11c3Qgbm90IGJlIG51bGwuJyxcbiAgQ09OVEVYVF9BQ1RJVklUSUVTX1NIT1VMRF9CRV9BTl9BUlJBWTogICAgICAgICAgICAnQ29udGV4dCBBY3Rpdml0aWVzIHByb3BlcnR5IHZhbHVlcyBzaG91bGQgcHJlZmVyIHRvIGJlIGFuIGFycmF5IG9mIEFjdGl2aXRpZXMgcmF0aGVyIHRoYW4gYSBzaW5nbGUgQWN0aXZpdHkgb2JqZWN0LicsXG4gIENPTlRFWFRfTVVTVF9CRV9OT05fTlVMX01BUF9PQkpFQ1Q6ICAgICAgICAgICAgICAgJ0lmIHByZXNlbnQsIHRoZSBcImNvbnRleHRcIiBwcm9wZXJ0eSBtdXN0IGJlIGEgbm9uLW51bGwgbWFwIG9iamVjdC4nLFxuICBDT1JSRUNUX1JFU1BPTlNFU19QQVRURVJOX01VU1RfQkVfQVJSQVk6ICAgICAgICAgICdJZiBwcmVzZW50LCB0aGUgXCJjb3JyZWN0UmVzcG9uc2VzUGF0dGVyblwiIHZhbHVlIG11c3QgYmUgYW4gQXJyYXkgb2Ygc3RyaW5ncy4nLFxuICBDT1JSRUNUX1JFU1BPTlNFU19QQVRURVJOX01VU1RfQkVfU1RSSU5HUzogICAgICAgICdcImNvcnJlY3RSZXNwb25zZXNQYXR0ZXJuXCIgaXRlbXMgbXVzdCBiZSBzdHJpbmdzLicsXG4gIERBVEVfTVVTVF9CRV9WQUxJRDogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1RoaXMgcHJvcGVydHlzIHN0cmluZyB2YWx1ZSBtdXN0IGJlIGNvbmZvcm1hbnQgdG8gSVNPIDg2MDEgZm9yIERhdGUgVGltZXMuJyxcbiAgREFURV9TSE9VTERfSU5DTFVERV9aT05FX0lORk9STUFUSU9OOiAgICAgICAgICAgICAnSVNPIDg2MDEgZGF0ZSB0aW1lIHN0cmluZ3MgdXNlZCBpbiB0aGUgeEFQSSBzaG91bGQgaW5jbHVkZSB0aW1lIHpvbmUgaW5mb3JtYXRpb24uJyxcbiAgREVGSU5JVElPTlNfTVVTVF9CRV9PQkpFQ1RTOiAgICAgICAgICAgICAgICAgICAgICAnXCJkZWZpbml0aW9uc1wiLCB3aGVuIHByZXNlbnQsIG11c3QgYmUgbWFwIG9iamVjdHMnLFxuICBESVNQTEFZX1NIT1VMRF9CRV9QUk9WSURFRDogICAgICAgICAgICAgICAgICAgICAgICdcImRpc3BsYXlcIiBwcm9wZXJ0eSBzaG91bGQgYmUgcHJvdmlkZWQuJyxcbiAgRFVSQVRJT05fTVVTVF9CRV9WQUxJRDogICAgICAgICAgICAgICAgICAgICAgICAgICAnSWYgcHJlc2VudCwgdGhlIFwiZHVyYXRpb25cIiBwcm9wZXJ0eSB2YWx1ZSBtdXN0IGJlIGFuIElTTyA4NjAxIGR1cmF0aW9uJyxcbiAgRVhURU5TSU9OU19NVVNUX05PVF9CRV9OVUxMOiAgICAgICAgICAgICAgICAgICAgICAnSWYgcHJlc2VudCwgdGhlIGV4dGVuc2lvbnMgcHJvcGVydHkgbXVzdCBiZSBhIG5vbi1udWxsIG1hcCBvYmplY3QuJyxcbiAgR1JPVVBfQVVUSE9SSVRZX0FHRU5UX01FTUJFUlNfTVVTVF9CRV9UV086ICAgICAgICAnSWYgdXNlZCBhcyBhIEdyb3VwLCB0aGUgXCJhdXRob3JpdHlcIiBwcm9wZXJ0eSBtdXN0IGNvbnRhaW4gYSBcIm1lbWJlclwiIHByb3BlcnR5IHRoYXQgaXMgYW4gYXJyYXkgY29udGFpbmluZyBleGFjdGx5IHR3byBBZ2VudCBvYmplY3RzLicsXG4gIEdST1VQX0lGSV9QUk9QRVJUSUVTX01VU1RfQkVfU1BFQ0lGSUVEOiAgICAgICAgICAgJ0V4YWN0bHkgb25lIEludmVyc2UgRnVuY3Rpb25hbCBJZGVudGlmaWVyIHByb3BlcnR5IG11c3QgYmUgc3BlY2lmaWVkIGZvciBhIFwiZ3JvdXBcIi4nLFxuICBHUk9VUF9NRU1CRVJfTVVTVF9CRV9BUlJBWTogICAgICAgICAgICAgICAgICAgICAgICdJZiBwcmVzZW50LCB0aGUgbWVtYmVyIHByb3BlcnR5IG9mIGEgR3JvdXAgbXVzdCBiZSBhbiBBcnJheScsXG4gIEdST1VQX01VU1RfQkVfTk9OX05VTExfTUFQX09CSkVDVDogICAgICAgICAgICAgICAgJ1wiZ3JvdXBcIiBtdXN0IGJlIGEgbm9uLW51bGwgbWFwIG9iamVjdCcsXG4gIElEX01VU1RfQkVfVU5JUVVFOiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1wiaWRcIiBwcm9wZXJ0aWVzIG11c3QgYmUgdW5pcXVlIHdpdGhpbiBlYWNoIGludGVyYWN0aW9uIGNvbXBvbmVudCBhcnJheScsXG4gIElEX01VU1RfQkVfVkFMSURfVVVJRF9SRUY6ICAgICAgICAgICAgICAgICAgICAgICAgJ1wiaWRcIiBwcm9wZXJ0eSB2YWx1ZSBtdXN0IGJlIGEgdmFsaWQgVVVJRCBzdHJpbmcgZm9yIHN0YXRlbWVudCByZWZlcmVuY2Ugb2JqZWN0cy4nLFxuICBJRF9NVVNUX0JFX1ZBTElEOiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdJZCB3YXMgbm90IGEgdmFsaWQgVVVJRCcsXG4gIElEX1NIT1VMRF9OT1RfQ09OVEFJTl9XSElURVNQQUNFUzogICAgICAgICAgICAgICAgJ1wiaWRcIiBwcm9wZXJ0aWVzIG9uIGludGVyYWN0aW9uIGNvbXBvbmVudHMgc2hvdWxkIG5vdCBjb250YWluIHdoaXRlc3BhY2UnLFxuICBJRFNfU0hPVUxEX0JFX0dFTkVSQVRFRF9CWV9MUlM6ICAgICAgICAgICAgICAgICAgICdJZHMgc2hvdWxkIGJlIGdlbmVyYXRlZCBieSB0aGUgQWN0aXZpdHkgUHJvdmlkZXIsIGFuZCBtdXN0IGJlIGdlbmVyYXRlZCBieSB0aGUgTFJTJyxcbiAgSUZJX01VU1RfQkVfTUJPWF9VUkk6ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnXCJtYm94XCIgcHJvcGVydHkgd2FzIHJlcXVpcmVkIHRvIGJlIGEgbWFpbHRvIFVSSSBzdHJpbmcgYnV0IHdhcyBub3QgYSBzdHJpbmcgYXQgYWxsLicsXG4gIElGSV9NVVNUX0JFX1ZBTElEX01CT1hfRk9STUFUOiAgICAgICAgICAgICAgICAgICAgJ1wibWJveFwiIHByb3BlcnR5IHdhcyByZXF1aXJlZCB0byBiZSBhIG1haWx0byBVUkkgc3RyaW5nIGJ1dCBkaWQgbm90IG1hdGNoIHRoZSBtYWlsdG8gZm9ybWF0LicsXG4gIElOVEVSQUNUSU9OX0FDVElWSVRZX1NIT1VMRF9IQVZFOiAgICAgICAgICAgICAgICAgJ0ludGVyYWN0aW9uIEFjdGl2aXR5IERlZmluaXRpb25zIHNob3VsZCBoYXZlIGEgdHlwZSBwcm9wZXJ0eSBvZicsXG4gIElOVEVSQUNUSU9OX0NPTVBPTkVOVF9NVVNUX05PVF9CRV9OVUxMOiAgICAgICAgICAgJ1RoaXMgaW50ZXJhY3Rpb24gY29tcG9uZW50IGNvbGxlY3Rpb24gbWVtYmVyIG11c3QgYmUgYSBub24tbnVsbCBtYXAgb2JqZWN0JyxcbiAgSU5URVJBQ1RJT05fQ09NUE9ORU5UX1NIT1VMRF9CRV9BUlJBWTogICAgICAgICAgICAnVGhpcyBpbnRlcmFjdGlvbiBjb21wb25lbnQgY29sbGVjdGlvbiBwcm9wZXJ0eSBzaG91bGQgYmUgYW4gYXJyYXkuJyxcbiAgSU5URVJBQ1RJT05fVFlQRV9NVVNUX0JFX0NNSTogICAgICAgICAgICAgICAgICAgICAnSWYgcHJlc2VudCwgdGhlIFwiaW50ZXJhY3Rpb25UeXBlXCIgdmFsdWUgbXVzdCBiZSBhIENNSSBpbnRlcmFjdGlvbiB0eXBlIG9wdGlvbi4nLFxuICBJTlRFUkFDVElPTl9UWVBFX01VU1RfQkVfVkFMSUQ6ICAgICAgICAgICAgICAgICAgICdUaGlzIGludGVyYWN0aW9uIGNvbXBvbmVudCBjb2xsZWN0aW9uIHByb3BlcnR5IGlzIG5vdCBhc3NvY2lhdGVkIHdpdGggdGhlIHByZXNlbnQgaW50ZXJhY3Rpb25UeXBlIG9mOiAnLFxuICBJTlZBTElEX0pTT046ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdJbnZhbGlkIEpTT04uIFRoZSBzdGF0ZW1lbnQgY291bGQgbm90IGJlIHBhcnNlZC4nLFxuICBMQU5HVUFHRV9NQVBfS0VZX0lOVkFMSUQ6ICAgICAgICAgICAgICAgICAgICAgICAgICdrZXksIExhbmd1YWdlIGRvZXMgbm90IGNvbmZvcm0gdG8gUkZDIDU2NDYnLFxuICBMQU5HVUFHRV9NQVBfS0VZX01VU1RfQkVfU1RSSU5HOiAgICAgICAgICAgICAgICAgICdrZXk6IExhbmd1YWdlIE1hcCB2YWx1ZSBzaG91bGQgYmUgYSBTdHJpbmcsIGJ1dCB3YXMgbm90JyxcbiAgTEFOR1VBR0VfTUFQU19NVVNUX05PVF9CRV9OVUxMOiAgICAgICAgICAgICAgICAgICAnTGFuZ3VhZ2UgTWFwcywgd2hlbiBwcmVzZW50LCBtdXN0IGJlIG5vbi1udWxsIG1hcCBvYmplY3RzJyxcbiAgTEFOR1VBR0VfTVVTVF9CRV9TVFJJTkc6ICAgICAgICAgICAgICAgICAgICAgICAgICAnVGhlIGxhbmd1YWdlIHByb3BlcnR5IG11c3QgYmUgZW5jb2RlZCBhcyBhbiBSRkMgNTY0NiBjb21wbGlhbnQgc3RyaW5nLCBidXQgd2FzIG5vdC4nLFxuICBMRU5HVEhfTVVTVF9CRV9JTlRFR0VSOiAgICAgICAgICAgICAgICAgICAgICAgICAgICdcImxlbmd0aFwiIHByb3BlcnR5IG11c3QgYmUgcHJvdmlkZWQgd2l0aCBhbiBpbnRlZ2VyIHZhbHVlJyxcbiAgTUFYX01VU1RfQkVfR1JFQVRFUl9USEFOX01JTjogICAgICAgICAgICAgICAgICAgICAnSWYgYm90aCBcIm1heFwiIGFuZCBcIm1pblwiIGFyZSBwcmVzZW50LCB0aGUgbWF4IHByb3BlcnR5IHZhbHVlIHNob3VsZCBiZSBncmVhdGVyIHRoYW4gbWluJyxcbiAgTUVNQkVSX01VU1RfQkVfUFJPVklERURfRk9SX0FOT05ZTU9VU19HUk9VUFM6ICAgICAnXCJtZW1iZXJcIiBwcm9wZXJ0eSBtdXN0IGJlIHByb3ZpZGVkIGZvciBBbm9ueW1vdXMgR3JvdXBzLicsXG4gIE1VU1RfQkVfQk9PTEVBTl9QUkVTRU5UOiAgICAgICAgICAgICAgICAgICAgICAgICAgJ3Byb3BlcnR5IHdhcyByZXF1aXJlZCB0byBiZSBhIEJvb2xlYW4gYnV0IHdhcyBhYnNlbnQuJyxcbiAgTVVTVF9CRV9CT09MRUFOOiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAncHJvcGVydHksIGlmIHByZXNlbnQsIG11c3QgYmUgYSBCb29sZWFuLicsXG4gIE1VU1RfQkVfSVJJX1NUUklORzogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ3Byb3BlcnR5LCBpZiBwcmVzZW50LCBzaG91bGQgYmUgYSBJUkktbGlrZSBhYnNvbHV0ZSBVUkkgcGVyIFJGQyAzOTg3LicsXG4gIE1VU1RfQkVfTlVNQkVSX1BSRVNFTlQ6ICAgICAgICAgICAgICAgICAgICAgICAgICAgJ3Byb3BlcnR5IHdhcyByZXF1aXJlZCB0byBiZSBhIE51bWJlciBidXQgd2FzIGFic2VudC4nLFxuICBNVVNUX0JFX05VTUJFUjogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdwcm9wZXJ0eSwgaWYgcHJlc2VudCwgbXVzdCBiZSBhIE51bWJlci4nLFxuICBNVVNUX0JFX1BSRVNFTlQ6ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdwcm9wZXJ0eSB3YXMgcmVxdWlyZWQgdG8gYmUgYSBzdHJpbmcgYnV0IHdhcyBhYnNlbnQuJyxcbiAgTVVTVF9CRV9TVFJJTkc6ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAncHJvcGVydHksIGlmIHByZXNlbnQsIG11c3QgYmUgYSBzdHJpbmcuJyxcbiAgTVVTVF9CRV9VUklfUFJFU0VOVDogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAncHJvcGVydHkgd2FzIHJlcXVpcmVkIHRvIGJlIGEgVVJJIHN0cmluZyBidXQgd2FzIGFic2VudC4nLFxuICBNVVNUX0JFX1VSSV9TVFJJTkc6ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdwcm9wZXJ0eSwgaWYgcHJlc2VudCwgbXVzdCBiZSBhIFVSSSBzdHJpbmcuJyxcbiAgT0JKRUNUX01VU1RfQkVfREVGSU5FRDogICAgICAgICAgICAgICAgICAgICAgICAgICAnXCJvYmplY3RcIiBwcm9wZXJ0eSBtdXN0IGJlIHByb3ZpZGVkLicsXG4gIE9CSkVDVF9NVVNUX0JFX05PTl9OVUxMX01BUF9PQkpFQ1Q6ICAgICAgICAgICAgICAgJ1wib2JqZWN0XCIgcHJvcGVydHkgbXVzdCBiZSBhIG5vbi1udWxsIG1hcCBvYmplY3QuJyxcbiAgT0JKRUNUX1RZUEVfTVVTVF9CRV9TVEFURU1FTlRfUkVGOiAgICAgICAgICAgICAgICAnXCJvYmplY3RUeXBlXCIgcHJvcGVydHkgdmFsdWUgbXVzdCBiZSBcIlN0YXRlbWVudFJlZlwiIGZvciBzdGF0ZW1lbnQgcmVmZXJlbmNlIG9iamVjdHMuJyxcbiAgT0JKRUNUX1RZUEVfTVVTVF9CRV9WQUxJRF9PUFRJT046ICAgICAgICAgICAgICAgICAnb2JqZWN0XFwncyBcIm9iamVjdFR5cGVcIiBkaWQgbm90IG1hdGNoIGEgdmFsaWQgb3B0aW9uJyxcbiAgUkFXX01VU1RfQkVfR1JFQVRFUl9USEFOX01JTjogICAgICAgICAgICAgICAgICAgICAnSWYgYm90aCBcInJhd1wiIGFuZCBcIm1pblwiIGFyZSBwcmVzZW50LCB0aGUgcmF3IHByb3BlcnR5IHZhbHVlIHNob3VsZCBiZSBncmVhdGVyIHRoYW4gbWluJyxcbiAgUkFXX01VU1RfQkVfTEVTU19USEFOX01BWDogICAgICAgICAgICAgICAgICAgICAgICAnSWYgYm90aCBcInJhd1wiIGFuZCBcIm1heFwiIGFyZSBwcmVzZW50LCB0aGUgcmF3IHByb3BlcnR5IHZhbHVlIHNob3VsZCBiZSBsZXNzIHRoYW4gbWF4JyxcbiAgUkVHSVNUUkFUSU9OX01VU1RfQkVfVVVJRF9TVFJJTkc6ICAgICAgICAgICAgICAgICAnSWYgcHJlc2VudCwgdGhlIHJlZ2lzdHJhdGlvbiBwcm9wZXJ0eSBtdXN0IGJlIGEgVVVJRCBzdHJpbmcuJyxcbiAgUkVTVUxUX01VU1RfQkVfTUFQX09CSkVDVDogICAgICAgICAgICAgICAgICAgICAgICAnSWYgcHJlc2VudCwgdGhlIHJlc3VsdCBtdXN0IGJlIGEgbWFwIG9iamVjdCcsXG4gIFJFVklTSU9OX01VU1RfQkVfQUdFTlRfT1JfR1JPVVA6ICAgICAgICAgICAgICAgICAgJ1RoZSByZXZpc2lvbiBwcm9wZXJ0eSBtdXN0IG5vdCBiZSB1c2VkIGlmIHRoZSBTdGF0ZW1lbnRcXCdzIE9iamVjdCBpcyBhbiBBZ2VudCBvciBHcm91cC4nLFxuICBTQ0FMRURfTVVTVF9CRV9CRVRXRUVOXzBfMTogICAgICAgICAgICAgICAgICAgICAgICdJZiBwcmVzZW50LCB0aGUgc2NhbGVkIHByb3BlcnR5IHZhbHVlIG11c3QgYmUgYmV0d2VlbiAwIGFuZCAxJyxcbiAgU0hBMl9NVVNUX0JFX1BST1ZJREVEX09OX0FUVEFDSE1FTlRfT0JKRUNUUzogICAgICAnXCJzaGEyXCIgcHJvcGVydHkgbXVzdCBiZSBwcm92aWRlZCBvbiBhdHRhY2htZW50IG9iamVjdHMnLFxuICBTSEEyX01VU1RfQ09OVEFJTl9CQVNFXzY0X1NUUklORzogICAgICAgICAgICAgICAgICdcInNoYTJcIiBwcm9wZXJ0eSBtdXN0IGNvbnRhaW4gYSBzdHJpbmcgd2l0aCBiYXNlNjQgY29udGVudHMnLFxuICBTVEFURU1FTlRfQVJHVU1FTlRfSVNfTk9UX1ZBTElEOiAgICAgICAgICAgICAgICAgICdTdGF0ZW1lbnQgYXJndW1lbnQgcHJvdmlkZWQgd2FzIG5vdCBhIHZhbGlkIG9iamVjdCBvciBhIHZhbGlkIEpTT04gc3RyaW5nLicsXG4gIFNUQVRFTUVOVF9BUkdVTUVOVF9NVVNUX0JFX1BST1ZJREVEOiAgICAgICAgICAgICAgJ05vIHN0YXRlbWVudCBhcmd1bWVudCBwcm92aWRlZC4nLFxuICBTVEFURU1FTlRfTVVTVF9CRV9QQVJTRURfQ09SUkVDVExZOiAgICAgICAgICAgICAgICdOdWxsIG9yIG5vbi1vYmplY3Qgc3RhdGVtZW50IHZhbHVlIHBhcnNlZCBmcm9tIHByb3ZpZGVkIHN0YXRtZW50IEpTT04uJyxcbiAgU1RBVEVNRU5UX01VU1RfTk9UX0JFX05VTEw6ICAgICAgICAgICAgICAgICAgICAgICAnTnVsbCBzdGF0ZW1lbnQgYXJndW1lbnQgcHJvdmlkZWQuJyxcbiAgU1RBVEVNRU5UX1JFRl9NVVNUX05PVF9CRV9OVUxMX01BUF9PQkpFQ1RTOiAgICAgICAnU3RhdGVtZW50UmVmIGluc3RhbmNlcyBtdXN0IGJlIG5vbi1udWxsIG1hcCBvYmplY3RzJyxcbiAgU1VCX1NUQVRFTUVOVF9NVVNUX05PVF9DT05UQUlOX1NVQl9TVEFURU1FTlQ6ICAgICAnQSBTdWJTdGF0ZW1lbnQgbXVzdCBub3QgY29udGFpbiBhIFN1YlN0YXRlbWVudCcsXG4gIFVORVhQRUNURUQ6ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1VuZXhwZWN0ZWQgcHJvcGVydHkgbm90IHBlcm1pdHRlZCcsXG4gIFZFUkJfTVVTVF9CRV9QUk9WSURFRDogICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1ZlcmIgbXVzdCBiZSBwcm92aWRlZCcsXG4gIFZFUkJfTVVTVF9OT1RfQkVfTlVMTDogICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1ZlcmIgcHJvcGVydHkgdmFsdWUgbXVzdCBhIG5vbi1udWxsIG1hcCBvYmplY3QuJyxcbiAgVkVSU0lPTl9NVVNUX0NPTVBMWV9TRU1BTlRJQ19WRVJTSU9OSU5HOiAgICAgICAgICAnXCJ2ZXJzaW9uXCIgbXVzdCBiZSBhIG5vbi1udWxsIHN0cmluZyB0aGF0IGNvbXBsaWVzIHdpdGggU2VtYW50aWMgVmVyc2lvbmluZyAxLjAuMCdcbn0pO1xuXG5leHBvcnQge3hhcGlFcnJvckxldmVsc307XG5leHBvcnQge3hhcGlWYWxpZGF0aW9uRXJyb3JzfTtcbiIsIid1c2Ugc3RyaWN0JztcblxuY29uc3QgeGFwaUdlbmVyYWwgPSBPYmplY3QuZnJlZXplKHtcbiAgRklSU1RfUkVQT1JUX1ZFUlNUSU9OICAgICAgICAgICAgIDogJzEuMC4wJyxcbiAgR1JPVVBfQVVUSE9SSVRZX0FHRU5UX01FTUJFUlMgICAgIDogMixcbiAgSU5URVJBQ1RJT05fREVGSU5JVElPTl9UWVBFICAgICAgIDogJ2h0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS9hY3Rpdml0aWVzL2NtaS5pbnRlcmFjdGlvbicsXG4gIE1BWF9TQ0FMRURfVkFMVUUgICAgICAgICAgICAgICAgICA6IDEsXG4gIE1JTl9TQ0FMRURfVkFMVUUgICAgICAgICAgICAgICAgICA6IDAsXG4gIE5PX0lOREVYX0ZPVU5EICAgICAgICAgICAgICAgICAgICA6IC0xLFxuICBOVU1FUl9PRl9TUEVDSUZJRURfSUZJX1BST1BFUlRJRVMgOiAxXG59KTtcblxuZXhwb3J0IHt4YXBpR2VuZXJhbH07XG4iLCIndXNlIHN0cmljdCc7XG5cbmV4cG9ydCBjb25zdCBpbnRlcmFjdGlvblR5cGVzID0gT2JqZWN0LmZyZWV6ZSh7XG4gIENIT0lDRTogICAgICAgJ2Nob2ljZScsXG4gIEZJTExfSU46ICAgICAgJ2ZpbGwtaW4nLFxuICBMSUtFUlQ6ICAgICAgICdsaWtlcnQnLFxuICBMT05HX0ZJTExfSU46ICdsb25nLWZpbGwtaW4nLFxuICBNQVRDSElORzogICAgICdtYXRjaGluZycsXG4gIE5VTUVSSUM6ICAgICAgJ251bWVyaWMnLFxuICBPVEhFUjogICAgICAgICdvdGhlcicsXG4gIFBFUkZPUk1BTkNFOiAgJ3BlcmZvcm1hbmNlJyxcbiAgU0VRVUVOQ0lORzogICAnc2VxdWVuY2luZycsXG4gIFRSVUVfRkFMU0U6ICAgJ3RydWUtZmFsc2UnXG59KTtcblxuZXhwb3J0IGNvbnN0IHhhcGlWYWxpZGF0aW9uSW50ZXJhY3Rpb25UeXBlcyA9IE9iamVjdC5mcmVlemUoW1xuICBpbnRlcmFjdGlvblR5cGVzLkNIT0lDRSxcbiAgaW50ZXJhY3Rpb25UeXBlcy5GSUxMX0lOLFxuICBpbnRlcmFjdGlvblR5cGVzLkxJS0VSVCxcbiAgaW50ZXJhY3Rpb25UeXBlcy5MT05HX0ZJTExfSU4sXG4gIGludGVyYWN0aW9uVHlwZXMuTUFUQ0hJTkcsXG4gIGludGVyYWN0aW9uVHlwZXMuTlVNRVJJQyxcbiAgaW50ZXJhY3Rpb25UeXBlcy5PVEhFUixcbiAgaW50ZXJhY3Rpb25UeXBlcy5QRVJGT1JNQU5DRSxcbiAgaW50ZXJhY3Rpb25UeXBlcy5TRVFVRU5DSU5HLFxuICBpbnRlcmFjdGlvblR5cGVzLlRSVUVfRkFMU0Vcbl0pO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG5jb25zdCBwcm9wZXJ0aWVzID0gT2JqZWN0LmZyZWV6ZSh7XG4gIEFDQ09VTlQ6ICAgICAgICAgICAgICAgICAgICdhY2NvdW50JyxcbiAgQUNUSVZJVFk6ICAgICAgICAgICAgICAgICAgJ2FjdGl2aXR5JyxcbiAgQUNUT1I6ICAgICAgICAgICAgICAgICAgICAgJ2FjdG9yJyxcbiAgQUdFTlQ6ICAgICAgICAgICAgICAgICAgICAgJ2FnZW50JyxcbiAgQVRUQUNITUVOVDogICAgICAgICAgICAgICAgJ2F0dGFjaG1lbnQnLFxuICBBVFRBQ0hNRU5UUzogICAgICAgICAgICAgICAnYXR0YWNobWVudHMnLFxuICBBVVRIT1JJVFk6ICAgICAgICAgICAgICAgICAnYXV0aG9yaXR5JyxcbiAgQ0FURUdPUlk6ICAgICAgICAgICAgICAgICAgJ2NhdGVnb3J5JyxcbiAgQ0hPSUNFOiAgICAgICAgICAgICAgICAgICAgJ2Nob2ljZScsXG4gIENIT0lDRVM6ICAgICAgICAgICAgICAgICAgICdjaG9pY2VzJyxcbiAgQ09NUExFVElPTjogICAgICAgICAgICAgICAgJ2NvbXBsZXRpb24nLFxuICBDT05URU5UX1RZUEU6ICAgICAgICAgICAgICAnY29udGVudFR5cGUnLFxuICBDT05URVhUX0FDVElWSVRJRVM6ICAgICAgICAnY29udGV4dEFjdGl2aXRpZXMnLFxuICBDT05URVhUOiAgICAgICAgICAgICAgICAgICAnY29udGV4dCcsXG4gIENPUlJFQ1RfUkVTUE9OU0VTX1BBVFRFUk46ICdjb3JyZWN0UmVzcG9uc2VzUGF0dGVybicsXG4gIERBVEVfVElNRTogICAgICAgICAgICAgICAgICdkYXRlVGltZScsXG4gIERFRklOSVRJT046ICAgICAgICAgICAgICAgICdkZWZpbml0aW9uJyxcbiAgREVTQ1JJUFRJT046ICAgICAgICAgICAgICAgJ2Rlc2NyaXB0aW9uJyxcbiAgRElTUExBWTogICAgICAgICAgICAgICAgICAgJ2Rpc3BsYXknLFxuICBEVVJBVElPTjogICAgICAgICAgICAgICAgICAnZHVyYXRpb24nLFxuICBFWFRFTlNJT05TOiAgICAgICAgICAgICAgICAnZXh0ZW5zaW9ucycsXG4gIEZJTEVfVVJMOiAgICAgICAgICAgICAgICAgICdmaWxlVXJsJyxcbiAgR1JPVVA6ICAgICAgICAgICAgICAgICAgICAgJ2dyb3VwJyxcbiAgR1JPVVBJTkc6ICAgICAgICAgICAgICAgICAgJ2dyb3VwaW5nJyxcbiAgSE9NRV9QQUdFOiAgICAgICAgICAgICAgICAgJ2hvbWVQYWdlJyxcbiAgSUQ6ICAgICAgICAgICAgICAgICAgICAgICAgJ2lkJyxcbiAgSU5TVFJVQ1RPUjogICAgICAgICAgICAgICAgJ2luc3RydWN0b3InLFxuICBJTlRFUkFDVElPTl9DT01QT05FTlRTOiAgICAnaW50ZXJhY3Rpb25Db21wb25lbnRzJyxcbiAgSU5URVJBQ1RJT05fVFlQRTogICAgICAgICAgJ2ludGVyYWN0aW9uVHlwZScsXG4gIExBTkdVQUdFX01BUDogICAgICAgICAgICAgICdsYW5ndWFnZU1hcCcsXG4gIExBTkdVQUdFOiAgICAgICAgICAgICAgICAgICdsYW5ndWFnZScsXG4gIExFTkdUSDogICAgICAgICAgICAgICAgICAgICdsZW5ndGgnLFxuICBMSUtFUlQ6ICAgICAgICAgICAgICAgICAgICAnbGlrZXJ0JyxcbiAgTUFUQ0hJTkc6ICAgICAgICAgICAgICAgICAgJ21hdGNoaW5nJyxcbiAgTUFYOiAgICAgICAgICAgICAgICAgICAgICAgJ21heCcsXG4gIE1CT1hfU0hBXzFfU1VNOiAgICAgICAgICAgICdtYm94X3NoYTFzdW0nLFxuICBNQk9YOiAgICAgICAgICAgICAgICAgICAgICAnbWJveCcsXG4gIE1FTUJFUjogICAgICAgICAgICAgICAgICAgICdtZW1iZXInLFxuICBNSU46ICAgICAgICAgICAgICAgICAgICAgICAnbWluJyxcbiAgTU9SRV9JTkZPOiAgICAgICAgICAgICAgICAgJ21vcmVJbmZvJyxcbiAgTkFNRTogICAgICAgICAgICAgICAgICAgICAgJ25hbWUnLFxuICBPQkpFQ1RfVFlQRTogICAgICAgICAgICAgICAnb2JqZWN0VHlwZScsXG4gIE9CSkVDVDogICAgICAgICAgICAgICAgICAgICdvYmplY3QnLFxuICBPUEVOX0lEOiAgICAgICAgICAgICAgICAgICAnb3BlbklEJyxcbiAgT1RIRVI6ICAgICAgICAgICAgICAgICAgICAgJ290aGVyJyxcbiAgUEFSRU5UOiAgICAgICAgICAgICAgICAgICAgJ3BhcmVudCcsXG4gIFBFUkZPUk1BTkNFOiAgICAgICAgICAgICAgICdwZXJmb3JtYW5jZScsXG4gIFBMQVRGT1JNOiAgICAgICAgICAgICAgICAgICdwbGF0Zm9ybScsXG4gIFJBVzogICAgICAgICAgICAgICAgICAgICAgICdyYXcnLFxuICBSRUdJU1RSQVRJT046ICAgICAgICAgICAgICAncmVnaXN0cmF0aW9uJyxcbiAgUkVTUE9OU0U6ICAgICAgICAgICAgICAgICAgJ3Jlc3BvbnNlJyxcbiAgUkVTVUxUOiAgICAgICAgICAgICAgICAgICAgJ3Jlc3VsdCcsXG4gIFJFVklTSU9OOiAgICAgICAgICAgICAgICAgICdyZXZpc2lvbicsXG4gIFNDQUxFOiAgICAgICAgICAgICAgICAgICAgICdzY2FsZScsXG4gIFNDQUxFRDogICAgICAgICAgICAgICAgICAgICdzY2FsZWQnLFxuICBTQ09SRTogICAgICAgICAgICAgICAgICAgICAnc2NvcmUnLFxuICBTRVFVRU5DSU5HOiAgICAgICAgICAgICAgICAnc2VxdWVuY2luZycsXG4gIFNIQTI6ICAgICAgICAgICAgICAgICAgICAgICdzaGEyJyxcbiAgU09VUkNFOiAgICAgICAgICAgICAgICAgICAgJ3NvdXJjZScsXG4gIFNUQVRFTUVOVF9SRUY6ICAgICAgICAgICAgICdzdGF0ZW1lbnRSZWYnLFxuICBTVEFURU1FTlQ6ICAgICAgICAgICAgICAgICAnc3RhdGVtZW50JyxcbiAgU1RFUFM6ICAgICAgICAgICAgICAgICAgICAgJ3N0ZXBzJyxcbiAgU1RPUkVEOiAgICAgICAgICAgICAgICAgICAgJ3N0b3JlZCcsXG4gIFNVQl9DT05URVhUOiAgICAgICAgICAgICAgICdzdWJDb250ZXh0JyxcbiAgU1VDQ0VTUzogICAgICAgICAgICAgICAgICAgJ3N1Y2Nlc3MnLFxuICBUQVJHRVQ6ICAgICAgICAgICAgICAgICAgICAndGFyZ2V0JyxcbiAgVEVBTTogICAgICAgICAgICAgICAgICAgICAgJ3RlYW0nLFxuICBUSU1FU1RBTVA6ICAgICAgICAgICAgICAgICAndGltZXN0YW1wJyxcbiAgVFlQRTogICAgICAgICAgICAgICAgICAgICAgJ3R5cGUnLFxuICBVU0FHRV9UWVBFOiAgICAgICAgICAgICAgICAndXNhZ2VUeXBlJyxcbiAgVkVSQjogICAgICAgICAgICAgICAgICAgICAgJ3ZlcmInLFxuICBWRVJTSU9OOiAgICAgICAgICAgICAgICAgICAndmVyc2lvbidcbn0pO1xuXG5jb25zdCBvYmplY3RUeXBlcyA9IE9iamVjdC5mcmVlemUoe1xuICBHUk9VUDogICAgICAgICAnR3JvdXAnLFxuICBBR0VOVDogICAgICAgICAnQWdlbnQnLFxuICBBQ1RJVklUWTogICAgICAnQWN0aXZpdHknLFxuICBTVEFURU1FTlRfUkVGOiAnU3RhdGVtZW50UmVmJyxcbiAgU1VCX1NUQVRFTUVOVDogJ1N1YlN0YXRlbWVudCdcbn0pO1xuXG5jb25zdCB4YXBpVmFsaWRhdGlvbklmaVByb3BlcnR5TmFtZXMgPSBPYmplY3QuZnJlZXplKFtcbiAgcHJvcGVydGllcy5BQ0NPVU5ULFxuICBwcm9wZXJ0aWVzLk1CT1hfU0hBXzFfU1VNLFxuICBwcm9wZXJ0aWVzLk1CT1gsXG4gIHByb3BlcnRpZXMuT1BFTl9JRFxuXSk7XG5cbmNvbnN0IHhBcGlWYWxpZE9iamVjdFR5cGVzID0gT2JqZWN0LmZyZWV6ZShbXG4gIG9iamVjdFR5cGVzLkdST1VQLFxuICBvYmplY3RUeXBlcy5BR0VOVCxcbiAgb2JqZWN0VHlwZXMuQUNUSVZJVFksXG4gIG9iamVjdFR5cGVzLlNUQVRFTUVOVF9SRUYsXG4gIG9iamVjdFR5cGVzLlNVQl9TVEFURU1FTlRcbl0pO1xuXG5jb25zdCB4YXBpV2hpdGVMaXN0UHJvcGVydGllcyA9IE9iamVjdC5mcmVlemUoe1xuICBJRkk6IFtcbiAgICBwcm9wZXJ0aWVzLkhPTUVfUEFHRSxcbiAgICBwcm9wZXJ0aWVzLk5BTUVcbiAgXSxcbiAgVVJJOiBbXG4gICAgcHJvcGVydGllcy5JRCxcbiAgICBwcm9wZXJ0aWVzLkRJU1BMQVlcbiAgXSxcbiAgQ09NUE9ORU5UX0FSUkFZOiBbXG4gICAgcHJvcGVydGllcy5JRCxcbiAgICBwcm9wZXJ0aWVzLkRFU0NSSVBUSU9OXG4gIF0sXG4gIEFDVElWSVRZX0RFRklOSVRJT046IFtcbiAgICBwcm9wZXJ0aWVzLk5BTUUsXG4gICAgcHJvcGVydGllcy5ERVNDUklQVElPTixcbiAgICBwcm9wZXJ0aWVzLlRZUEUsXG4gICAgcHJvcGVydGllcy5NT1JFX0lORk8sXG4gICAgcHJvcGVydGllcy5FWFRFTlNJT05TLFxuICAgIHByb3BlcnRpZXMuSU5URVJBQ1RJT05fVFlQRSxcbiAgICBwcm9wZXJ0aWVzLkNPUlJFQ1RfUkVTUE9OU0VTX1BBVFRFUk4sXG4gICAgcHJvcGVydGllcy5DSE9JQ0VTLFxuICAgIHByb3BlcnRpZXMuU0NBTEUsXG4gICAgcHJvcGVydGllcy5TT1VSQ0UsXG4gICAgcHJvcGVydGllcy5UQVJHRVQsXG4gICAgcHJvcGVydGllcy5TVEVQU1xuICBdLFxuICBBQ1RJVklUWTogW1xuICAgIHByb3BlcnRpZXMuT0JKRUNUX1RZUEUsXG4gICAgcHJvcGVydGllcy5JRCxcbiAgICBwcm9wZXJ0aWVzLkRFRklOSVRJT05cbiAgXSxcbiAgU1RBVEVNRU5UX1JFRjogW1xuICAgIHByb3BlcnRpZXMuSUQsXG4gICAgcHJvcGVydGllcy5PQkpFQ1RfVFlQRVxuICBdLFxuICBTQ09SRTogW1xuICAgIHByb3BlcnRpZXMuU0NBTEVELFxuICAgIHByb3BlcnRpZXMuUkFXLFxuICAgIHByb3BlcnRpZXMuTUlOLFxuICAgIHByb3BlcnRpZXMuTUFYXG4gIF0sXG4gIFJFU1VMVDogW1xuICAgIHByb3BlcnRpZXMuU0NPUkUsXG4gICAgcHJvcGVydGllcy5TVUNDRVNTLFxuICAgIHByb3BlcnRpZXMuQ09NUExFVElPTixcbiAgICBwcm9wZXJ0aWVzLlJFU1BPTlNFLFxuICAgIHByb3BlcnRpZXMuRFVSQVRJT04sXG4gICAgcHJvcGVydGllcy5FWFRFTlNJT05TXG4gIF0sXG4gIEFUVEFDSE1FTlQ6IFtcbiAgICBwcm9wZXJ0aWVzLlVTQUdFX1RZUEUsXG4gICAgcHJvcGVydGllcy5ESVNQTEFZLFxuICAgIHByb3BlcnRpZXMuREVTQ1JJUFRJT04sXG4gICAgcHJvcGVydGllcy5DT05URU5UX1RZUEUsXG4gICAgcHJvcGVydGllcy5MRU5HVEgsXG4gICAgcHJvcGVydGllcy5TSEEyLFxuICAgIHByb3BlcnRpZXMuRklMRV9VUkxcbiAgXSxcbiBBR0VOVDogW1xuICAgcHJvcGVydGllcy5PQkpFQ1RfVFlQRSxcbiAgIHByb3BlcnRpZXMuTkFNRSxcbiAgIHByb3BlcnRpZXMuQUNDT1VOVCxcbiAgIHByb3BlcnRpZXMuTUJPWF9TSEFfMV9TVU0sXG4gICBwcm9wZXJ0aWVzLk1CT1gsXG4gICBwcm9wZXJ0aWVzLk9QRU5fSURcbiBdLFxuIEdST1VQOiBbXG4gICBwcm9wZXJ0aWVzLk9CSkVDVF9UWVBFLFxuICAgcHJvcGVydGllcy5OQU1FLFxuICAgcHJvcGVydGllcy5NRU1CRVIsXG4gICBwcm9wZXJ0aWVzLkFDQ09VTlQsXG4gICBwcm9wZXJ0aWVzLk1CT1hfU0hBXzFfU1VNLFxuICAgcHJvcGVydGllcy5NQk9YLFxuICAgcHJvcGVydGllcy5PUEVOX0lEXG4gXSxcbiBDT05URVhUX0FDVElWSVRJRVM6IFtcbiAgIHByb3BlcnRpZXMuUEFSRU5ULFxuICAgcHJvcGVydGllcy5HUk9VUElORyxcbiAgIHByb3BlcnRpZXMuQ0FURUdPUlksXG4gICBwcm9wZXJ0aWVzLk9USEVSXG4gXSxcbiBTVEFURU1FTlQ6IFtcbiAgIHByb3BlcnRpZXMuSUQsXG4gICBwcm9wZXJ0aWVzLkFDVE9SLFxuICAgcHJvcGVydGllcy5WRVJCLFxuICAgcHJvcGVydGllcy5PQkpFQ1QsXG4gICBwcm9wZXJ0aWVzLlJFU1VMVCxcbiAgIHByb3BlcnRpZXMuQ09OVEVYVCxcbiAgIHByb3BlcnRpZXMuVElNRVNUQU1QLFxuICAgcHJvcGVydGllcy5TVE9SRUQsXG4gICBwcm9wZXJ0aWVzLkFVVEhPUklUWSxcbiAgIHByb3BlcnRpZXMuVkVSU0lPTixcbiAgIHByb3BlcnRpZXMuQVRUQUNITUVOVFNcbiBdLFxuIFNVQl9TVEFURU1FTlQ6IFtcbiAgIHByb3BlcnRpZXMuQUNUT1IsXG4gICBwcm9wZXJ0aWVzLlZFUkIsXG4gICBwcm9wZXJ0aWVzLk9CSkVDVCxcbiAgIHByb3BlcnRpZXMuUkVTVUxULFxuICAgcHJvcGVydGllcy5DT05URVhULFxuICAgcHJvcGVydGllcy5USU1FU1RBTVAsXG4gICBwcm9wZXJ0aWVzLkFUVEFDSE1FTlRTLFxuICAgcHJvcGVydGllcy5PQkpFQ1RfVFlQRVxuIF0sXG4gRVhURU5TSU9OUzogW1xuICAgcHJvcGVydGllcy5SRUdJU1RSQVRJT04sXG4gICBwcm9wZXJ0aWVzLklOU1RSVUNUT1IsXG4gICBwcm9wZXJ0aWVzLlRFQU0sXG4gICBwcm9wZXJ0aWVzLkNPTlRFWFRfQUNUSVZJVElFUyxcbiAgIHByb3BlcnRpZXMuUkVWSVNJT04sXG4gICBwcm9wZXJ0aWVzLlBMQVRGT1JNLFxuICAgcHJvcGVydGllcy5MQU5HVUFHRSxcbiAgIHByb3BlcnRpZXMuU1RBVEVNRU5ULFxuICAgcHJvcGVydGllcy5FWFRFTlNJT05TXG4gXVxufSk7XG5cbmV4cG9ydCB7cHJvcGVydGllc307XG5leHBvcnQge29iamVjdFR5cGVzfTtcbmV4cG9ydCB7eGFwaVZhbGlkYXRpb25JZmlQcm9wZXJ0eU5hbWVzfTtcbmV4cG9ydCB7eEFwaVZhbGlkT2JqZWN0VHlwZXN9O1xuZXhwb3J0IHt4YXBpV2hpdGVMaXN0UHJvcGVydGllc307XG4iLCIndXNlIHN0cmljdCc7XG5cbmNvbnN0IHhhcGlWYWxpZGF0aW9uUmVnZXggPSBPYmplY3QuZnJlZXplKHtcbiAgVVVJRDogICAgICAgICAgICAgICAgL15bMC05YS1mXXs4fS1bMC05YS1mXXs0fS1bMC05YS1mXXs0fS1bMC05YS1mXXs0fS1bMC05YS1mXXsxMn0kL2ksXG4gIElTT184NjAxX0RVUkFUSU9OOiAgIC9eUCgoXFxkKyhbXFwuLF1cXGQrKT9ZKT8oXFxkKyhbXFwuLF1cXGQrKT9NKT8oXFxkKyhbXFwuLF1cXGQrKT9XKT8oXFxkKyhbXFwuLF1cXGQrKT9EKT8pPyhUKFxcZCsoW1xcLixdXFxkKyk/SCk/KFxcZCsoW1xcLixdXFxkKyk/TSk/KFxcZCsoW1xcLixdXFxkKyk/Uyk/KT8kLyxcbiAgSVNPXzg2MDFfREFURV9USU1FOiAgL14oXFxkezR9fFsrXFwtXVxcZHs2fSkoPzotKFxcZHsyfSkoPzotKFxcZHsyfSkpPyk/KD86VChcXGR7Mn0pOihcXGR7Mn0pKD86OihcXGR7Mn0pKD86XFwuKFxcZHszfSkpPyk/KD86KFopfChbK1xcLV0pKFxcZHsyfSkoPzo6KFxcZHsyfSkpPyk/KT8kLyxcbiAgTUFJTFRPX1VSSTogICAgICAgICAgL15tYWlsdG86LyxcbiAgQ09OVEFJTlNfV0hJVEVTUEFDRTogL1xccy9nLFxuICBTRU1WRVJfMV9QXzBfUF8wOiAgICAvXigoXFxkKylcXC4oXFxkKylcXC4oXFxkKykpKD86LShbXFxkQS1aYS16XFwtXSspKT8kLyxcbiAgQkFTRV82NDogICAgICAgICAgICAgL14oPzpbQS1aYS16MC05XFwrXFwvXXs0fSkqKD86W0EtWmEtejAtOVxcK1xcL117Mn09PXxbQS1aYS16MC05XFwrXFwvXXszfT18W0EtWmEtejAtOVxcK1xcL117NH0pJC8sXG4gIElSSTogICAgICAgICAgICAgICAgIC9eW2Etel0oPzpbXFwtYS16MC05XFwrXFwuXSkqOig/OlxcL1xcLyg/Oig/OiVbMC05YS1mXVswLTlhLWZdfFtcXC1hLXowLTlcXC5fflxcdTAwQTAtXFx1RDdGRlxcdUY5MDAtXFx1RkRDRlxcdUZERjAtXFx1RkZFRlxcdTEwMDAwLVxcdTFGRkZEXFx1MjAwMDAtXFx1MkZGRkRcXHUzMDAwMC1cXHUzRkZGRFxcdTQwMDAwLVxcdTRGRkZEXFx1NTAwMDAtXFx1NUZGRkRcXHU2MDAwMC1cXHU2RkZGRFxcdTcwMDAwLVxcdTdGRkZEXFx1ODAwMDAtXFx1OEZGRkRcXHU5MDAwMC1cXHU5RkZGRFxcdUEwMDAwLVxcdUFGRkZEXFx1QjAwMDAtXFx1QkZGRkRcXHVDMDAwMC1cXHVDRkZGRFxcdUQwMDAwLVxcdURGRkZEXFx1RTEwMDAtXFx1RUZGRkQhXFwkJidcXChcXClcXCpcXCssOz06XSkqQCk/KD86XFxbKD86KD86KD86WzAtOWEtZl17MSw0fTopezZ9KD86WzAtOWEtZl17MSw0fTpbMC05YS1mXXsxLDR9fCg/OlswLTldfFsxLTldWzAtOV18MVswLTldWzAtOV18MlswLTRdWzAtOV18MjVbMC01XSkoPzpcXC4oPzpbMC05XXxbMS05XVswLTldfDFbMC05XVswLTldfDJbMC00XVswLTldfDI1WzAtNV0pKXszfSl8OjooPzpbMC05YS1mXXsxLDR9Oil7NX0oPzpbMC05YS1mXXsxLDR9OlswLTlhLWZdezEsNH18KD86WzAtOV18WzEtOV1bMC05XXwxWzAtOV1bMC05XXwyWzAtNF1bMC05XXwyNVswLTVdKSg/OlxcLig/OlswLTldfFsxLTldWzAtOV18MVswLTldWzAtOV18MlswLTRdWzAtOV18MjVbMC01XSkpezN9KXwoPzpbMC05YS1mXXsxLDR9KT86Oig/OlswLTlhLWZdezEsNH06KXs0fSg/OlswLTlhLWZdezEsNH06WzAtOWEtZl17MSw0fXwoPzpbMC05XXxbMS05XVswLTldfDFbMC05XVswLTldfDJbMC00XVswLTldfDI1WzAtNV0pKD86XFwuKD86WzAtOV18WzEtOV1bMC05XXwxWzAtOV1bMC05XXwyWzAtNF1bMC05XXwyNVswLTVdKSl7M30pfCg/OlswLTlhLWZdezEsNH06WzAtOWEtZl17MSw0fSk/OjooPzpbMC05YS1mXXsxLDR9Oil7M30oPzpbMC05YS1mXXsxLDR9OlswLTlhLWZdezEsNH18KD86WzAtOV18WzEtOV1bMC05XXwxWzAtOV1bMC05XXwyWzAtNF1bMC05XXwyNVswLTVdKSg/OlxcLig/OlswLTldfFsxLTldWzAtOV18MVswLTldWzAtOV18MlswLTRdWzAtOV18MjVbMC01XSkpezN9KXwoPzooPzpbMC05YS1mXXsxLDR9Oil7MCwyfVswLTlhLWZdezEsNH0pPzo6KD86WzAtOWEtZl17MSw0fTopezJ9KD86WzAtOWEtZl17MSw0fTpbMC05YS1mXXsxLDR9fCg/OlswLTldfFsxLTldWzAtOV18MVswLTldWzAtOV18MlswLTRdWzAtOV18MjVbMC01XSkoPzpcXC4oPzpbMC05XXxbMS05XVswLTldfDFbMC05XVswLTldfDJbMC00XVswLTldfDI1WzAtNV0pKXszfSl8KD86KD86WzAtOWEtZl17MSw0fTopezAsM31bMC05YS1mXXsxLDR9KT86OlswLTlhLWZdezEsNH06KD86WzAtOWEtZl17MSw0fTpbMC05YS1mXXsxLDR9fCg/OlswLTldfFsxLTldWzAtOV18MVswLTldWzAtOV18MlswLTRdWzAtOV18MjVbMC01XSkoPzpcXC4oPzpbMC05XXxbMS05XVswLTldfDFbMC05XVswLTldfDJbMC00XVswLTldfDI1WzAtNV0pKXszfSl8KD86KD86WzAtOWEtZl17MSw0fTopezAsNH1bMC05YS1mXXsxLDR9KT86Oig/OlswLTlhLWZdezEsNH06WzAtOWEtZl17MSw0fXwoPzpbMC05XXxbMS05XVswLTldfDFbMC05XVswLTldfDJbMC00XVswLTldfDI1WzAtNV0pKD86XFwuKD86WzAtOV18WzEtOV1bMC05XXwxWzAtOV1bMC05XXwyWzAtNF1bMC05XXwyNVswLTVdKSl7M30pfCg/Oig/OlswLTlhLWZdezEsNH06KXswLDV9WzAtOWEtZl17MSw0fSk/OjpbMC05YS1mXXsxLDR9fCg/Oig/OlswLTlhLWZdezEsNH06KXswLDZ9WzAtOWEtZl17MSw0fSk/OjopfHZbMC05YS1mXStbXFwtYS16MC05XFwuX34hXFwkJidcXChcXClcXCpcXCssOz06XSspXFxdfCg/OlswLTldfFsxLTldWzAtOV18MVswLTldWzAtOV18MlswLTRdWzAtOV18MjVbMC01XSkoPzpcXC4oPzpbMC05XXxbMS05XVswLTldfDFbMC05XVswLTldfDJbMC00XVswLTldfDI1WzAtNV0pKXszfXwoPzolWzAtOWEtZl1bMC05YS1mXXxbXFwtYS16MC05XFwuX35cXHUwMEEwLVxcdUQ3RkZcXHVGOTAwLVxcdUZEQ0ZcXHVGREYwLVxcdUZGRUZcXHUxMDAwMC1cXHUxRkZGRFxcdTIwMDAwLVxcdTJGRkZEXFx1MzAwMDAtXFx1M0ZGRkRcXHU0MDAwMC1cXHU0RkZGRFxcdTUwMDAwLVxcdTVGRkZEXFx1NjAwMDAtXFx1NkZGRkRcXHU3MDAwMC1cXHU3RkZGRFxcdTgwMDAwLVxcdThGRkZEXFx1OTAwMDAtXFx1OUZGRkRcXHVBMDAwMC1cXHVBRkZGRFxcdUIwMDAwLVxcdUJGRkZEXFx1QzAwMDAtXFx1Q0ZGRkRcXHVEMDAwMC1cXHVERkZGRFxcdUUxMDAwLVxcdUVGRkZEIVxcJCYnXFwoXFwpXFwqXFwrLDs9QF0pKikoPzo6WzAtOV0qKT8oPzpcXC8oPzooPzolWzAtOWEtZl1bMC05YS1mXXxbXFwtYS16MC05XFwuX35cXHUwMEEwLVxcdUQ3RkZcXHVGOTAwLVxcdUZEQ0ZcXHVGREYwLVxcdUZGRUZcXHUxMDAwMC1cXHUxRkZGRFxcdTIwMDAwLVxcdTJGRkZEXFx1MzAwMDAtXFx1M0ZGRkRcXHU0MDAwMC1cXHU0RkZGRFxcdTUwMDAwLVxcdTVGRkZEXFx1NjAwMDAtXFx1NkZGRkRcXHU3MDAwMC1cXHU3RkZGRFxcdTgwMDAwLVxcdThGRkZEXFx1OTAwMDAtXFx1OUZGRkRcXHVBMDAwMC1cXHVBRkZGRFxcdUIwMDAwLVxcdUJGRkZEXFx1QzAwMDAtXFx1Q0ZGRkRcXHVEMDAwMC1cXHVERkZGRFxcdUUxMDAwLVxcdUVGRkZEIVxcJCYnXFwoXFwpXFwqXFwrLDs9OkBdKSkqKSp8XFwvKD86KD86KD86KD86JVswLTlhLWZdWzAtOWEtZl18W1xcLWEtejAtOVxcLl9+XFx1MDBBMC1cXHVEN0ZGXFx1RjkwMC1cXHVGRENGXFx1RkRGMC1cXHVGRkVGXFx1MTAwMDAtXFx1MUZGRkRcXHUyMDAwMC1cXHUyRkZGRFxcdTMwMDAwLVxcdTNGRkZEXFx1NDAwMDAtXFx1NEZGRkRcXHU1MDAwMC1cXHU1RkZGRFxcdTYwMDAwLVxcdTZGRkZEXFx1NzAwMDAtXFx1N0ZGRkRcXHU4MDAwMC1cXHU4RkZGRFxcdTkwMDAwLVxcdTlGRkZEXFx1QTAwMDAtXFx1QUZGRkRcXHVCMDAwMC1cXHVCRkZGRFxcdUMwMDAwLVxcdUNGRkZEXFx1RDAwMDAtXFx1REZGRkRcXHVFMTAwMC1cXHVFRkZGRCFcXCQmJ1xcKFxcKVxcKlxcKyw7PTpAXSkpKykoPzpcXC8oPzooPzolWzAtOWEtZl1bMC05YS1mXXxbXFwtYS16MC05XFwuX35cXHUwMEEwLVxcdUQ3RkZcXHVGOTAwLVxcdUZEQ0ZcXHVGREYwLVxcdUZGRUZcXHUxMDAwMC1cXHUxRkZGRFxcdTIwMDAwLVxcdTJGRkZEXFx1MzAwMDAtXFx1M0ZGRkRcXHU0MDAwMC1cXHU0RkZGRFxcdTUwMDAwLVxcdTVGRkZEXFx1NjAwMDAtXFx1NkZGRkRcXHU3MDAwMC1cXHU3RkZGRFxcdTgwMDAwLVxcdThGRkZEXFx1OTAwMDAtXFx1OUZGRkRcXHVBMDAwMC1cXHVBRkZGRFxcdUIwMDAwLVxcdUJGRkZEXFx1QzAwMDAtXFx1Q0ZGRkRcXHVEMDAwMC1cXHVERkZGRFxcdUUxMDAwLVxcdUVGRkZEIVxcJCYnXFwoXFwpXFwqXFwrLDs9OkBdKSkqKSopP3woPzooPzooPzolWzAtOWEtZl1bMC05YS1mXXxbXFwtYS16MC05XFwuX35cXHUwMEEwLVxcdUQ3RkZcXHVGOTAwLVxcdUZEQ0ZcXHVGREYwLVxcdUZGRUZcXHUxMDAwMC1cXHUxRkZGRFxcdTIwMDAwLVxcdTJGRkZEXFx1MzAwMDAtXFx1M0ZGRkRcXHU0MDAwMC1cXHU0RkZGRFxcdTUwMDAwLVxcdTVGRkZEXFx1NjAwMDAtXFx1NkZGRkRcXHU3MDAwMC1cXHU3RkZGRFxcdTgwMDAwLVxcdThGRkZEXFx1OTAwMDAtXFx1OUZGRkRcXHVBMDAwMC1cXHVBRkZGRFxcdUIwMDAwLVxcdUJGRkZEXFx1QzAwMDAtXFx1Q0ZGRkRcXHVEMDAwMC1cXHVERkZGRFxcdUUxMDAwLVxcdUVGRkZEIVxcJCYnXFwoXFwpXFwqXFwrLDs9OkBdKSkrKSg/OlxcLyg/Oig/OiVbMC05YS1mXVswLTlhLWZdfFtcXC1hLXowLTlcXC5fflxcdTAwQTAtXFx1RDdGRlxcdUY5MDAtXFx1RkRDRlxcdUZERjAtXFx1RkZFRlxcdTEwMDAwLVxcdTFGRkZEXFx1MjAwMDAtXFx1MkZGRkRcXHUzMDAwMC1cXHUzRkZGRFxcdTQwMDAwLVxcdTRGRkZEXFx1NTAwMDAtXFx1NUZGRkRcXHU2MDAwMC1cXHU2RkZGRFxcdTcwMDAwLVxcdTdGRkZEXFx1ODAwMDAtXFx1OEZGRkRcXHU5MDAwMC1cXHU5RkZGRFxcdUEwMDAwLVxcdUFGRkZEXFx1QjAwMDAtXFx1QkZGRkRcXHVDMDAwMC1cXHVDRkZGRFxcdUQwMDAwLVxcdURGRkZEXFx1RTEwMDAtXFx1RUZGRkQhXFwkJidcXChcXClcXCpcXCssOz06QF0pKSopKnwoPyEoPzolWzAtOWEtZl1bMC05YS1mXXxbXFwtYS16MC05XFwuX35cXHUwMEEwLVxcdUQ3RkZcXHVGOTAwLVxcdUZEQ0ZcXHVGREYwLVxcdUZGRUZcXHUxMDAwMC1cXHUxRkZGRFxcdTIwMDAwLVxcdTJGRkZEXFx1MzAwMDAtXFx1M0ZGRkRcXHU0MDAwMC1cXHU0RkZGRFxcdTUwMDAwLVxcdTVGRkZEXFx1NjAwMDAtXFx1NkZGRkRcXHU3MDAwMC1cXHU3RkZGRFxcdTgwMDAwLVxcdThGRkZEXFx1OTAwMDAtXFx1OUZGRkRcXHVBMDAwMC1cXHVBRkZGRFxcdUIwMDAwLVxcdUJGRkZEXFx1QzAwMDAtXFx1Q0ZGRkRcXHVEMDAwMC1cXHVERkZGRFxcdUUxMDAwLVxcdUVGRkZEIVxcJCYnXFwoXFwpXFwqXFwrLDs9OkBdKSkpKD86XFw/KD86KD86JVswLTlhLWZdWzAtOWEtZl18W1xcLWEtejAtOVxcLl9+XFx1MDBBMC1cXHVEN0ZGXFx1RjkwMC1cXHVGRENGXFx1RkRGMC1cXHVGRkVGXFx1MTAwMDAtXFx1MUZGRkRcXHUyMDAwMC1cXHUyRkZGRFxcdTMwMDAwLVxcdTNGRkZEXFx1NDAwMDAtXFx1NEZGRkRcXHU1MDAwMC1cXHU1RkZGRFxcdTYwMDAwLVxcdTZGRkZEXFx1NzAwMDAtXFx1N0ZGRkRcXHU4MDAwMC1cXHU4RkZGRFxcdTkwMDAwLVxcdTlGRkZEXFx1QTAwMDAtXFx1QUZGRkRcXHVCMDAwMC1cXHVCRkZGRFxcdUMwMDAwLVxcdUNGRkZEXFx1RDAwMDAtXFx1REZGRkRcXHVFMTAwMC1cXHVFRkZGRCFcXCQmJ1xcKFxcKVxcKlxcKyw7PTpAXSl8W1xcdUUwMDAtXFx1RjhGRlxcdUYwMDAwLVxcdUZGRkZEfFxcdTEwMDAwMC1cXHUxMEZGRkRcXC9cXD9dKSopPyg/OlxcIyg/Oig/OiVbMC05YS1mXVswLTlhLWZdfFtcXC1hLXowLTlcXC5fflxcdTAwQTAtXFx1RDdGRlxcdUY5MDAtXFx1RkRDRlxcdUZERjAtXFx1RkZFRlxcdTEwMDAwLVxcdTFGRkZEXFx1MjAwMDAtXFx1MkZGRkRcXHUzMDAwMC1cXHUzRkZGRFxcdTQwMDAwLVxcdTRGRkZEXFx1NTAwMDAtXFx1NUZGRkRcXHU2MDAwMC1cXHU2RkZGRFxcdTcwMDAwLVxcdTdGRkZEXFx1ODAwMDAtXFx1OEZGRkRcXHU5MDAwMC1cXHU5RkZGRFxcdUEwMDAwLVxcdUFGRkZEXFx1QjAwMDAtXFx1QkZGRkRcXHVDMDAwMC1cXHVDRkZGRFxcdUQwMDAwLVxcdURGRkZEXFx1RTEwMDAtXFx1RUZGRkQhXFwkJidcXChcXClcXCpcXCssOz06QF0pfFtcXC9cXD9dKSopPyQvaSxcbiAgQkNQXzQ3OiAgICAgICAgICAgICAgL14oPzooZW4tR0Itb2VkfGktKD86YW1pfGJubnxkZWZhdWx0fGVub2NoaWFufGhha3xrbGluZ29ufGx1eHxtaW5nb3xuYXZham98cHdufHRhb3x0YXl8dHN1KXxzZ24tKD86QkUtRlJ8QkUtTkx8Q0gtREUpKXwoYXJ0LWxvamJhbnxjZWwtZ2F1bGlzaHxuby0oPzpib2t8bnluKXx6aC0oPzpndW95dXxoYWtrYXxtaW58bWluLW5hbnx4aWFuZykpKSR8Xih4KD86LVswLTlhLXpdezEsOH0pKykkfF4oPzooKD86W2Etel17MiwzfSg/Oig/Oi1bYS16XXszfSl7MSwzfSk/KXxbYS16XXs0fXxbYS16XXs1LDh9KSg/Oi0oW2Etel17NH0pKT8oPzotKFthLXpdezJ9fFswLTldezN9KSk/KCg/Oi0oPzpbYS16MC05XXs1LDh9fFswLTldW2EtejAtOV17M30pKSopPygoPzotWzAtOWEtd3ktel0oPzotW2EtejAtOV17Miw4fSl7MSx9KSopPygteCg/Oi1bMC05YS16XXsxLDh9KSspPykkL2lcbn0pO1xuXG5jb25zdCBkYXRlRm9ybWF0UmVnZXhQb3NpdGlvbnMgPSBPYmplY3QuZnJlZXplKHtcbiAgWUVBUjogICAgICAgICAgICAgMSxcbiAgTU9OVEg6ICAgICAgICAgICAgMixcbiAgREFZOiAgICAgICAgICAgICAgMyxcbiAgSE9VUjogICAgICAgICAgICAgNCxcbiAgTUlOVVRFOiAgICAgICAgICAgNSxcbiAgU0VDT05EOiAgICAgICAgICAgNixcbiAgTVNFQ09ORDogICAgICAgICAgNyxcbiAgWk9ORTogICAgICAgICAgICAgOCxcbiAgUkVMQVRJVkVfVElNRTogICAgOSxcbiAgVElNRV9aT05FX0hPVVI6ICAgMTAsXG4gIFRJTUVfWk9ORV9NSU5VVEU6IDExXG59KTtcblxuZXhwb3J0IHt4YXBpVmFsaWRhdGlvblJlZ2V4fTtcbmV4cG9ydCB7ZGF0ZUZvcm1hdFJlZ2V4UG9zaXRpb25zfTtcbiIsIid1c2Ugc3RyaWN0JztcblxuY29uc3RcbiAgSVNfU1RSSU5HICA9ICdbb2JqZWN0IFN0cmluZ10nLFxuICBJU19BUlJBWSAgID0gJ1tvYmplY3QgQXJyYXldJyxcbiAgSVNfQk9PTEVBTiA9ICdbb2JqZWN0IEJvb2xlYW5dJyxcbiAgSVNfTlVNQkVSICA9ICdbb2JqZWN0IE51bWJlcl0nXG47XG5cbnZhciB0b1N0cmluZyA9IE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmc7XG52YXIgeGFwaVZhbGlkYXRpb25VdGlscztcblxueGFwaVZhbGlkYXRpb25VdGlscyA9IHtcbiAgaXNTdHJpbmcob2JqKSB7XG4gICAgcmV0dXJuIHRvU3RyaW5nLmNhbGwob2JqKSA9PT0gSVNfU1RSSU5HO1xuICB9LFxuXG4gIGlzT2JqZWN0KG9iaikge1xuICAgIHJldHVybiBvYmogPT09IE9iamVjdChvYmopO1xuICB9LFxuXG4gIGlzQXJyYXk6IEFycmF5LmlzQXJyYXkgfHwgZnVuY3Rpb24ob2JqKSB7XG4gICAgcmV0dXJuIHRvU3RyaW5nLmNhbGwob2JqKSA9PT0gSVNfQVJSQVk7XG4gIH0sXG5cbiAgaXNCb29sZWFuKG9iaikge1xuICAgIHJldHVybiBvYmogPT09IHRydWUgfHwgb2JqID09PSBmYWxzZSB8fCB0b1N0cmluZy5jYWxsKG9iaikgPT09IElTX0JPT0xFQU47XG4gIH0sXG5cbiAgaXNOdW1iZXIob2JqKSB7XG4gICAgcmV0dXJuIHRvU3RyaW5nLmNhbGwob2JqKSA9PT0gSVNfTlVNQkVSO1xuICB9LFxuXG4gIGlzRGVmaW5lZChvYmopIHtcbiAgICByZXR1cm4gKG9iaiAhPT0gbnVsbCB8fCBvYmogIT09IHVuZGVmaW5lZCk7XG4gIH0sXG5cbiAgaXNOb25OdWxsTWFwT2JqZWN0KHRhcmdldCkge1xuICAgICAgcmV0dXJuIHRoaXMuaXNEZWZpbmVkKHRhcmdldCkgJiYgdGhpcy5pc09iamVjdCh0YXJnZXQpICYmICF0aGlzLmlzQXJyYXkodGFyZ2V0KTtcbiAgfSxcblxuICBpc1ZhbGlkTGFuZ3VhZ2VUYWcodGFyZ2V0LCB2YWxpZExhbmd1YWdlUmVnZXgpIHtcbiAgICAvLyBUT0RPIC0gdXNlIG1vcmUgcHJlY2lzZSA1NjQ2IGhhbmRsaW5nLCByYXRoZXIgdGhhbiB0aGlzIHNpbXBsaWZpZWQgQkNQIDQ3IHJlZ2V4LCB3aGljaCBjb21iaW5lcyBSRkMgNTY0NiBhbmQgUkZDIDQ2NDcuXG4gICAgLy8gcmV0dXJuIHRoaXMuaXNEZWZpbmVkKHRhcmdldCkgJiYgdGhpcy5pc1N0cmluZyh0YXJnZXQpICYmIHhhcGlWYWxpZGF0aW9uUmVnZXguQkNQXzQ3LnRlc3QodGFyZ2V0KTtcbiAgICByZXR1cm4gdGhpcy5pc0RlZmluZWQodGFyZ2V0KSAmJiB0aGlzLmlzU3RyaW5nKHRhcmdldCkgJiYgdmFsaWRMYW5ndWFnZVJlZ2V4LnRlc3QodGFyZ2V0KTtcbiAgfSxcblxuICBhZGRQcm9wVG9UcmFjZSh0cmFjZSwgYWRkZW5kdW0pIHtcbiAgICByZXR1cm4gdGhpcy5pc0RlZmluZWQoYWRkZW5kdW0pID8gYCR7dHJhY2V9LiR7YWRkZW5kdW19YCA6IHRyYWNlO1xuICB9LFxuXG4gIGFkZExvb2t1cFRvVHJhY2UodHJhY2UsIGtleSkge1xuICAgIHJldHVybiAoIXRoaXMuaXNEZWZpbmVkKGtleSkpID8gdHJhY2UgOiAodGhpcy5pc051bWJlcihrZXkpID8gYCR7dHJhY2V9WyR7a2V5fV1gIDogYCR7dHJhY2V9W1wiJHtrZXl9XCJdYCk7XG4gIH0sXG5cbiAgbG9jYWxUcmFjZVRvU3RyaW5nKHRyYWNlLCBhZGRlbmR1bSkge1xuICAgIHJldHVybiB0aGlzLmFkZFByb3BUb1RyYWNlKHRyYWNlLCBhZGRlbmR1bSk7XG4gIH0sXG5cbiAgaXNHcm91cChhY3Rvck9yR3JvdXAsIGdyb3VwVHlwZSkge1xuICAgIC8vIHJldHVybiAoYWN0b3JPckdyb3VwLm1lbWJlciAhPT0gbnVsbCAmJiBhY3Rvck9yR3JvdXAubWVtYmVyICE9PSB1bmRlZmluZWQpIHx8IGFjdG9yT3JHcm91cC5vYmplY3RUeXBlID09PSBvYmplY3RUeXBlcy5HUk9VUDtcbiAgICByZXR1cm4gKGFjdG9yT3JHcm91cC5tZW1iZXIgIT09IG51bGwgJiYgYWN0b3JPckdyb3VwLm1lbWJlciAhPT0gdW5kZWZpbmVkKSB8fCBhY3Rvck9yR3JvdXAub2JqZWN0VHlwZSA9PT0gZ3JvdXBUeXBlO1xuICB9XG59O1xuXG5leHBvcnQge3hhcGlWYWxpZGF0aW9uVXRpbHN9O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG5pbXBvcnQge3Byb3BlcnRpZXMsIG9iamVjdFR5cGVzLCB4YXBpVmFsaWRhdGlvbklmaVByb3BlcnR5TmFtZXMsIHhBcGlWYWxpZE9iamVjdFR5cGVzLCB4YXBpV2hpdGVMaXN0UHJvcGVydGllc30gZnJvbSAnLi9jb25zdGFudHMvcHJvcGVydGllcyc7XG5pbXBvcnQge3hhcGlFcnJvckxldmVscywgeGFwaVZhbGlkYXRpb25FcnJvcnN9IGZyb20gJy4vY29uc3RhbnRzL2Vycm9ycyc7XG5pbXBvcnQge3hhcGlWYWxpZGF0aW9uSW50ZXJhY3Rpb25UeXBlc30gZnJvbSAnLi9jb25zdGFudHMvaW50ZXJhY3Rpb24tdHlwZXMnO1xuaW1wb3J0IHt4YXBpVmFsaWRhdGlvblJlZ2V4LCBkYXRlRm9ybWF0UmVnZXhQb3NpdGlvbnN9IGZyb20gJy4vY29uc3RhbnRzL3JlZ2V4JztcbmltcG9ydCB7eGFwaUdlbmVyYWx9IGZyb20gJy4vY29uc3RhbnRzL2dlbmVyYWwnO1xuaW1wb3J0IHt4YXBpVmFsaWRhdGlvblV0aWxzfSBmcm9tICcuL3V0aWxzL3V0aWxzJztcblxudmFyIHhhcGlWYWxpZGF0aW9uO1xuXG5mdW5jdGlvbiBtYWtlVjFSZXBvcnQoaW5zdGFuY2UsIGVycm9ycykge1xuICB2YXIgdmVyc2lvbjtcblxuICBpbnN0YW5jZSA9IGluc3RhbmNlIHx8IG51bGw7XG4gIGVycm9ycyAgID0gZXJyb3JzICAgfHwgbnVsbDtcbiAgdmVyc2lvbiAgPSB4YXBpR2VuZXJhbC5GSVJTVF9SRVBPUlRfVkVSU1RJT047XG4gIHJldHVybiB7aW5zdGFuY2UsIGVycm9ycywgdmVyc2lvbn07XG59XG5cbmZ1bmN0aW9uIG1ha2VWMVNpbmdsZUVycm9yUmVwb3J0KGluc3RhbmNlLCBlcnJvcikge1xuICByZXR1cm4gbWFrZVYxUmVwb3J0KGluc3RhbmNlLCBlcnJvciA9PT0gbnVsbCB8fCBlcnJvciA9PT0gdW5kZWZpbmVkID8gW10gOiBbZXJyb3JdKTtcbn1cblxuZnVuY3Rpb24gdmFsaWRhdGVBYnNlbmNlT2ZOb25XaGl0ZWxpc3RlZFByb3BlcnRpZXModGFyZ2V0LCBhbGxvd2VkUHJvcGVydGllcywgdHJhY2UsIGVycm9ycykge1xuICB2YXIgbG9jYWxFcnJvcnMsIGxvY2FsVHJhY2UsIHByb3BlcnR5TmFtZTtcblxuICBsb2NhbEVycm9ycyA9IGVycm9ycyB8fCBbXTtcbiAgbG9jYWxUcmFjZSAgPSB0cmFjZSAgfHwgJyc7XG5cbiAgZm9yIChwcm9wZXJ0eU5hbWUgaW4gdGFyZ2V0KSB7XG4gICAgaWYgKHRhcmdldC5oYXNPd25Qcm9wZXJ0eShwcm9wZXJ0eU5hbWUpICYmIGFsbG93ZWRQcm9wZXJ0aWVzLmluZGV4T2YocHJvcGVydHlOYW1lKSA9PT0geGFwaUdlbmVyYWwuTk9fSU5ERVhfRk9VTkQpIHtcbiAgICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKGxvY2FsVHJhY2UsIHByb3BlcnR5TmFtZSksXG4gICAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLlVORVhQRUNURUQsXG4gICAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIGxvY2FsRXJyb3JzO1xufVxuXG5mdW5jdGlvbiB2YWxpZGF0ZVByb3BlcnR5SXNTdHJpbmcocGFyZW50LCBwcm9wZXJ0eU5hbWUsIHRyYWNlLCBlcnJvcnMsIGlzUmVxdWlyZWQsIHZpb2xhdGlvblR5cGUpIHtcbiAgdmFyIGxvY2FsRXJyb3JzLCBsb2NhbFRyYWNlLCBwcm9wVmFsdWUsIGxvY2FsVmlvbGF0aW9uVHlwZTtcblxuICBsb2NhbEVycm9ycyAgICAgICAgPSBlcnJvcnMgfHwgW107XG4gIGxvY2FsVHJhY2UgICAgICAgICA9IHRyYWNlICB8fCAnJztcbiAgcHJvcFZhbHVlICAgICAgICAgID0gcGFyZW50W3Byb3BlcnR5TmFtZV0sXG4gIGxvY2FsVmlvbGF0aW9uVHlwZSA9IHZpb2xhdGlvblR5cGUgfHwgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OO1xuXG4gIGlmIChwcm9wVmFsdWUgIT09IHVuZGVmaW5lZCkge1xuICAgIGlmIChwcm9wVmFsdWUgPT09IG51bGwgfHwgIXhhcGlWYWxpZGF0aW9uVXRpbHMuaXNTdHJpbmcocHJvcFZhbHVlKSkge1xuICAgICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMubG9jYWxUcmFjZVRvU3RyaW5nKGxvY2FsVHJhY2UsIHByb3BlcnR5TmFtZSksXG4gICAgICAgIG1lc3NhZ2U6IGAke3Byb3BlcnR5TmFtZX0gJHt4YXBpVmFsaWRhdGlvbkVycm9ycy5NVVNUX0JFX1NUUklOR31gLFxuICAgICAgICBsZXZlbDogICBsb2NhbFZpb2xhdGlvblR5cGVcbiAgICAgIH0pO1xuICAgIH1cbiAgfSBlbHNlIGlmIChpc1JlcXVpcmVkKSB7XG4gICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlLCBwcm9wZXJ0eU5hbWUpLFxuICAgICAgbWVzc2FnZTogYCR7cHJvcGVydHlOYW1lfSAke3hhcGlWYWxpZGF0aW9uRXJyb3JzLk1VU1RfQkVfUFJFU0VOVH1gLFxuICAgICAgbGV2ZWw6ICAgbG9jYWxWaW9sYXRpb25UeXBlXG4gICAgfSk7XG4gIH1cblxuICByZXR1cm4gbG9jYWxFcnJvcnM7XG59XG5cbmZ1bmN0aW9uIHZhbGlkYXRlUHJvcGVydHlJc1VyaSh0YXJnZXQsIHByb3BlcnR5TmFtZSwgdHJhY2UsIGVycm9ycywgaXNSZXF1aXJlZCkge1xuICB2YXIgbG9jYWxFcnJvcnMsIGxvY2FsVHJhY2UsIHByb3BWYWx1ZTtcblxuICBsb2NhbEVycm9ycyA9IGVycm9ycyB8fCBbXTtcbiAgbG9jYWxUcmFjZSAgPSB0cmFjZSAgfHwgJyc7XG4gIHByb3BWYWx1ZSAgID0gdGFyZ2V0W3Byb3BlcnR5TmFtZV07XG5cbiAgaWYgKHByb3BWYWx1ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgaWYgKHByb3BWYWx1ZSA9PT0gbnVsbCB8fCAheGFwaVZhbGlkYXRpb25VdGlscy5pc1N0cmluZyhwcm9wVmFsdWUpKSB7XG4gICAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSwgcHJvcGVydHlOYW1lKSxcbiAgICAgICAgbWVzc2FnZTogYCR7cHJvcGVydHlOYW1lfSAke3hhcGlWYWxpZGF0aW9uRXJyb3JzLk1VU1RfQkVfVVJJX1NUUklOR31gLFxuICAgICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICAgIH0pO1xuICAgIH0gZWxzZSBpZiAoIXhhcGlWYWxpZGF0aW9uUmVnZXguSVJJLnRlc3QocHJvcFZhbHVlKSkge1xuICAgICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICAgIHRyYWNlOiAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSwgcHJvcGVydHlOYW1lKSxcbiAgICAgICAgbWVzc2FnZTogYCR7cHJvcGVydHlOYW1lfSAke3hhcGlWYWxpZGF0aW9uRXJyb3JzLk1VU1RfQkVfSVJJX1NUUklOR31gLFxuICAgICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuU0hPVUxEX1ZJT0xBVElPTlxuICAgICAgfSk7XG4gICAgfVxuICB9IGVsc2UgaWYgKGlzUmVxdWlyZWQpIHtcbiAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMubG9jYWxUcmFjZVRvU3RyaW5nKGxvY2FsVHJhY2UsIHByb3BlcnR5TmFtZSksXG4gICAgICBtZXNzYWdlOiBgJHtwcm9wZXJ0eU5hbWV9ICR7eGFwaVZhbGlkYXRpb25FcnJvcnMuTVVTVF9CRV9VUklfUFJFU0VOVH1gLFxuICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgfSk7XG4gIH1cbiAgcmV0dXJuIGxvY2FsRXJyb3JzO1xufVxuXG5mdW5jdGlvbiB2YWxpZGF0ZVByb3BlcnR5SXNVcmwodGFyZ2V0LCBwcm9wZXJ0eU5hbWUsIHRyYWNlLCBlcnJvcnMsIGlzUmVxdWlyZWQpIHtcbiAgLy8gVE9ETyAtIGNoZWNrIHdoZXRoZXIgYSBmb3JtYWwgVVJMIGZvcm1hdCBkZWZpbml0aW9uIGlzIHJlY29tbWVuZGVkL2VuZm9yY2VkIGZvciB4QVBJXG4gIHJldHVybiB2YWxpZGF0ZVByb3BlcnR5SXNTdHJpbmcodGFyZ2V0LCBwcm9wZXJ0eU5hbWUsIHRyYWNlLCBlcnJvcnMsIGlzUmVxdWlyZWQpO1xufVxuXG5mdW5jdGlvbiB2YWxpZGF0ZVByb3BlcnR5SXNCb29sZWFuKHBhcmVudCwgcHJvcGVydHlOYW1lLCB0cmFjZSwgZXJyb3JzLCBpc1JlcXVpcmVkKSB7XG4gIHZhciBsb2NhbEVycm9ycywgbG9jYWxUcmFjZSwgcHJvcFZhbHVlO1xuXG4gIGxvY2FsRXJyb3JzID0gZXJyb3JzIHx8IFtdO1xuICBsb2NhbFRyYWNlICA9IHRyYWNlICB8fCAnJztcbiAgcHJvcFZhbHVlICAgPSBwYXJlbnRbcHJvcGVydHlOYW1lXTtcblxuICBpZiAocHJvcFZhbHVlICE9PSB1bmRlZmluZWQpIHtcbiAgICBpZiAocHJvcFZhbHVlID09PSBudWxsIHx8ICF4YXBpVmFsaWRhdGlvblV0aWxzLmlzQm9vbGVhbihwcm9wVmFsdWUpKSB7XG4gICAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSwgcHJvcGVydHlOYW1lKSxcbiAgICAgICAgbWVzc2FnZTogYCR7cHJvcGVydHlOYW1lfSAke3hhcGlWYWxpZGF0aW9uRXJyb3JzLk1VU1RfQkVfQk9PTEVBTn1gLFxuICAgICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICAgIH0pO1xuICAgIH1cbiAgfSBlbHNlIGlmIChpc1JlcXVpcmVkKSB7XG4gICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlLCBwcm9wZXJ0eU5hbWUpLFxuICAgICAgbWVzc2FnZTogYCR7cHJvcGVydHlOYW1lfSAke3hhcGlWYWxpZGF0aW9uRXJyb3JzLk1VU1RfQkVfQk9PTEVBTl9QUkVTRU5UfWAsXG4gICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICB9KTtcbiAgfVxuICByZXR1cm4gbG9jYWxFcnJvcnM7XG59XG5cbmZ1bmN0aW9uIHZhbGlkYXRlUHJvcGVydHlJc051bWJlcihwYXJlbnQsIHByb3BlcnR5TmFtZSwgdHJhY2UsIGVycm9ycywgaXNSZXF1aXJlZCkge1xuICB2YXIgbG9jYWxFcnJvcnMsIGxvY2FsVHJhY2UsIHByb3BWYWx1ZTtcblxuICBsb2NhbEVycm9ycyA9IGVycm9ycyB8fCBbXTtcbiAgbG9jYWxUcmFjZSAgPSB0cmFjZSAgfHwgJyc7XG4gIHByb3BWYWx1ZSAgID0gcGFyZW50W3Byb3BlcnR5TmFtZV07XG5cbiAgICBpZiAocHJvcFZhbHVlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGlmIChwcm9wVmFsdWUgPT09IG51bGwgfHwgIXhhcGlWYWxpZGF0aW9uVXRpbHMuaXNOdW1iZXIocHJvcFZhbHVlKSkge1xuICAgICAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlLCBwcm9wZXJ0eU5hbWUpLFxuICAgICAgICAgIG1lc3NhZ2U6IGAke3Byb3BlcnR5TmFtZX0gJHt4YXBpVmFsaWRhdGlvbkVycm9ycy5NVVNUX0JFX05VTUJFUn1gLFxuICAgICAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKGlzUmVxdWlyZWQpIHtcbiAgICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlLCBwcm9wZXJ0eU5hbWUpLFxuICAgICAgICBtZXNzYWdlOiBgJHtwcm9wZXJ0eU5hbWV9ICR7eGFwaVZhbGlkYXRpb25FcnJvcnMuTVVTVF9CRV9OVU1CRVJfUFJFU0VOVH1gLFxuICAgICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICAgIH0pO1xuICAgIH1cbiAgICByZXR1cm4gbG9jYWxFcnJvcnM7XG59XG5cbmZ1bmN0aW9uIHZhbGlkYXRlSUZJUHJvcGVydGllcyh0YXJnZXQsIHRyYWNlLCBlcnJvcnMpIHtcbiAgdmFyIGxvY2FsRXJyb3JzLCBsb2NhbFRyYWNlLCBhY2NvdW50VHJhY2U7XG5cbiAgbG9jYWxFcnJvcnMgPSBlcnJvcnMgfHwgW107XG4gIGxvY2FsVHJhY2UgID0gdHJhY2UgIHx8ICcnO1xuXG4gIGlmICh0YXJnZXQubWJveCAhPT0gdW5kZWZpbmVkICYmIHRhcmdldC5tYm94ICE9PSBudWxsKSB7XG4gICAgaWYgKCF4YXBpVmFsaWRhdGlvblV0aWxzLmlzU3RyaW5nKHRhcmdldC5tYm94KSkge1xuICAgICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICAgIHRyYWNlOiB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLk1CT1gpLFxuICAgICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5JRklfTVVTVF9CRV9NQk9YX1VSSSxcbiAgICAgICAgbGV2ZWw6IHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgICAgfSk7XG4gICAgfSBlbHNlIGlmICgheGFwaVZhbGlkYXRpb25SZWdleC5NQUlMVE9fVVJJLnRlc3QodGFyZ2V0Lm1ib3gpKSB7XG4gICAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSwgcHJvcGVydGllcy5NQk9YKSxcbiAgICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuSUZJX01VU1RfQkVfVkFMSURfTUJPWF9GT1JNQVQsXG4gICAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgdmFsaWRhdGVQcm9wZXJ0eUlzU3RyaW5nKHRhcmdldCwgcHJvcGVydGllcy5NQk9YX1NIQV8xX1NVTSwgbG9jYWxUcmFjZSwgbG9jYWxFcnJvcnMsICAvKmlzUmVxdWlyZWQqL2ZhbHNlKTtcbiAgdmFsaWRhdGVQcm9wZXJ0eUlzVXJpKHRhcmdldCwgcHJvcGVydGllcy5PUEVOX0lELCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycywgLyppc1JlcXVpcmVkKi9mYWxzZSk7XG5cbiAgaWYgKHRhcmdldC5hY2NvdW50ICE9PSB1bmRlZmluZWQgJiYgdGFyZ2V0LmFjY291bnQgIT09IG51bGwpIHtcbiAgICBhY2NvdW50VHJhY2UgPSB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuQUNDT1VOVCk7XG4gICAgdmFsaWRhdGVQcm9wZXJ0eUlzVXJpKHRhcmdldC5hY2NvdW50LCBwcm9wZXJ0aWVzLkhPTUVfUEFHRSxhY2NvdW50VHJhY2UsIGxvY2FsRXJyb3JzLCAvKmlzUmVxdWlyZWQqL3RydWUpO1xuICAgIHZhbGlkYXRlUHJvcGVydHlJc1N0cmluZyh0YXJnZXQuYWNjb3VudCwgcHJvcGVydGllcy5OQU1FLCBhY2NvdW50VHJhY2UsIGxvY2FsRXJyb3JzLCAvKmlzUmVxdWlyZWQqL3RydWUpO1xuICAgIHZhbGlkYXRlQWJzZW5jZU9mTm9uV2hpdGVsaXN0ZWRQcm9wZXJ0aWVzKHRhcmdldC5hY2NvdW50LCB4YXBpV2hpdGVMaXN0UHJvcGVydGllcy5JRkksIGFjY291bnRUcmFjZSwgbG9jYWxFcnJvcnMpO1xuICB9XG5cbiAgcmV0dXJuIGxvY2FsRXJyb3JzO1xufVxuXG5mdW5jdGlvbiBnZXRJRklzKHRhcmdldCkge1xuICB2YXIgaWZpcztcblxuICBpZiAodGFyZ2V0ID09PSBudWxsIHx8IHRhcmdldCA9PT0gdW5kZWZpbmVkKSB7cmV0dXJuIFtdO31cblxuICBpZmlzID0geGFwaVZhbGlkYXRpb25JZmlQcm9wZXJ0eU5hbWVzLmZpbHRlcigobmFtZSkgPT4ge1xuICAgIGlmICh0YXJnZXRbbmFtZV0gIT09IHVuZGVmaW5lZCAmJiB0YXJnZXRbbmFtZV0gIT09IG51bGwpIHtcbiAgICAgIHJldHVybiB7a2V5OiBuYW1lLCB2YWx1ZTogdGFyZ2V0W25hbWVdfTtcbiAgICB9XG4gIH0pO1xuXG4gIHJldHVybiBpZmlzO1xufVxuXG5mdW5jdGlvbiBnZXRJRklDb3VudCh0YXJnZXQpIHtcbiAgcmV0dXJuIGdldElGSXModGFyZ2V0KS5sZW5ndGg7XG59XG5cbmZ1bmN0aW9uIHZhbGlkYXRlRXh0ZW5zaW9ucyhleHRlbnNpb25zLCB0cmFjZSwgZXJyb3JzKSB7XG4gIHZhciBsb2NhbEVycm9ycywgbG9jYWxUcmFjZTtcblxuICBsb2NhbEVycm9ycyA9IGVycm9ycyB8fCBbXSxcbiAgbG9jYWxUcmFjZSAgPSB0cmFjZSAgfHwgcHJvcGVydGllcy5FWFRFTlNJT05TO1xuXG4gIGlmIChleHRlbnNpb25zID09PSB1bmRlZmluZWQpIHtyZXR1cm4gbG9jYWxFcnJvcnM7fVxuXG4gIGlmICgheGFwaVZhbGlkYXRpb25VdGlscy5pc05vbk51bGxNYXBPYmplY3QoZXh0ZW5zaW9ucykpIHtcbiAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgIHRyYWNlOiAgIGxvY2FsVHJhY2UsXG4gICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5FWFRFTlNJT05TX01VU1RfTk9UX0JFX05VTEwsXG4gICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICB9KTtcbiAgfVxuICAvLyBUT0RPIC0gZG91YmxlLWNoZWNrIHdoYXQgZnVydGhlciBlbmZvcmNlYWJsZSBjb25zdHJhaW50cyBleGlzdCBvbiBleHRlbnNpb24gb2JqZWN0IHByb3BlcnRpZXNcbiAgcmV0dXJuIGxvY2FsRXJyb3JzO1xufVxuXG5mdW5jdGlvbiB2YWxpZGF0ZUxhbmd1YWdlTWFwKGxhbmd1YWdlTWFwLCB0cmFjZSwgZXJyb3JzKSB7XG4gIHZhciBsb2NhbEVycm9ycywgbG9jYWxUcmFjZSwgcHJvcE5hbWUsIG1hcHBlZFZhbHVlO1xuXG4gIGxvY2FsRXJyb3JzID0gZXJyb3JzIHx8IFtdO1xuICBsb2NhbFRyYWNlICA9IHRyYWNlICB8fCBwcm9wZXJ0aWVzLkxBTkdVQUdFX01BUDtcblxuICBpZiAobGFuZ3VhZ2VNYXAgPT09IHVuZGVmaW5lZCkge3JldHVybiBsb2NhbEVycm9yczt9XG5cbiAgaWYgKCF4YXBpVmFsaWRhdGlvblV0aWxzLmlzTm9uTnVsbE1hcE9iamVjdChsYW5ndWFnZU1hcCkpIHtcbiAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSksXG4gICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5MQU5HVUFHRV9NQVBTX01VU1RfTk9UX0JFX05VTEwsXG4gICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICB9KTtcblxuICAgIHJldHVybiBsb2NhbEVycm9ycztcbiAgfVxuXG4gIGZvciAocHJvcE5hbWUgaW4gbGFuZ3VhZ2VNYXApIHtcblxuICAgIGlmIChsYW5ndWFnZU1hcC5oYXNPd25Qcm9wZXJ0eShwcm9wTmFtZSkpIHtcbiAgICAgIGlmICgheGFwaVZhbGlkYXRpb25VdGlscy5pc1ZhbGlkTGFuZ3VhZ2VUYWcocHJvcE5hbWUsIHhhcGlWYWxpZGF0aW9uUmVnZXguQkNQXzQ3KSkge1xuICAgICAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKGxvY2FsVHJhY2UsIHByb3BOYW1lKSxcbiAgICAgICAgICBtZXNzYWdlOiBgJHtwcm9wTmFtZX0gJHt4YXBpVmFsaWRhdGlvbkVycm9ycy5MQU5HVUFHRV9NQVBfS0VZX0lOVkFMSUR9YCxcbiAgICAgICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIG1hcHBlZFZhbHVlID0gbGFuZ3VhZ2VNYXBbcHJvcE5hbWVdO1xuXG4gICAgICBpZiAobWFwcGVkVmFsdWUgPT09IG51bGwgfHwgbWFwcGVkVmFsdWUgPT09IHVuZGVmaW5lZCB8fCAheGFwaVZhbGlkYXRpb25VdGlscy5pc1N0cmluZyhtYXBwZWRWYWx1ZSkpIHtcbiAgICAgICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRMb29rdXBUb1RyYWNlKGxvY2FsVHJhY2UsIHByb3BOYW1lKSxcbiAgICAgICAgICBtZXNzYWdlOiBgJHtwcm9wTmFtZX0gJHt4YXBpVmFsaWRhdGlvbkVycm9ycy5MQU5HVUFHRV9NQVBfS0VZX01VU1RfQkVfU1RSSU5HfWAsXG4gICAgICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiBsb2NhbEVycm9ycztcbn1cblxuZnVuY3Rpb24gdmFsaWRhdGVWZXJiKHZlcmIsIHRyYWNlLCBlcnJvcnMpIHtcbiAgdmFyIGxvY2FsRXJyb3JzLCBsb2NhbFRyYWNlO1xuXG4gIGxvY2FsRXJyb3JzID0gZXJyb3JzIHx8IFtdO1xuICBsb2NhbFRyYWNlICA9IHRyYWNlICB8fCBwcm9wZXJ0aWVzLlZFUkI7XG5cbiAgaWYgKHZlcmIgPT09IHVuZGVmaW5lZCkge1xuICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSksXG4gICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5WRVJCX01VU1RfQkVfUFJPVklERUQsXG4gICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICB9KTtcblxuICAgIHJldHVybiBsb2NhbEVycm9ycztcbiAgfVxuXG4gIGlmICgheGFwaVZhbGlkYXRpb25VdGlscy5pc05vbk51bGxNYXBPYmplY3QodmVyYikpIHtcbiAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMubG9jYWxUcmFjZVRvU3RyaW5nKGxvY2FsVHJhY2UpLFxuICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuVkVSQl9NVVNUX05PVF9CRV9OVUxMLFxuICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgfSk7XG5cbiAgICByZXR1cm4gbG9jYWxFcnJvcnM7XG4gIH1cblxuICB2YWxpZGF0ZVByb3BlcnR5SXNVcmkodmVyYiwgcHJvcGVydGllcy5JRCwgbG9jYWxUcmFjZSwgbG9jYWxFcnJvcnMsICAvKmlzUmVxdWlyZWQqL3RydWUpO1xuXG4gIGlmICh2ZXJiLmRpc3BsYXkgPT09IHVuZGVmaW5lZCkge1xuICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRQcm9wVG9UcmFjZShsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLkRJU1BMQVkpLFxuICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuRElTUExBWV9TSE9VTERfQkVfUFJPVklERUQsXG4gICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuU0hPVUxEX1ZJT0xBVElPTlxuICAgIH0pO1xuICB9IGVsc2Uge1xuICAgIHZhbGlkYXRlTGFuZ3VhZ2VNYXAodmVyYi5kaXNwbGF5LCB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuRElTUExBWSksIGxvY2FsRXJyb3JzKTtcbiAgfVxuXG4gIHZhbGlkYXRlQWJzZW5jZU9mTm9uV2hpdGVsaXN0ZWRQcm9wZXJ0aWVzKHZlcmIsIHhhcGlXaGl0ZUxpc3RQcm9wZXJ0aWVzLlVSSSwgbG9jYWxUcmFjZSwgbG9jYWxFcnJvcnMpO1xuXG4gIHJldHVybiBsb2NhbEVycm9ycztcbn1cblxuZnVuY3Rpb24gdmFsaWRhdGVJbnRlcmFjdGlvbkNvbXBvbmVudEFycmF5KGNvbXBvbmVudHMsIGludGVyYWN0aW9uVHlwZSwgYWxsb3dlZEludGVyYWN0aW9uVHlwZXMsIHRyYWNlLCBlcnJvcnMpIHtcbiAgdmFyIGxvY2FsRXJyb3JzLCBsb2NhbFRyYWNlLCBpc0FsbG93ZWRDb21wb25lbnRUeXBlLCBpZHMsIHBlckNvbXBvbmVudFRyYWNlO1xuXG4gIGxvY2FsRXJyb3JzICAgICAgICAgICAgPSBlcnJvcnMgfHwgW107XG4gIGxvY2FsVHJhY2UgICAgICAgICAgICAgPSB0cmFjZSAgfHwgcHJvcGVydGllcy5JTlRFUkFDVElPTl9DT01QT05FTlRTO1xuICBpc0FsbG93ZWRDb21wb25lbnRUeXBlID0gYWxsb3dlZEludGVyYWN0aW9uVHlwZXMuaW5kZXhPZihpbnRlcmFjdGlvblR5cGUpICE9PSB4YXBpR2VuZXJhbC5OT19JTkRFWF9GT1VORDtcbiAgaWRzICAgICAgICAgICAgICAgICAgICA9IFtdO1xuXG4gIGlmIChpc0FsbG93ZWRDb21wb25lbnRUeXBlICYmIGNvbXBvbmVudHMgIT09IHVuZGVmaW5lZCkge1xuICAgIGlmIChjb21wb25lbnRzID09PSBudWxsIHx8ICF4YXBpVmFsaWRhdGlvblV0aWxzLmlzQXJyYXkoY29tcG9uZW50cykpIHtcbiAgICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgICB0cmFjZTogICBsb2NhbFRyYWNlLFxuICAgICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5JTlRFUkFDVElPTl9DT01QT05FTlRfU0hPVUxEX0JFX0FSUkFZLFxuICAgICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuU0hPVUxEX1ZJT0xBVElPTlxuICAgICAgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbXBvbmVudHMuZm9yRWFjaCgoaW50ZXJhY3Rpb25Db21wb25lbnQsIGkpID0+IHtcbiAgICAgICAgcGVyQ29tcG9uZW50VHJhY2UgPSB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZExvb2t1cFRvVHJhY2UobG9jYWxUcmFjZSwgaSk7XG5cbiAgICAgICAgaWYgKCF4YXBpVmFsaWRhdGlvblV0aWxzLmlzTm9uTnVsbE1hcE9iamVjdChpbnRlcmFjdGlvbkNvbXBvbmVudCkpIHtcbiAgICAgICAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgICAgICAgIHRyYWNlOiAgIHBlckNvbXBvbmVudFRyYWNlLFxuICAgICAgICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuSU5URVJBQ1RJT05fQ09NUE9ORU5UX01VU1RfTk9UX0JFX05VTEwsXG4gICAgICAgICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB2YWxpZGF0ZVByb3BlcnR5SXNTdHJpbmcoaW50ZXJhY3Rpb25Db21wb25lbnQsIHByb3BlcnRpZXMuSUQsIHBlckNvbXBvbmVudFRyYWNlLCBsb2NhbEVycm9ycywgLyppc1JlcXVpcmVkKi90cnVlLCB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT04pO1xuICAgICAgICAgIGlmIChpZHMuaW5kZXhPZihpbnRlcmFjdGlvbkNvbXBvbmVudC5pZCkgIT09IHhhcGlHZW5lcmFsLk5PX0lOREVYX0ZPVU5EKSB7XG4gICAgICAgICAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgICAgICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRQcm9wVG9UcmFjZShwZXJDb21wb25lbnRUcmFjZSwgcHJvcGVydGllcy5JRCksXG4gICAgICAgICAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLklEX01VU1RfQkVfVU5JUVVFLFxuICAgICAgICAgICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBpZHMucHVzaChpbnRlcmFjdGlvbkNvbXBvbmVudC5pZCk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKGludGVyYWN0aW9uQ29tcG9uZW50LmlkICYmIHhhcGlWYWxpZGF0aW9uUmVnZXguQ09OVEFJTlNfV0hJVEVTUEFDRS50ZXN0KGludGVyYWN0aW9uQ29tcG9uZW50LmlkKSkge1xuICAgICAgICAgICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICAgICAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UocGVyQ29tcG9uZW50VHJhY2UsIHByb3BlcnRpZXMuSUQpLFxuICAgICAgICAgICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5JRF9TSE9VTERfTk9UX0NPTlRBSU5fV0hJVEVTUEFDRVMsXG4gICAgICAgICAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5TSE9VTERfVklPTEFUSU9OXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICB2YWxpZGF0ZUxhbmd1YWdlTWFwKGludGVyYWN0aW9uQ29tcG9uZW50LmRlc2NyaXB0aW9uLCB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKHBlckNvbXBvbmVudFRyYWNlLCBwcm9wZXJ0aWVzLkRFU0NSSVBUSU9OKSwgbG9jYWxFcnJvcnMpO1xuICAgICAgICAgIHZhbGlkYXRlQWJzZW5jZU9mTm9uV2hpdGVsaXN0ZWRQcm9wZXJ0aWVzKGludGVyYWN0aW9uQ29tcG9uZW50LCB4YXBpV2hpdGVMaXN0UHJvcGVydGllcy5DT01QT05FTlRfQVJSQVksIHBlckNvbXBvbmVudFRyYWNlLCBsb2NhbEVycm9ycyk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuXG4gICAgfVxuICB9IGVsc2UgaWYgKGludGVyYWN0aW9uVHlwZSAmJiBjb21wb25lbnRzKSB7XG4gICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICB0cmFjZTogICBsb2NhbFRyYWNlLFxuICAgICAgbWVzc2FnZTogYCR7eGFwaVZhbGlkYXRpb25FcnJvcnMuSU5URVJBQ1RJT05fVFlQRV9NVVNUX0JFX1ZBTElEfSAke2ludGVyYWN0aW9uVHlwZX1gLFxuICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLlNIT1VMRF9WSU9MQVRJT05cbiAgICB9KTtcbiAgfVxuXG4gIHJldHVybiBsb2NhbEVycm9ycztcbn1cblxuZnVuY3Rpb24gdmFsaWRhdGVBY3Rpdml0eURlZmludGlvbihkZWZpbml0aW9uLCB0cmFjZSwgZXJyb3JzKSB7XG4gIHZhciBsb2NhbEVycm9ycywgbG9jYWxUcmFjZSwgY29ycmVjdFJlc3BvbnNlc1BhdHRlcm5UcmFjZTtcblxuICBsb2NhbEVycm9ycyAgICAgICAgICAgICAgICAgID0gZXJyb3JzIHx8IFtdO1xuICBsb2NhbFRyYWNlICAgICAgICAgICAgICAgICAgID0gdHJhY2UgIHx8IHByb3BlcnRpZXMuREVGSU5JVElPTjtcbiAgY29ycmVjdFJlc3BvbnNlc1BhdHRlcm5UcmFjZSA9IHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSwgcHJvcGVydGllcy5DT1JSRUNUX1JFU1BPTlNFU19QQVRURVJOKTtcblxuICBpZiAoIXhhcGlWYWxpZGF0aW9uVXRpbHMuaXNOb25OdWxsTWFwT2JqZWN0KGRlZmluaXRpb24pKSB7XG4gICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKGxvY2FsVHJhY2UpLFxuICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuREVGSU5JVElPTlNfTVVTVF9CRV9PQkpFQ1RTLFxuICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgfSk7XG5cbiAgICByZXR1cm4gbG9jYWxFcnJvcnM7XG4gIH1cblxuICB2YWxpZGF0ZUxhbmd1YWdlTWFwKGRlZmluaXRpb24ubmFtZSwgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRQcm9wVG9UcmFjZShsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLk5BTUUpLCBsb2NhbEVycm9ycyk7XG4gIHZhbGlkYXRlTGFuZ3VhZ2VNYXAoZGVmaW5pdGlvbi5kZXNjcmlwdGlvbiwgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRQcm9wVG9UcmFjZShsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLkRFU0NSSVBUSU9OKSwgbG9jYWxFcnJvcnMpO1xuXG4gIHZhbGlkYXRlUHJvcGVydHlJc1VyaShkZWZpbml0aW9uLCBwcm9wZXJ0aWVzLlRZUEUsIGxvY2FsVHJhY2UsIGxvY2FsRXJyb3JzLCAgLyppc1JlcXVpcmVkKi9mYWxzZSk7XG4gIHZhbGlkYXRlUHJvcGVydHlJc1VybChkZWZpbml0aW9uLCBwcm9wZXJ0aWVzLk1PUkVfSU5GTywgbG9jYWxUcmFjZSwgbG9jYWxFcnJvcnMsICAvKmlzUmVxdWlyZWQqL2ZhbHNlKTtcbiAgdmFsaWRhdGVFeHRlbnNpb25zKGRlZmluaXRpb24uZXh0ZW5zaW9ucywgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRQcm9wVG9UcmFjZShsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLkVYVEVOU0lPTlMpLCBsb2NhbEVycm9ycyk7XG5cbiAgaWYgKGRlZmluaXRpb24uaW50ZXJhY3Rpb25UeXBlICE9PSB1bmRlZmluZWQpIHtcbiAgICBpZiAoZGVmaW5pdGlvbi50eXBlICE9PSB4YXBpR2VuZXJhbC5JTlRFUkFDVElPTl9ERUZJTklUSU9OX1RZUEUpIHtcbiAgICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLlRZUEUpLFxuICAgICAgICBtZXNzYWdlOiBgJHt4YXBpVmFsaWRhdGlvbkVycm9ycy5JTlRFUkFDVElPTl9BQ1RJVklUWV9TSE9VTERfSEFWRX0gXCIke3hhcGlHZW5lcmFsLklOVEVSQUNUSU9OX0RFRklOSVRJT05fVFlQRX1cImAsXG4gICAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5TSE9VTERfVklPTEFUSU9OXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAoeGFwaVZhbGlkYXRpb25JbnRlcmFjdGlvblR5cGVzLmluZGV4T2YoZGVmaW5pdGlvbi5pbnRlcmFjdGlvblR5cGUpID09PSB4YXBpR2VuZXJhbC5OT19JTkRFWF9GT1VORCkge1xuICAgICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMubG9jYWxUcmFjZVRvU3RyaW5nKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuSU5URVJBQ1RJT05fVFlQRSksXG4gICAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLklOVEVSQUNUSU9OX1RZUEVfTVVTVF9CRV9DTUksXG4gICAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgaWYgKGRlZmluaXRpb24uY29ycmVjdFJlc3BvbnNlc1BhdHRlcm4gIT09IHVuZGVmaW5lZCkge1xuICAgIGlmICgheGFwaVZhbGlkYXRpb25VdGlscy5pc0FycmF5KGRlZmluaXRpb24uY29ycmVjdFJlc3BvbnNlc1BhdHRlcm4pKSB7XG4gICAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgICAgdHJhY2U6ICAgY29ycmVjdFJlc3BvbnNlc1BhdHRlcm5UcmFjZSxcbiAgICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuQ09SUkVDVF9SRVNQT05TRVNfUEFUVEVSTl9NVVNUX0JFX0FSUkFZLFxuICAgICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICAgIH0pO1xuICAgIH0gZWxzZSB7XG4gICAgICBkZWZpbml0aW9uLmNvcnJlY3RSZXNwb25zZXNQYXR0ZXJuLmZvckVhY2goKHJlc3BvbnNlLCBpKSA9PiB7XG4gICAgICAgIGlmIChyZXNwb25zZSA9PT0gbnVsbCB8fCByZXNwb25zZSA9PT0gdW5kZWZpbmVkIHx8ICF4YXBpVmFsaWRhdGlvblV0aWxzLmlzU3RyaW5nKHJlc3BvbnNlKSkge1xuICAgICAgICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRMb29rdXBUb1RyYWNlKGNvcnJlY3RSZXNwb25zZXNQYXR0ZXJuVHJhY2UsIGkpLFxuICAgICAgICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuQ09SUkVDVF9SRVNQT05TRVNfUEFUVEVSTl9NVVNUX0JFX1NUUklOR1MsXG4gICAgICAgICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgdmFsaWRhdGVJbnRlcmFjdGlvbkNvbXBvbmVudEFycmF5KFxuICAgIGRlZmluaXRpb24uY2hvaWNlcyxcbiAgICBkZWZpbml0aW9uLmludGVyYWN0aW9uVHlwZSxcbiAgICBbcHJvcGVydGllcy5DSE9JQ0UsIHByb3BlcnRpZXMuU0VRVUVOQ0lOR10sXG4gICAgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRQcm9wVG9UcmFjZShsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLkNIT0lDRVMpLFxuICAgIGxvY2FsRXJyb3JzXG4gICk7XG5cbiAgdmFsaWRhdGVJbnRlcmFjdGlvbkNvbXBvbmVudEFycmF5KFxuICAgIGRlZmluaXRpb24uc2NhbGUsXG4gICAgZGVmaW5pdGlvbi5pbnRlcmFjdGlvblR5cGUsXG4gICAgW3Byb3BlcnRpZXMuTElLRVJUXSxcbiAgICB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuU0NBTEUpLFxuICAgIGxvY2FsRXJyb3JzXG4gICk7XG5cbiAgdmFsaWRhdGVJbnRlcmFjdGlvbkNvbXBvbmVudEFycmF5KFxuICAgIGRlZmluaXRpb24uc291cmNlLFxuICAgIGRlZmluaXRpb24uaW50ZXJhY3Rpb25UeXBlLFxuICAgIFtwcm9wZXJ0aWVzLk1BVENISU5HXSxcbiAgICB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuU09VUkNFKSxcbiAgICBsb2NhbEVycm9yc1xuICApO1xuXG4gIHZhbGlkYXRlSW50ZXJhY3Rpb25Db21wb25lbnRBcnJheShcbiAgICBkZWZpbml0aW9uLnRhcmdldCxcbiAgICBkZWZpbml0aW9uLmludGVyYWN0aW9uVHlwZSxcbiAgICBbcHJvcGVydGllcy5NQVRDSElOR10sXG4gICAgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRQcm9wVG9UcmFjZShsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLlRBUkdFVCksXG4gICAgbG9jYWxFcnJvcnNcbiAgKTtcblxuICB2YWxpZGF0ZUludGVyYWN0aW9uQ29tcG9uZW50QXJyYXkoXG4gICAgZGVmaW5pdGlvbi5zdGVwcyxcbiAgICBkZWZpbml0aW9uLmludGVyYWN0aW9uVHlwZSxcbiAgICBbcHJvcGVydGllcy5QRVJGT1JNQU5DRV0sXG4gICAgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRQcm9wVG9UcmFjZShsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLlNURVBTKSxcbiAgICBsb2NhbEVycm9yc1xuICApO1xuXG4gIHZhbGlkYXRlQWJzZW5jZU9mTm9uV2hpdGVsaXN0ZWRQcm9wZXJ0aWVzKGRlZmluaXRpb24sIHhhcGlXaGl0ZUxpc3RQcm9wZXJ0aWVzLkFDVElWSVRZX0RFRklOSVRJT04sIGxvY2FsVHJhY2UsIGxvY2FsRXJyb3JzKTtcbiAgcmV0dXJuIGxvY2FsRXJyb3JzO1xufVxuXG5mdW5jdGlvbiB2YWxpZGF0ZUFjdGl2aXR5KGFjdGl2aXR5LCB0cmFjZSwgZXJyb3JzKSB7XG4gIHZhciBsb2NhbEVycm9ycywgbG9jYWxUcmFjZTtcblxuICBsb2NhbEVycm9ycyA9IGVycm9ycyB8fCBbXTtcbiAgbG9jYWxUcmFjZSAgPSB0cmFjZSAgfHwgcHJvcGVydGllcy5BQ1RJVklUWTtcblxuICBpZiAoIXhhcGlWYWxpZGF0aW9uVXRpbHMuaXNOb25OdWxsTWFwT2JqZWN0KGFjdGl2aXR5KSkge1xuICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSksXG4gICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5BQ1RJVklUSUVTX01VU1RfTk9UX0JFX05VTEwsXG4gICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICB9KTtcblxuICAgIHJldHVybiBsb2NhbEVycm9ycztcbiAgfVxuXG4gIHZhbGlkYXRlUHJvcGVydHlJc1VyaShhY3Rpdml0eSwgcHJvcGVydGllcy5JRCwgbG9jYWxUcmFjZSwgbG9jYWxFcnJvcnMsICAvKmlzUmVxdWlyZWQqL3RydWUpO1xuXG4gIGlmIChhY3Rpdml0eS5kZWZpbml0aW9uICE9PSB1bmRlZmluZWQpIHtcbiAgICB2YWxpZGF0ZUFjdGl2aXR5RGVmaW50aW9uKFxuICAgICAgYWN0aXZpdHkuZGVmaW5pdGlvbixcbiAgICAgIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSwgcHJvcGVydGllcy5ERUZJTklUSU9OKSxcbiAgICAgIGxvY2FsRXJyb3JzXG4gICAgKTtcbiAgfVxuXG4gIHZhbGlkYXRlQWJzZW5jZU9mTm9uV2hpdGVsaXN0ZWRQcm9wZXJ0aWVzKGFjdGl2aXR5LCB4YXBpV2hpdGVMaXN0UHJvcGVydGllcy5BQ1RJVklUWSwgbG9jYWxUcmFjZSwgbG9jYWxFcnJvcnMpO1xuXG4gIHJldHVybiBsb2NhbEVycm9ycztcbn1cblxuZnVuY3Rpb24gdmFsaWRhdGVTdGF0ZW1lbnRSZWYoc3RhdGVtZW50UmVmLCB0cmFjZSwgZXJyb3JzKSB7XG4gIHZhciBsb2NhbEVycm9ycywgbG9jYWxUcmFjZTtcblxuICBsb2NhbEVycm9ycyA9IGVycm9ycyB8fCBbXTtcbiAgbG9jYWxUcmFjZSAgPSB0cmFjZSAgfHwgcHJvcGVydGllcy5TVEFURU1FTlRfUkVGO1xuXG4gIGlmICgheGFwaVZhbGlkYXRpb25VdGlscy5pc05vbk51bGxNYXBPYmplY3Qoc3RhdGVtZW50UmVmKSkge1xuICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSksXG4gICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5TVEFURU1FTlRfUkVGX01VU1RfTk9UX0JFX05VTExfTUFQX09CSkVDVFMsXG4gICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICB9KTtcbiAgICByZXR1cm4gbG9jYWxFcnJvcnM7XG4gIH1cblxuXG4gIGlmIChzdGF0ZW1lbnRSZWYub2JqZWN0VHlwZSAhPT0gb2JqZWN0VHlwZXMuU1RBVEVNRU5UX1JFRikge1xuICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRQcm9wVG9UcmFjZShsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLk9CSkVDVF9UWVBFKSxcbiAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLk9CSkVDVF9UWVBFX01VU1RfQkVfU1RBVEVNRU5UX1JFRixcbiAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgIH0pO1xuICB9XG5cbiAgaWYgKCFzdGF0ZW1lbnRSZWYuaWQgfHwgIXhhcGlWYWxpZGF0aW9uUmVnZXguVVVJRC50ZXN0KHN0YXRlbWVudFJlZi5pZCkpIHtcbiAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSwgcHJvcGVydGllcy5JRCksXG4gICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5JRF9NVVNUX0JFX1ZBTElEX1VVSURfUkVGLFxuICAgICAgbGV2ZWw6ICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICB9KTtcbiAgfVxuXG4gIHZhbGlkYXRlQWJzZW5jZU9mTm9uV2hpdGVsaXN0ZWRQcm9wZXJ0aWVzKHN0YXRlbWVudFJlZiwgeGFwaVdoaXRlTGlzdFByb3BlcnRpZXMuU1RBVEVNRU5UX1JFRiwgbG9jYWxUcmFjZSwgbG9jYWxFcnJvcnMpO1xuXG4gIHJldHVybiBsb2NhbEVycm9ycztcbn1cblxuZnVuY3Rpb24gdmFsaWRhdGVTY29yZShzY29yZSwgdHJhY2UsIGVycm9ycykge1xuICB2YXIgbG9jYWxFcnJvcnMsIGxvY2FsVHJhY2U7XG5cbiAgbG9jYWxFcnJvcnMgPSBlcnJvcnMgfHwgW107XG4gIGxvY2FsVHJhY2UgID0gdHJhY2UgIHx8IHByb3BlcnRpZXMuU0NPUkU7XG5cbiAgaWYgKHNjb3JlID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHJldHVybiBsb2NhbEVycm9ycztcbiAgfVxuXG4gIHZhbGlkYXRlUHJvcGVydHlJc051bWJlcihzY29yZSwgcHJvcGVydGllcy5TQ0FMRUQsIGxvY2FsVHJhY2UsIGxvY2FsRXJyb3JzLCAgLyppc1JlcXVpcmVkKi9mYWxzZSk7XG5cbiAgaWYgKHNjb3JlLnNjYWxlZCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgaWYgKHNjb3JlLnNjYWxlZCA8IHhhcGlHZW5lcmFsLk1JTl9TQ0FMRURfVkFMVUUgfHwgc2NvcmUuc2NhbGVkID4geGFwaUdlbmVyYWwuTUFYX1NDQUxFRF9WQUxVRSkge1xuICAgICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSwgcHJvcGVydGllcy5TQ0FMRUQpLFxuICAgICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5TQ0FMRURfTVVTVF9CRV9CRVRXRUVOXzBfMSxcbiAgICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBpZiAoc2NvcmUubWluICE9PSB1bmRlZmluZWQpIHtcbiAgICB2YWxpZGF0ZVByb3BlcnR5SXNOdW1iZXIoc2NvcmUsIHByb3BlcnRpZXMuTUlOLCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycywgIC8qaXNSZXF1aXJlZCovZmFsc2UpO1xuXG4gICAgICBpZiAoc2NvcmUucmF3ICE9PSB1bmRlZmluZWQgJiYgc2NvcmUucmF3IDwgc2NvcmUubWluKSB7XG4gICAgICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSwgcHJvcGVydGllcy5SQVcpLFxuICAgICAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLlJBV19NVVNUX0JFX0dSRUFURVJfVEhBTl9NSU4sXG4gICAgICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBpZiAoc2NvcmUubWF4ICE9PSB1bmRlZmluZWQgJiYgc2NvcmUubWF4IDwgc2NvcmUubWluKSB7XG4gICAgICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSwgcHJvcGVydGllcy5NQVgpLFxuICAgICAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLk1BWF9NVVNUX0JFX0dSRUFURVJfVEhBTl9NSU4sXG4gICAgICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgICAgIH0pO1xuICAgICAgfVxuICB9XG5cbiAgaWYgKHNjb3JlLm1heCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgdmFsaWRhdGVQcm9wZXJ0eUlzTnVtYmVyKHNjb3JlLCBwcm9wZXJ0aWVzLk1BWCwgbG9jYWxUcmFjZSwgbG9jYWxFcnJvcnMsICAvKmlzUmVxdWlyZWQqL2ZhbHNlKTtcblxuICAgIGlmIChzY29yZS5yYXcgIT09IHVuZGVmaW5lZCAmJiBzY29yZS5yYXcgPiBzY29yZS5tYXgpIHtcbiAgICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuUkFXKSxcbiAgICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuUkFXX01VU1RfQkVfTEVTU19USEFOX01BWCxcbiAgICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICB2YWxpZGF0ZVByb3BlcnR5SXNOdW1iZXIoc2NvcmUsIHByb3BlcnRpZXMuUkFXLCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycywgIC8qaXNSZXF1aXJlZCovZmFsc2UpO1xuICB2YWxpZGF0ZUFic2VuY2VPZk5vbldoaXRlbGlzdGVkUHJvcGVydGllcyhzY29yZSwgeGFwaVdoaXRlTGlzdFByb3BlcnRpZXMuU0NPUkUsIGxvY2FsVHJhY2UsIGxvY2FsRXJyb3JzKTtcblxuICByZXR1cm4gbG9jYWxFcnJvcnM7XG59XG5cbmZ1bmN0aW9uIHZhbGlkYXRlUmVzdWx0KHJlc3VsdCwgdHJhY2UsIGVycm9ycykge1xuICB2YXIgbG9jYWxFcnJvcnMsIGxvY2FsVHJhY2U7XG5cbiAgbG9jYWxFcnJvcnMgPSBlcnJvcnMgfHwgW107XG4gIGxvY2FsVHJhY2UgID0gdHJhY2UgIHx8IHByb3BlcnRpZXMuUkVTVUxUO1xuXG4gIGlmIChyZXN1bHQgPT09IHVuZGVmaW5lZCkge3JldHVybiBsb2NhbEVycm9yczt9XG5cbiAgaWYgKCF4YXBpVmFsaWRhdGlvblV0aWxzLmlzTm9uTnVsbE1hcE9iamVjdChyZXN1bHQpKSB7XG4gICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKGxvY2FsVHJhY2UpLFxuICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuUkVTVUxUX01VU1RfQkVfTUFQX09CSkVDVCxcbiAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgIH0pO1xuXG4gICAgcmV0dXJuIGxvY2FsRXJyb3JzO1xuICB9XG5cbiAgdmFsaWRhdGVTY29yZShyZXN1bHQuc2NvcmUsIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSwgcHJvcGVydGllcy5TQ09SRSksIGxvY2FsRXJyb3JzKTtcbiAgdmFsaWRhdGVQcm9wZXJ0eUlzQm9vbGVhbihyZXN1bHQsIHByb3BlcnRpZXMuU1VDQ0VTUywgbG9jYWxUcmFjZSwgbG9jYWxFcnJvcnMsICAvKmlzUmVxdWlyZWQqL2ZhbHNlKTtcbiAgdmFsaWRhdGVQcm9wZXJ0eUlzQm9vbGVhbihyZXN1bHQsIHByb3BlcnRpZXMuQ09NUExFVElPTiwgbG9jYWxUcmFjZSwgbG9jYWxFcnJvcnMsICAvKmlzUmVxdWlyZWQqL2ZhbHNlKTtcbiAgdmFsaWRhdGVQcm9wZXJ0eUlzU3RyaW5nKHJlc3VsdCwgcHJvcGVydGllcy5SRVNQT05TRSwgbG9jYWxUcmFjZSwgbG9jYWxFcnJvcnMsICAvKmlzUmVxdWlyZWQqL2ZhbHNlKTtcbiAgdmFsaWRhdGVFeHRlbnNpb25zKHJlc3VsdC5leHRlbnNpb25zLCB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuRVhURU5TSU9OUyksIGxvY2FsRXJyb3JzKTtcblxuICBpZiAocmVzdWx0LmR1cmF0aW9uICE9PSB1bmRlZmluZWQgJiYgKHJlc3VsdC5kdXJhdGlvbiA9PT0gbnVsbCB8fCAheGFwaVZhbGlkYXRpb25VdGlscy5pc1N0cmluZyhyZXN1bHQuZHVyYXRpb24pIHx8ICF4YXBpVmFsaWRhdGlvblJlZ2V4LklTT184NjAxX0RVUkFUSU9OLnRlc3QocmVzdWx0LmR1cmF0aW9uKSkpIHtcbiAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSwgcHJvcGVydGllcy5EVVJBVElPTiksXG4gICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5EVVJBVElPTl9NVVNUX0JFX1ZBTElELFxuICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgfSk7XG4gIH1cblxuICB2YWxpZGF0ZUFic2VuY2VPZk5vbldoaXRlbGlzdGVkUHJvcGVydGllcyhyZXN1bHQsIHhhcGlXaGl0ZUxpc3RQcm9wZXJ0aWVzLlJFU1VMVCwgbG9jYWxUcmFjZSwgbG9jYWxFcnJvcnMpO1xuXG4gIHJldHVybiBsb2NhbEVycm9ycztcbn1cblxuZnVuY3Rpb24gdmFsaWRhdGVQcm9wZXJ0eUlzSVNPODYwMVN0cmluZyhwYXJlbnQsIHByb3BlcnR5TmFtZSwgdHJhY2UsIGVycm9ycykge1xuICB2YXIgbG9jYWxFcnJvcnMsIGxvY2FsVHJhY2UsIG1hdGNoZWQsIGRhdGV0aW1lO1xuXG4gIGxvY2FsRXJyb3JzID0gZXJyb3JzIHx8IFtdO1xuICBsb2NhbFRyYWNlICA9IHRyYWNlICB8fCBwcm9wZXJ0aWVzLkRBVEVfVElNRTtcbiAgZGF0ZXRpbWUgICAgPSBwYXJlbnRbcHJvcGVydHlOYW1lXTtcblxuICBpZiAoZGF0ZXRpbWUgPT09IHVuZGVmaW5lZCkge3JldHVybiBsb2NhbEVycm9yczt9XG5cbiAgaWYgKGRhdGV0aW1lID09PSBudWxsIHx8ICF4YXBpVmFsaWRhdGlvblV0aWxzLmlzU3RyaW5nKGRhdGV0aW1lKSkge1xuICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSwgcHJvcGVydHlOYW1lKSxcbiAgICAgIG1lc3NhZ2U6IGAke3Byb3BlcnR5TmFtZX0gJHt4YXBpVmFsaWRhdGlvbkVycm9ycy5NVVNUX0JFX1NUUklOR31gLFxuICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgfSk7XG5cbiAgICByZXR1cm4gbG9jYWxFcnJvcnM7XG4gIH1cblxuICBtYXRjaGVkID0geGFwaVZhbGlkYXRpb25SZWdleC5JU09fODYwMV9EQVRFX1RJTUUuZXhlYyhkYXRldGltZSk7XG5cbiAgaWYgKG1hdGNoZWQpIHtcbiAgICBpZiAoIWRhdGVJbmNsdWRlc1pvbmVJbmZvcm1hdGlvbihtYXRjaGVkKSkge1xuICAgICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMubG9jYWxUcmFjZVRvU3RyaW5nKGxvY2FsVHJhY2UsIHByb3BlcnR5TmFtZSksXG4gICAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLkRBVEVfU0hPVUxEX0lOQ0xVREVfWk9ORV9JTkZPUk1BVElPTixcbiAgICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLlNIT1VMRF9WSU9MQVRJT05cbiAgICAgIH0pO1xuICAgIH1cbiAgfSBlbHNlIHtcbiAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMubG9jYWxUcmFjZVRvU3RyaW5nKGxvY2FsVHJhY2UsIHByb3BlcnR5TmFtZSksXG4gICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5EQVRFX01VU1RfQkVfVkFMSUQsXG4gICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICB9KTtcbiAgfVxuXG4gIHJldHVybiBsb2NhbEVycm9ycztcbn1cblxuZnVuY3Rpb24gdmFsaWRhdGVWZXJzaW9uKHZlcnNpb24sIHRyYWNlLCBlcnJvcnMpIHtcbiAgdmFyIGxvY2FsRXJyb3JzLCBsb2NhbFRyYWNlO1xuXG4gIGxvY2FsRXJyb3JzID0gZXJyb3JzIHx8IFtdO1xuICBsb2NhbFRyYWNlICA9IHRyYWNlICB8fCBwcm9wZXJ0aWVzLlZFUlNJT047XG5cbiAgaWYgKHZlcnNpb24gPT09IHVuZGVmaW5lZCkge3JldHVybiBsb2NhbEVycm9yczt9XG5cbiAgaWYgKHZlcnNpb24gPT09IG51bGwgfHwgIXhhcGlWYWxpZGF0aW9uVXRpbHMuaXNTdHJpbmcodmVyc2lvbikgfHwgIXhhcGlWYWxpZGF0aW9uUmVnZXguU0VNVkVSXzFfUF8wX1BfMC50ZXN0KHZlcnNpb24pKSB7XG4gICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlKSxcbiAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLlZFUlNJT05fTVVTVF9DT01QTFlfU0VNQU5USUNfVkVSU0lPTklORyxcbiAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgIH0pO1xuICB9XG5cbiAgcmV0dXJuIGxvY2FsRXJyb3JzO1xufVxuXG5mdW5jdGlvbiB2YWxpZGF0ZUF0dGFjaG1lbnRPYmplY3QoYXR0YWNobWVudCwgdHJhY2UsIGVycm9ycykge1xuICB2YXIgbG9jYWxFcnJvcnMsIGxvY2FsVHJhY2U7XG5cbiAgbG9jYWxFcnJvcnMgPSBlcnJvcnMgfHwgW107XG4gIGxvY2FsVHJhY2UgID0gdHJhY2UgfHwgcHJvcGVydGllcy5BVFRBQ0hNRU5UO1xuXG4gIGlmICgheGFwaVZhbGlkYXRpb25VdGlscy5pc05vbk51bGxNYXBPYmplY3QoYXR0YWNobWVudCkpIHtcbiAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMubG9jYWxUcmFjZVRvU3RyaW5nKGxvY2FsVHJhY2UpLFxuICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuQVRUQUNITUVOVFNfTVVTVF9OT1RfQkVfTlVMTF9NQVBfT0JKRUNUUyxcbiAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgIH0pO1xuXG4gICAgcmV0dXJuIGxvY2FsRXJyb3JzO1xuICB9XG5cbiAgaWYgKGF0dGFjaG1lbnQuZGlzcGxheSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLkRJU1BMQVkpLFxuICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuRElTUExBWV9TSE9VTERfQkVfUFJPVklERUQsXG4gICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICB9KTtcblxuICB9IGVsc2Uge1xuICAgIHZhbGlkYXRlTGFuZ3VhZ2VNYXAoYXR0YWNobWVudC5kaXNwbGF5LCB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuRElTUExBWSksIGxvY2FsRXJyb3JzKTtcbiAgfVxuXG4gIHZhbGlkYXRlTGFuZ3VhZ2VNYXAoYXR0YWNobWVudC5kZXNjcmlwdGlvbiwgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRQcm9wVG9UcmFjZShsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLkRFU0NSSVBUSU9OKSwgbG9jYWxFcnJvcnMpO1xuICB2YWxpZGF0ZVByb3BlcnR5SXNVcmkoYXR0YWNobWVudCwgcHJvcGVydGllcy5VU0FHRV9UWVBFLCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycywgLyppc1JlcXVpcmVkKi90cnVlLCB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT04pO1xuICB2YWxpZGF0ZVByb3BlcnR5SXNVcmkoYXR0YWNobWVudCwgcHJvcGVydGllcy5GSUxFX1VSTCwgbG9jYWxUcmFjZSwgbG9jYWxFcnJvcnMsICAvKmlzUmVxdWlyZWQqL2ZhbHNlLCB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT04pO1xuXG4gIC8vIFRPRE8gLSBtb3JlIGNvbXBsZXRlIHZhbGlkYXRpb24gZm9yIEludGVybmV0IE1lZGlhIFR5cGUgdmlhIFJGQyAyMDQ2XG4gIHZhbGlkYXRlUHJvcGVydHlJc1N0cmluZyhhdHRhY2htZW50LCBwcm9wZXJ0aWVzLkNPTlRFTlRfVFlQRSwgbG9jYWxUcmFjZSwgbG9jYWxFcnJvcnMsIC8qaXNSZXF1aXJlZCovdHJ1ZSwgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OKTtcblxuICBpZiAoYXR0YWNobWVudC5sZW5ndGggPT09IHVuZGVmaW5lZCB8fCBhdHRhY2htZW50Lmxlbmd0aCA9PT0gbnVsbCB8fCAheGFwaVZhbGlkYXRpb25VdGlscy5pc051bWJlcihhdHRhY2htZW50Lmxlbmd0aCkgfHwgKGF0dGFjaG1lbnQubGVuZ3RoICUgMSAhPT0gMCkpIHtcbiAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMubG9jYWxUcmFjZVRvU3RyaW5nKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuTEVOR1RIKSxcbiAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLkxFTkdUSF9NVVNUX0JFX0lOVEVHRVIsXG4gICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICB9KTtcbiAgfVxuXG4gIGlmIChhdHRhY2htZW50LnNoYTIgPT09IHVuZGVmaW5lZCkge1xuICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSwgcHJvcGVydGllcy5TSEEyKSxcbiAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLlNIQTJfTVVTVF9CRV9QUk9WSURFRF9PTl9BVFRBQ0hNRU5UX09CSkVDVFMsXG4gICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICB9KTtcbiAgfSBlbHNlIGlmIChhdHRhY2htZW50LnNoYTIgPT09IG51bGwgfHwgIXhhcGlWYWxpZGF0aW9uVXRpbHMuaXNTdHJpbmcoYXR0YWNobWVudC5zaGEyKSB8fCAheGFwaVZhbGlkYXRpb25SZWdleC5CQVNFXzY0LnRlc3QoYXR0YWNobWVudC5zaGEyKSkge1xuICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSwgcHJvcGVydGllcy5TSEEyKSxcbiAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLlNIQTJfTVVTVF9DT05UQUlOX0JBU0VfNjRfU1RSSU5HLFxuICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgfSk7XG4gIH1cblxuICB2YWxpZGF0ZUFic2VuY2VPZk5vbldoaXRlbGlzdGVkUHJvcGVydGllcyhhdHRhY2htZW50LCB4YXBpV2hpdGVMaXN0UHJvcGVydGllcy5BVFRBQ0hNRU5ULCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycyk7XG4gIHJldHVybiBsb2NhbEVycm9ycztcbn1cblxuZnVuY3Rpb24gdmFsaWRhdGVBdHRhY2htZW50cyhhdHRhY2htZW50cywgdHJhY2UsIGVycm9ycykge1xuICB2YXIgbG9jYWxFcnJvcnMsIGxvY2FsVHJhY2U7XG5cbiAgbG9jYWxFcnJvcnMgPSBlcnJvcnMgfHwgW107XG4gIGxvY2FsVHJhY2UgID0gdHJhY2UgIHx8IHByb3BlcnRpZXMuQVRUQUNITUVOVFM7XG5cbiAgaWYgKGF0dGFjaG1lbnRzID09PSB1bmRlZmluZWQpIHtyZXR1cm4gbG9jYWxFcnJvcnM7fVxuXG4gIGlmIChhdHRhY2htZW50cyA9PT0gbnVsbCB8fCAheGFwaVZhbGlkYXRpb25VdGlscy5pc0FycmF5KGF0dGFjaG1lbnRzKSkge1xuICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSksXG4gICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5BVFRBQ0hNRU5UU19NVVNUX0JFX05PVF9OVUxMX0FSUkFZLFxuICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgfSk7XG5cbiAgICByZXR1cm4gbG9jYWxFcnJvcnM7XG4gIH1cblxuICBhdHRhY2htZW50cy5mb3JFYWNoKChhdHRhY2htZW50LCBpKSA9PiB7XG4gICAgdmFsaWRhdGVBdHRhY2htZW50T2JqZWN0KGF0dGFjaG1lbnQsIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkTG9va3VwVG9UcmFjZShsb2NhbFRyYWNlLCBpKSwgbG9jYWxFcnJvcnMpO1xuICB9KTtcblxuICByZXR1cm4gbG9jYWxFcnJvcnM7XG59XG5cbmZ1bmN0aW9uIHZhbGlkYXRlQWdlbnQoYWdlbnQsIHRyYWNlLCBlcnJvcnMpIHtcbiAgdmFyIGxvY2FsRXJyb3JzLCBsb2NhbFRyYWNlLCBpZmlDb3VudDtcblxuICBsb2NhbEVycm9ycyA9IGVycm9ycyB8fCBbXTtcbiAgbG9jYWxUcmFjZSAgPSB0cmFjZSAgfHwgcHJvcGVydGllcy5BR0VOVDtcblxuICBpZiAoIXhhcGlWYWxpZGF0aW9uVXRpbHMuaXNOb25OdWxsTWFwT2JqZWN0KGFnZW50KSkge1xuICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSksXG4gICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5BR0VOVF9NVVNUX0JFX05PTl9OVUxMX01BUF9PQkpFQ1QsXG4gICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICB9KTtcbiAgICByZXR1cm4gbG9jYWxFcnJvcnM7XG4gIH1cblxuICBpZmlDb3VudCA9IGdldElGSUNvdW50KGFnZW50KTtcblxuICBpZiAoaWZpQ291bnQgIT09IHhhcGlHZW5lcmFsLk5VTUVSX09GX1NQRUNJRklFRF9JRklfUFJPUEVSVElFUykge1xuICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSksXG4gICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5BR0VOVF9JRklfUFJPUEVSVElFU19NVVNUX0JFX1NQRUNJRklFRCxcbiAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgIH0pO1xuICB9XG5cbiAgaWYgKGFnZW50Lm9iamVjdFR5cGUgPT09IG9iamVjdFR5cGVzLkdST1VQKSB7XG4gICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlKSxcbiAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLkFHRU5UX01VU1RfTk9UX0hBVkVfR1JPVVBfQ0hBUkFDVEVSSVNUSUNTLFxuICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgfSk7XG4gIH1cblxuICB2YWxpZGF0ZUlGSVByb3BlcnRpZXMoYWdlbnQsIGxvY2FsVHJhY2UsIGxvY2FsRXJyb3JzKTtcbiAgdmFsaWRhdGVQcm9wZXJ0eUlzU3RyaW5nKGFnZW50LCBwcm9wZXJ0aWVzLk5BTUUsIGxvY2FsVHJhY2UsIGxvY2FsRXJyb3JzLCAgLyppc1JlcXVpcmVkKi9mYWxzZSk7XG5cbiAgdmFsaWRhdGVBYnNlbmNlT2ZOb25XaGl0ZWxpc3RlZFByb3BlcnRpZXMoYWdlbnQsIHhhcGlXaGl0ZUxpc3RQcm9wZXJ0aWVzLkFHRU5ULCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycyk7XG5cbiAgcmV0dXJuIGxvY2FsRXJyb3JzO1xufVxuXG5mdW5jdGlvbiB2YWxpZGF0ZUdyb3VwKGdyb3VwLCB0cmFjZSwgZXJyb3JzKSB7XG4gIHZhciBsb2NhbEVycm9ycywgbG9jYWxUcmFjZSwgbWVtYmVyVHJhY2UsIGlmaUNvdW50O1xuXG4gIGxvY2FsRXJyb3JzID0gZXJyb3JzIHx8IFtdO1xuICBsb2NhbFRyYWNlICA9IHRyYWNlICB8fCBwcm9wZXJ0aWVzLkdST1VQO1xuICBtZW1iZXJUcmFjZSA9IHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSwgcHJvcGVydGllcy5NRU1CRVIpO1xuXG4gIGlmICgheGFwaVZhbGlkYXRpb25VdGlscy5pc05vbk51bGxNYXBPYmplY3QoZ3JvdXApKSB7XG4gICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlKSxcbiAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLkdST1VQX01VU1RfQkVfTk9OX05VTExfTUFQX09CSkVDVCxcbiAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgIH0pO1xuXG4gICAgcmV0dXJuIGxvY2FsRXJyb3JzO1xuICB9XG5cbiAgaWZpQ291bnQgPSBnZXRJRklDb3VudChncm91cCk7XG5cbiAgaWYgKGlmaUNvdW50ID09PSAwKSB7XG4gICAgaWYgKGdyb3VwLm1lbWJlciA9PT0gbnVsbCB8fCBncm91cC5tZW1iZXIgPT09IHVuZGVmaW5lZCkge1xuICAgICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICAgIHRyYWNlOiAgIG1lbWJlclRyYWNlLFxuICAgICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5NRU1CRVJfTVVTVF9CRV9QUk9WSURFRF9GT1JfQU5PTllNT1VTX0dST1VQUyxcbiAgICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgICB9KTtcbiAgICB9XG4gIH0gZWxzZSBpZiAoaWZpQ291bnQgPiB4YXBpR2VuZXJhbC5OVU1FUl9PRl9TUEVDSUZJRURfSUZJX1BST1BFUlRJRVMpIHtcbiAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMubG9jYWxUcmFjZVRvU3RyaW5nKGxvY2FsVHJhY2UpLFxuICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuR1JPVVBfSUZJX1BST1BFUlRJRVNfTVVTVF9CRV9TUEVDSUZJRUQsXG4gICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICB9KTtcbiAgfVxuXG4gIHZhbGlkYXRlSUZJUHJvcGVydGllcyhncm91cCwgbG9jYWxUcmFjZSwgbG9jYWxFcnJvcnMpO1xuXG4gIHZhbGlkYXRlUHJvcGVydHlJc1N0cmluZyhncm91cCwgcHJvcGVydGllcy5OQU1FLCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycywgIC8qaXNSZXF1aXJlZCovZmFsc2UpO1xuXG4gIGlmIChncm91cC5tZW1iZXIgIT09IHVuZGVmaW5lZCkge1xuICAgIGlmIChncm91cC5tZW1iZXIgPT09IG51bGwgfHwgIXhhcGlWYWxpZGF0aW9uVXRpbHMuaXNBcnJheShncm91cC5tZW1iZXIpKSB7XG4gICAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSwgcHJvcGVydGllcy5NRU1CRVIpLFxuICAgICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5HUk9VUF9NRU1CRVJfTVVTVF9CRV9BUlJBWSxcbiAgICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgICB9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgZ3JvdXAubWVtYmVyLmZvckVhY2goKG1lbWJlciwgaSkgPT4ge1xuICAgICAgICB2YWxpZGF0ZUFnZW50KG1lbWJlciwgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRMb29rdXBUb1RyYWNlKG1lbWJlclRyYWNlLCBpKSwgbG9jYWxFcnJvcnMpO1xuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgdmFsaWRhdGVBYnNlbmNlT2ZOb25XaGl0ZWxpc3RlZFByb3BlcnRpZXMoZ3JvdXAsIHhhcGlXaGl0ZUxpc3RQcm9wZXJ0aWVzLkdST1VQLCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycyk7XG5cbiAgcmV0dXJuIGxvY2FsRXJyb3JzO1xufVxuXG5mdW5jdGlvbiB2YWxpZGF0ZUFjdG9yKGFjdG9yLCB0cmFjZSwgZXJyb3JzKSB7XG4gIHZhciBsb2NhbEVycm9ycywgbG9jYWxUcmFjZTtcblxuICBsb2NhbEVycm9ycyA9IGVycm9ycyB8fCBbXTtcbiAgbG9jYWxUcmFjZSAgPSB0cmFjZSAgfHwgcHJvcGVydGllcy5BQ1RPUjtcblxuICBpZiAoYWN0b3IgPT09IG51bGwgfHwgYWN0b3IgPT09IHVuZGVmaW5lZCkge1xuICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSksXG4gICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5BQ1RPUl9NVVNUX0JFX1BST1ZJREVELFxuICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgfSk7XG5cbiAgICByZXR1cm4gbG9jYWxFcnJvcnM7XG4gIH1cblxuICBpZiAoeGFwaVZhbGlkYXRpb25VdGlscy5pc0dyb3VwKGFjdG9yLCBvYmplY3RUeXBlcy5HUk9VUCkpIHtcbiAgICB2YWxpZGF0ZUdyb3VwKGFjdG9yLCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycyk7XG4gIH0gZWxzZSB7XG4gICAgdmFsaWRhdGVBZ2VudChhY3RvciwgbG9jYWxUcmFjZSwgbG9jYWxFcnJvcnMpO1xuICB9XG5cbiAgcmV0dXJuIGxvY2FsRXJyb3JzO1xufVxuXG5mdW5jdGlvbiB2YWxpZGF0ZUF1dGhvcml0eShhdXRob3JpdHksIHRyYWNlLCBlcnJvcnMpIHtcbiAgdmFyIGxvY2FsRXJyb3JzLCBsb2NhbFRyYWNlO1xuXG4gIGxvY2FsRXJyb3JzID0gZXJyb3JzIHx8IFtdO1xuICBsb2NhbFRyYWNlICA9IHRyYWNlICB8fCBwcm9wZXJ0aWVzLkFVVEhPUklUWTtcblxuICBpZiAoYXV0aG9yaXR5ID09PSB1bmRlZmluZWQpIHtcbiAgICByZXR1cm4gbG9jYWxFcnJvcnM7XG4gIH1cblxuICBpZiAoIXhhcGlWYWxpZGF0aW9uVXRpbHMuaXNOb25OdWxsTWFwT2JqZWN0KGF1dGhvcml0eSkpIHtcbiAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMubG9jYWxUcmFjZVRvU3RyaW5nKGxvY2FsVHJhY2UpLFxuICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuQVVUSE9SSVRZX01VU1RfQkVfTk9OX05VTExfTUFQX09CSkVDVCxcbiAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgIH0pO1xuXG4gICAgcmV0dXJuIGxvY2FsRXJyb3JzO1xuICB9XG4gIGlmICh4YXBpVmFsaWRhdGlvblV0aWxzLmlzR3JvdXAoYXV0aG9yaXR5LCBvYmplY3RUeXBlcy5HUk9VUCkpIHtcbiAgICB2YWxpZGF0ZUdyb3VwKGF1dGhvcml0eSwgbG9jYWxUcmFjZSwgbG9jYWxFcnJvcnMpO1xuICAgIGlmICghYXV0aG9yaXR5Lm1lbWJlciB8fCAhYXV0aG9yaXR5Lm1lbWJlci5sZW5ndGggfHwgYXV0aG9yaXR5Lm1lbWJlci5sZW5ndGggIT09IHhhcGlHZW5lcmFsLkdST1VQX0FVVEhPUklUWV9BR0VOVF9NRU1CRVJTKSB7XG4gICAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSwgcHJvcGVydGllcy5NRU1CRVIpLFxuICAgICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5HUk9VUF9BVVRIT1JJVFlfQUdFTlRfTUVNQkVSU19NVVNUX0JFX1RXTyxcbiAgICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgICB9KTtcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgdmFsaWRhdGVBZ2VudChhdXRob3JpdHksIGxvY2FsVHJhY2UsIGxvY2FsRXJyb3JzKTtcbiAgfVxuXG4gIHJldHVybiBsb2NhbEVycm9ycztcbn1cblxuZnVuY3Rpb24gdmFsaWRhdGVDb250ZXh0QWN0aXZpdHlTdWJDb250ZXh0KHN1YkNvbnRleHQsIHRyYWNlLCBlcnJvcnMpIHtcbiAgdmFyIGxvY2FsRXJyb3JzLCBsb2NhbFRyYWNlO1xuXG4gIGxvY2FsRXJyb3JzID0gZXJyb3JzIHx8IFtdO1xuICBsb2NhbFRyYWNlICA9IHRyYWNlICB8fCBwcm9wZXJ0aWVzLlNVQl9DT05URVhUO1xuXG4gIGlmIChzdWJDb250ZXh0ID09PSB1bmRlZmluZWQpIHtyZXR1cm4gbG9jYWxFcnJvcnM7fVxuXG4gIGlmIChzdWJDb250ZXh0ID09PSBudWxsKSB7XG4gICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlKSxcbiAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLkNPTlRFWFRfQUNUSVZJVElFU19NVVNUX05PVF9CRV9OVUxMLFxuICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgfSk7XG4gIH0gZWxzZSBpZiAoeGFwaVZhbGlkYXRpb25VdGlscy5pc0FycmF5KHN1YkNvbnRleHQpKSB7XG4gICAgc3ViQ29udGV4dC5mb3JFYWNoKChhY3Rpdml0eSwgaSkgPT4ge1xuICAgICAgdmFsaWRhdGVBY3Rpdml0eShhY3Rpdml0eSwgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRMb29rdXBUb1RyYWNlKGxvY2FsVHJhY2UsIGkpLCBsb2NhbEVycm9ycyk7XG4gICAgfSk7XG4gIH0gZWxzZSBpZiAoeGFwaVZhbGlkYXRpb25VdGlscy5pc09iamVjdChzdWJDb250ZXh0KSkge1xuICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSksXG4gICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5DT05URVhUX0FDVElWSVRJRVNfU0hPVUxEX0JFX0FOX0FSUkFZLFxuICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLlNIT1VMRF9WSU9MQVRJT05cbiAgICB9KTtcblxuICAgIHZhbGlkYXRlQWN0aXZpdHkoc3ViQ29udGV4dCwgbG9jYWxUcmFjZSwgbG9jYWxFcnJvcnMpO1xuICB9IGVsc2Uge1xuICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSksXG4gICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5DT05URVhUX0FDVElWSVRJRVNfTVVTVF9CRV9BUlJBWV9PUl9BQ1RJVklUWV9PQkosXG4gICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT059KTtcbiAgfVxuICByZXR1cm4gbG9jYWxFcnJvcnM7XG59XG5cbmZ1bmN0aW9uIHZhbGlkYXRlQ29udGV4dEFjdGl2aXRpZXMoY29udGV4dEFjdGl2aXRpZXMsIHRyYWNlLCBlcnJvcnMpIHtcbiAgdmFyIGxvY2FsRXJyb3JzLCBsb2NhbFRyYWNlO1xuXG4gIGxvY2FsRXJyb3JzID0gZXJyb3JzIHx8IFtdO1xuICBsb2NhbFRyYWNlICA9IHRyYWNlICB8fCBwcm9wZXJ0aWVzLkNPTlRFWFRfQUNUSVZJVElFUztcblxuICBpZiAoY29udGV4dEFjdGl2aXRpZXMgPT09IHVuZGVmaW5lZCkge1xuICAgIHJldHVybiBsb2NhbEVycm9ycztcbiAgfVxuXG4gIGlmICgheGFwaVZhbGlkYXRpb25VdGlscy5pc05vbk51bGxNYXBPYmplY3QoY29udGV4dEFjdGl2aXRpZXMpKSB7XG4gICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlKSxcbiAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLkNPTlRFWFRfQUNUSVZJVElFU19NVVNUX0JFX05PTl9OVUxMX01BUF9PQkpFQ1QsXG4gICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICB9KTtcbiAgICByZXR1cm4gbG9jYWxFcnJvcnM7XG4gIH1cblxuICB2YWxpZGF0ZUNvbnRleHRBY3Rpdml0eVN1YkNvbnRleHQoY29udGV4dEFjdGl2aXRpZXMucGFyZW50LCB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuUEFSRU5UKSwgbG9jYWxFcnJvcnMpO1xuICB2YWxpZGF0ZUNvbnRleHRBY3Rpdml0eVN1YkNvbnRleHQoY29udGV4dEFjdGl2aXRpZXMuZ3JvdXBpbmcsIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSwgcHJvcGVydGllcy5HUk9VUElORyksIGxvY2FsRXJyb3JzKTtcbiAgdmFsaWRhdGVDb250ZXh0QWN0aXZpdHlTdWJDb250ZXh0KGNvbnRleHRBY3Rpdml0aWVzLmNhdGVnb3J5LCB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuQ0FURUdPUlkpLCBsb2NhbEVycm9ycyk7XG4gIHZhbGlkYXRlQ29udGV4dEFjdGl2aXR5U3ViQ29udGV4dChjb250ZXh0QWN0aXZpdGllcy5vdGhlciwgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRQcm9wVG9UcmFjZShsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLk9USEVSKSwgbG9jYWxFcnJvcnMpO1xuXG4gIHZhbGlkYXRlQWJzZW5jZU9mTm9uV2hpdGVsaXN0ZWRQcm9wZXJ0aWVzKGNvbnRleHRBY3Rpdml0aWVzLCB4YXBpV2hpdGVMaXN0UHJvcGVydGllcy5DT05URVhUX0FDVElWSVRJRVMsIGxvY2FsVHJhY2UsIGxvY2FsRXJyb3JzKTtcblxuICByZXR1cm4gbG9jYWxFcnJvcnM7XG59XG5cbmZ1bmN0aW9uIHZhbGlkYXRlQ29udGV4dChjb250ZXh0LCB0cmFjZSwgZXJyb3JzLCBzdGF0ZW1lbnRPYmplY3RPYmplY3RUeXBlKSB7XG4gIHZhciBsb2NhbEVycm9ycywgbG9jYWxUcmFjZTtcblxuICBsb2NhbEVycm9ycyA9IGVycm9ycyB8fCBbXTtcbiAgbG9jYWxUcmFjZSA9IHRyYWNlIHx8IHByb3BlcnRpZXMuQ09OVEVYVDtcblxuICBpZiAoY29udGV4dCA9PT0gdW5kZWZpbmVkKSB7cmV0dXJuIGxvY2FsRXJyb3JzO31cblxuICBpZiAoIXhhcGlWYWxpZGF0aW9uVXRpbHMuaXNOb25OdWxsTWFwT2JqZWN0KGNvbnRleHQpKSB7XG4gICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICB0cmFjZTogICBsb2NhbFRyYWNlLFxuICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuQ09OVEVYVF9NVVNUX0JFX05PTl9OVUxfTUFQX09CSkVDVCxcbiAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgIH0pO1xuXG4gICAgcmV0dXJuIGxvY2FsRXJyb3JzO1xuICB9XG5cbiAgaWYgKGNvbnRleHQucmVnaXN0cmF0aW9uICE9PSB1bmRlZmluZWQgJiYgKGNvbnRleHQucmVnaXN0cmF0aW9uID09PSBudWxsIHx8ICF4YXBpVmFsaWRhdGlvblV0aWxzLmlzU3RyaW5nKGNvbnRleHQucmVnaXN0cmF0aW9uKSB8fCAheGFwaVZhbGlkYXRpb25SZWdleC5VVUlELnRlc3QoY29udGV4dC5yZWdpc3RyYXRpb24pKSkge1xuICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSwgcHJvcGVydGllcy5SRUdJU1RSQVRJT04pLFxuICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuUkVHSVNUUkFUSU9OX01VU1RfQkVfVVVJRF9TVFJJTkcsXG4gICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICB9KTtcbiAgfVxuXG4gIGlmIChbb2JqZWN0VHlwZXMuR1JPVVAsIG9iamVjdFR5cGVzLkFHRU5UXS5pbmRleE9mKHN0YXRlbWVudE9iamVjdE9iamVjdFR5cGUpICE9PSB4YXBpR2VuZXJhbC5OT19JTkRFWF9GT1VORCkge1xuICAgIGlmIChjb250ZXh0LnJldmlzaW9uICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLlJFVklTSU9OKSxcbiAgICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuUkVWSVNJT05fTVVTVF9CRV9BR0VOVF9PUl9HUk9VUCxcbiAgICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAoY29udGV4dC5wbGF0Zm9ybSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSwgcHJvcGVydGllcy5QTEFURk9STSksXG4gICAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLlBMQVRGT1JNX01VU1RfTk9UX0JFX1VTRURfV0lUSF9SRVZJU0lPTl9BR0VOVF9PUl9HUk9VUCxcbiAgICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICB2YWxpZGF0ZVByb3BlcnR5SXNTdHJpbmcoY29udGV4dCwgcHJvcGVydGllcy5SRVZJU0lPTiwgbG9jYWxUcmFjZSwgbG9jYWxFcnJvcnMsIC8qaXNSZXF1aXJlZCovZmFsc2UsIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTik7XG4gIHZhbGlkYXRlUHJvcGVydHlJc1N0cmluZyhjb250ZXh0LCBwcm9wZXJ0aWVzLlBMQVRGT1JNLCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycywgLyppc1JlcXVpcmVkKi9mYWxzZSwgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OKTtcblxuICBpZiAoY29udGV4dC50ZWFtICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHZhbGlkYXRlR3JvdXAoY29udGV4dC50ZWFtLCB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuVEVBTSksIGxvY2FsRXJyb3JzKTtcbiAgfVxuXG4gIGlmIChjb250ZXh0LmNvbnRleHRBY3Rpdml0aWVzICE9PSB1bmRlZmluZWQpIHtcbiAgICB2YWxpZGF0ZUNvbnRleHRBY3Rpdml0aWVzKGNvbnRleHQuY29udGV4dEFjdGl2aXRpZXMsIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSwgcHJvcGVydGllcy5DT05URVhUX0FDVElWSVRJRVMpLCBsb2NhbEVycm9ycyk7XG4gIH1cblxuICBpZiAoY29udGV4dC5sYW5ndWFnZSAhPT0gdW5kZWZpbmVkICYmICF4YXBpVmFsaWRhdGlvblV0aWxzLmlzVmFsaWRMYW5ndWFnZVRhZyhjb250ZXh0Lmxhbmd1YWdlLCB4YXBpVmFsaWRhdGlvblJlZ2V4LkJDUF80NykpIHtcbiAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMubG9jYWxUcmFjZVRvU3RyaW5nKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuTEFOR1VBR0UpLFxuICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuTEFOR1VBR0VfTVVTVF9CRV9TVFJJTkcsXG4gICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICB9KTtcbiAgfVxuXG4gIGlmIChjb250ZXh0LnN0YXRlbWVudCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgdmFsaWRhdGVTdGF0ZW1lbnRSZWYoY29udGV4dC5zdGF0ZW1lbnQsIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSwgcHJvcGVydGllcy5TVEFURU1FTlQpLCBsb2NhbEVycm9ycyk7XG4gIH1cblxuICBpZiAoY29udGV4dC5pbnN0cnVjdG9yICE9PSB1bmRlZmluZWQpIHtcbiAgICBpZiAoeGFwaVZhbGlkYXRpb25VdGlscy5pc0dyb3VwKGNvbnRleHQuaW5zdHJ1Y3Rvciwgb2JqZWN0VHlwZXMuR1JPVVApKSB7XG4gICAgICB2YWxpZGF0ZUdyb3VwKGNvbnRleHQuaW5zdHJ1Y3RvciwgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRQcm9wVG9UcmFjZShsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLklOU1RSVUNUT1IpLCBsb2NhbEVycm9ycyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHZhbGlkYXRlQWdlbnQoY29udGV4dC5pbnN0cnVjdG9yLCB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuSU5TVFJVQ1RPUiksIGxvY2FsRXJyb3JzKTtcbiAgICB9XG4gIH1cblxuICB2YWxpZGF0ZUV4dGVuc2lvbnMoY29udGV4dC5leHRlbnNpb25zLCB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuRVhURU5TSU9OUyksIGxvY2FsRXJyb3JzKTtcbiAgdmFsaWRhdGVBYnNlbmNlT2ZOb25XaGl0ZWxpc3RlZFByb3BlcnRpZXMoY29udGV4dCwgeGFwaVdoaXRlTGlzdFByb3BlcnRpZXMuRVhURU5TSU9OUyxsb2NhbFRyYWNlLGxvY2FsRXJyb3JzKTtcblxuICByZXR1cm4gbG9jYWxFcnJvcnM7XG59XG5cbmZ1bmN0aW9uIHZhbGlkYXRlT2JqZWN0KG9iamVjdCwgdHJhY2UsIGVycm9ycywgaXNXaXRoaW5TdWJTdGF0ZW1lbnQpIHtcbiAgdmFyIGxvY2FsRXJyb3JzLCBsb2NhbFRyYWNlLCBvYmplY3RUeXBlO1xuXG4gIGxvY2FsRXJyb3JzID0gZXJyb3JzIHx8IFtdO1xuICBsb2NhbFRyYWNlICA9IHRyYWNlICB8fCBwcm9wZXJ0aWVzLk9CSkVDVDtcblxuICBpZiAob2JqZWN0ID09PSB1bmRlZmluZWQpIHtcbiAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMubG9jYWxUcmFjZVRvU3RyaW5nKGxvY2FsVHJhY2UpLFxuICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuT0JKRUNUX01VU1RfQkVfREVGSU5FRCxcbiAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgIH0pO1xuXG4gICAgcmV0dXJuIGxvY2FsRXJyb3JzO1xuICB9XG5cbiAgaWYgKCF4YXBpVmFsaWRhdGlvblV0aWxzLmlzTm9uTnVsbE1hcE9iamVjdChvYmplY3QpKSB7XG4gICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlKSxcbiAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLk9CSkVDVF9NVVNUX0JFX05PTl9OVUxMX01BUF9PQkpFQ1QsXG4gICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICB9KTtcblxuICAgIHJldHVybiBsb2NhbEVycm9ycztcbiAgfVxuXG4gIHZhbGlkYXRlUHJvcGVydHlJc1N0cmluZyhvYmplY3QsIHByb3BlcnRpZXMuT0JKRUNUX1RZUEUsIGxvY2FsVHJhY2UsIGxvY2FsRXJyb3JzLCAvKmlzUmVxdWlyZWQqL3RydWUsIHhhcGlFcnJvckxldmVscy5TSE9VTERfVklPTEFUSU9OKTtcblxuICBvYmplY3RUeXBlID0gb2JqZWN0Lm9iamVjdFR5cGUgfHwgb2JqZWN0VHlwZXMuQUNUSVZJVFk7XG5cbiAgc3dpdGNoIChvYmplY3RUeXBlKSB7XG4gICAgY2FzZSBvYmplY3RUeXBlcy5BQ1RJVklUWTpcbiAgICAgIHZhbGlkYXRlQWN0aXZpdHkob2JqZWN0LCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycyk7XG4gICAgICBicmVhaztcbiAgICBjYXNlIG9iamVjdFR5cGVzLkFHRU5UOlxuICAgICAgdmFsaWRhdGVBZ2VudChvYmplY3QsIGxvY2FsVHJhY2UsIGxvY2FsRXJyb3JzKTtcbiAgICAgIGJyZWFrO1xuICAgIGNhc2Ugb2JqZWN0VHlwZXMuR1JPVVA6XG4gICAgICB2YWxpZGF0ZUdyb3VwKG9iamVjdCwgbG9jYWxUcmFjZSwgbG9jYWxFcnJvcnMpO1xuICAgICAgYnJlYWs7XG4gICAgY2FzZSBvYmplY3RUeXBlcy5TVEFURU1FTlRfUkVGOlxuICAgICAgdmFsaWRhdGVTdGF0ZW1lbnRSZWYob2JqZWN0LCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycyk7XG4gICAgICBicmVhaztcbiAgICBjYXNlIG9iamVjdFR5cGVzLlNVQl9TVEFURU1FTlQ6XG4gICAgICBpZiAoaXNXaXRoaW5TdWJTdGF0ZW1lbnQpIHtcbiAgICAgICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSwgcHJvcGVydGllcy5PQkpFQ1RfVFlQRSksXG4gICAgICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuU1VCX1NUQVRFTUVOVF9NVVNUX05PVF9DT05UQUlOX1NVQl9TVEFURU1FTlQsXG4gICAgICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgICAgdmFsaWRhdGUob2JqZWN0LCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycywgIC8qaXNTdWJTdGF0ZW1lbnQqL3RydWUpO1xuICAgICAgYnJlYWs7XG4gICAgZGVmYXVsdDpcbiAgICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLk9CSkVDVF9UWVBFKSxcbiAgICAgICAgbWVzc2FnZTogYCR7eGFwaVZhbGlkYXRpb25FcnJvcnMuT0JKRUNUX1RZUEVfTVVTVF9CRV9WQUxJRF9PUFRJT059ICR7eEFwaVZhbGlkT2JqZWN0VHlwZXMudG9TdHJpbmcoKX1gLFxuICAgICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICAgIH0pO1xuICB9XG5cbiAgcmV0dXJuIGxvY2FsRXJyb3JzO1xufVxuXG5mdW5jdGlvbiB2YWxpZGF0ZShzdGF0ZW1lbnQsIHRyYWNlLCBlcnJvcnMsIGlzU3ViU3RhdGVtZW50KSB7XG4gIHZhciBsb2NhbEVycm9ycywgbG9jYWxUcmFjZSwgc3RhdGVtZW50T2JqZWN0T2JqZWN0VHlwZSwgd2hpdGVsaXN0ZWRQcm9wZXJ0aWVzO1xuXG4gIGxvY2FsRXJyb3JzID0gZXJyb3JzIHx8IFtdO1xuICBsb2NhbFRyYWNlICA9IHRyYWNlICB8fCBwcm9wZXJ0aWVzLlNUQVRFTUVOVDtcblxuICB3aGl0ZWxpc3RlZFByb3BlcnRpZXMgPSB4YXBpV2hpdGVMaXN0UHJvcGVydGllcy5TVEFURU1FTlQ7XG5cbiAgaWYgKCF4YXBpVmFsaWRhdGlvblV0aWxzLmlzTm9uTnVsbE1hcE9iamVjdChzdGF0ZW1lbnQpKSB7XG4gICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlKSxcbiAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLlNUQVRFTUVOVF9SRUZfTVVTVF9OT1RfQkVfTlVMTF9NQVBfT0JKRUNUUyxcbiAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgIH0pO1xuXG4gICAgcmV0dXJuIGxvY2FsRXJyb3JzO1xuICB9XG5cbiAgaWYgKCFpc1N1YlN0YXRlbWVudCkge1xuICAgIGlmIChzdGF0ZW1lbnQuaWQgPT09IG51bGwgfHwgc3RhdGVtZW50LmlkID09PSB1bmRlZmluZWQgfHwgIXhhcGlWYWxpZGF0aW9uVXRpbHMuaXNTdHJpbmcoc3RhdGVtZW50LmlkKSkge1xuICAgICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMubG9jYWxUcmFjZVRvU3RyaW5nKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuSUQpLFxuICAgICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5JRFNfU0hPVUxEX0JFX0dFTkVSQVRFRF9CWV9MUlMsXG4gICAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5TSE9VTERfVklPTEFUSU9OXG4gICAgICB9KTtcbiAgICB9IGVsc2UgaWYgKCF4YXBpVmFsaWRhdGlvblJlZ2V4LlVVSUQudGVzdChzdGF0ZW1lbnQuaWQpKSB7XG4gICAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSwgcHJvcGVydGllcy5JRCksXG4gICAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLklEX01VU1RfQkVfVkFMSUQsXG4gICAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgICAgfSk7XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIHdoaXRlbGlzdGVkUHJvcGVydGllcyA9IHhhcGlXaGl0ZUxpc3RQcm9wZXJ0aWVzLlNVQl9TVEFURU1FTlQ7XG4gIH1cblxuICB2YWxpZGF0ZUFjdG9yKHN0YXRlbWVudC5hY3RvciwgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRQcm9wVG9UcmFjZShsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLkFDVE9SKSwgbG9jYWxFcnJvcnMpO1xuICB2YWxpZGF0ZVZlcmIoc3RhdGVtZW50LnZlcmIsIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSwgcHJvcGVydGllcy5WRVJCKSwgbG9jYWxFcnJvcnMpO1xuICB2YWxpZGF0ZU9iamVjdChzdGF0ZW1lbnQub2JqZWN0LCB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuT0JKRUNUKSwgbG9jYWxFcnJvcnMsIGlzU3ViU3RhdGVtZW50KTtcbiAgdmFsaWRhdGVSZXN1bHQoc3RhdGVtZW50LnJlc3VsdCwgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRQcm9wVG9UcmFjZShsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLlJFU1VMVCksIGxvY2FsRXJyb3JzKTtcblxuICBzdGF0ZW1lbnRPYmplY3RPYmplY3RUeXBlID0gc3RhdGVtZW50Lm9iamVjdCAmJiBzdGF0ZW1lbnQub2JqZWN0Lm9iamVjdFR5cGUgPyBzdGF0ZW1lbnQub2JqZWN0Lm9iamVjdFR5cGUgOiBvYmplY3RUeXBlcy5BQ1RJVklUWTtcblxuICB2YWxpZGF0ZUNvbnRleHQoc3RhdGVtZW50LmNvbnRleHQsIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSwgcHJvcGVydGllcy5DT05URVhUKSwgbG9jYWxFcnJvcnMsIHN0YXRlbWVudE9iamVjdE9iamVjdFR5cGUpO1xuICB2YWxpZGF0ZVByb3BlcnR5SXNJU084NjAxU3RyaW5nKHN0YXRlbWVudCwgcHJvcGVydGllcy5USU1FU1RBTVAsIGxvY2FsVHJhY2UsIGxvY2FsRXJyb3JzKTtcbiAgdmFsaWRhdGVQcm9wZXJ0eUlzSVNPODYwMVN0cmluZyhzdGF0ZW1lbnQsIHByb3BlcnRpZXMuU1RPUkVELCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycyk7XG5cbiAgdmFsaWRhdGVBdXRob3JpdHkoc3RhdGVtZW50LmF1dGhvcml0eSwgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRQcm9wVG9UcmFjZShsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLkFVVEhPUklUWSksIGxvY2FsRXJyb3JzKTtcbiAgdmFsaWRhdGVWZXJzaW9uKHN0YXRlbWVudC52ZXJzaW9uLCB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuVkVSU0lPTiksIGxvY2FsRXJyb3JzKTtcbiAgdmFsaWRhdGVBdHRhY2htZW50cyhzdGF0ZW1lbnQuYXR0YWNobWVudHMsIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSwgcHJvcGVydGllcy5BVFRBQ0hNRU5UUyksIGxvY2FsRXJyb3JzKTtcblxuICB2YWxpZGF0ZUFic2VuY2VPZk5vbldoaXRlbGlzdGVkUHJvcGVydGllcyhzdGF0ZW1lbnQsIHdoaXRlbGlzdGVkUHJvcGVydGllcywgbG9jYWxUcmFjZSwgbG9jYWxFcnJvcnMpO1xuXG4gIHJldHVybiBsb2NhbEVycm9ycztcbn1cblxuZnVuY3Rpb24gbWFrZVN0YXRlbWVudFJlcG9ydChzdGF0ZW1lbnQpIHtcbiAgdmFyIGxvY2FsRXJyb3JzO1xuXG4gIGxvY2FsRXJyb3JzID0gW107XG4gIHZhbGlkYXRlKHN0YXRlbWVudCwgcHJvcGVydGllcy5TVEFURU1FTlQsIGxvY2FsRXJyb3JzLCAgLyppc1JlcXVpcmVkKi9mYWxzZSk7XG5cbiAgcmV0dXJuIG1ha2VWMVJlcG9ydChzdGF0ZW1lbnQsIGxvY2FsRXJyb3JzKTtcbn1cblxuZnVuY3Rpb24gdmFsaWRhdGVBbWJpZ3VvdXNUeXBlU3RhdGVtZW50KHN0YXRlbWVudCkge1xuICB2YXIgc3RhdGVtZW50T2JqZWN0O1xuXG4gIGlmIChzdGF0ZW1lbnQgPT09IHVuZGVmaW5lZCkge1xuICAgIHJldHVybiBtYWtlVjFTaW5nbGVFcnJvclJlcG9ydCgvKmluc3RhbmNlKi9udWxsLCB7XG4gICAgICB0cmFjZTogICBwcm9wZXJ0aWVzLlNUQVRFTUVOVCxcbiAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLlNUQVRFTUVOVF9BUkdVTUVOVF9NVVNUX0JFX1BST1ZJREVELFxuICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgfSk7XG4gIH1cblxuICBpZiAoc3RhdGVtZW50ID09PSBudWxsKSB7XG4gICAgcmV0dXJuIG1ha2VWMVNpbmdsZUVycm9yUmVwb3J0KC8qaW5zdGFuY2UqL251bGwsIHtcbiAgICAgIHRyYWNlOiAgIHByb3BlcnRpZXMuU1RBVEVNRU5ULFxuICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuU1RBVEVNRU5UX01VU1RfTk9UX0JFX05VTEwsXG4gICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICB9KTtcbiAgfVxuXG4gIGlmICh4YXBpVmFsaWRhdGlvblV0aWxzLmlzU3RyaW5nKHN0YXRlbWVudCkpIHtcbiAgICB0cnkge1xuICAgICAgc3RhdGVtZW50T2JqZWN0ID0gSlNPTi5wYXJzZShzdGF0ZW1lbnQpO1xuICAgICAgaWYgKHN0YXRlbWVudE9iamVjdCA9PT0gbnVsbCB8fCAheGFwaVZhbGlkYXRpb25VdGlscy5pc09iamVjdChzdGF0ZW1lbnRPYmplY3QpIHx8IHhhcGlWYWxpZGF0aW9uVXRpbHMuaXNBcnJheShzdGF0ZW1lbnRPYmplY3QpKSB7XG4gICAgICAgIHJldHVybiBtYWtlVjFTaW5nbGVFcnJvclJlcG9ydChzdGF0ZW1lbnRPYmplY3QsIHtcbiAgICAgICAgICB0cmFjZTogICBwcm9wZXJ0aWVzLlNUQVRFTUVOVCxcbiAgICAgICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5TVEFURU1FTlRfTVVTVF9CRV9QQVJTRURfQ09SUkVDVExZLFxuICAgICAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICByZXR1cm4gbWFrZVYxU2luZ2xlRXJyb3JSZXBvcnQoc3RhdGVtZW50T2JqZWN0LCB7XG4gICAgICAgIHRyYWNlOiAgIHByb3BlcnRpZXMuU1RBVEVNRU5ULFxuICAgICAgICBtZXNzYWdlOiBgJHt4YXBpVmFsaWRhdGlvbkVycm9ycy5JTlZBTElEX0pTT059OiAke2UubWVzc2FnZX1gLFxuICAgICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHJldHVybiBtYWtlU3RhdGVtZW50UmVwb3J0KHN0YXRlbWVudE9iamVjdCk7XG4gIH1cblxuICBpZiAoeGFwaVZhbGlkYXRpb25VdGlscy5pc09iamVjdChzdGF0ZW1lbnQpICYmICF4YXBpVmFsaWRhdGlvblV0aWxzLmlzQXJyYXkoc3RhdGVtZW50KSkge1xuICAgIHJldHVybiBtYWtlU3RhdGVtZW50UmVwb3J0KHN0YXRlbWVudCk7XG4gIH1cblxuICByZXR1cm4gbWFrZVYxU2luZ2xlRXJyb3JSZXBvcnQoLyppbnN0YW5jZSovbnVsbCwge1xuICAgIHRyYWNlOiAgIHByb3BlcnRpZXMuU1RBVEVNRU5ULFxuICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLlNUQVRFTUVOVF9BUkdVTUVOVF9JU19OT1RfVkFMSUQsXG4gICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gIH0pO1xufVxuXG5mdW5jdGlvbiBkYXRlSW5jbHVkZXNab25lSW5mb3JtYXRpb24obWF0Y2hlZCkge1xuICByZXR1cm4gbWF0Y2hlZFtkYXRlRm9ybWF0UmVnZXhQb3NpdGlvbnMuWk9ORV0gfHxcbiAgICAgICAgICAobWF0Y2hlZFtkYXRlRm9ybWF0UmVnZXhQb3NpdGlvbnMuUkVMQVRJVkVfVElNRV0gJiYgbWF0Y2hlZFtkYXRlRm9ybWF0UmVnZXhQb3NpdGlvbnMuVElNRV9aT05FX0hPVVJdKTtcbn1cblxueGFwaVZhbGlkYXRpb24gPSB7XG4gIHZhbGlkYXRlU3RhdGVtZW50OiB2YWxpZGF0ZUFtYmlndW91c1R5cGVTdGF0ZW1lbnRcbn07XG5cbm1vZHVsZS5leHBvcnRzID0geGFwaVZhbGlkYXRpb247XG4iLCJpbXBvcnQge199IGZyb20gJ3VuZGVyc2NvcmUnO1xuaW1wb3J0IHtleHBlY3R9IGZyb20gJ2NoYWknO1xuaW1wb3J0IHt4YXBpVmFsaWRhdG9yfSBmcm9tICcuLi9zcmMveGFwaVZhbGlkYXRvcic7XG4vLyB2YXIgeGFwaVZhbGlkYXRvciA9IHJlcXVpcmUoJy4uL3hhcGlWYWxpZGF0b3InKTtcblxuZGVzY3JpYmUoXCJ4YXBpVmFsaWRhdG9yXCIsIGZ1bmN0aW9uKCkge1xuICBkZXNjcmliZShcIiN2YWxpZGF0ZVN0YXRlbWVudFwiLCBmdW5jdGlvbigpIHtcblxuICAgIGZ1bmN0aW9uIHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlcG9ydCwgcHJlZml4LCB0YXJnZXRMZXZlbCkge1xuICAgICAgaWYgKHJlcG9ydCA9PT0gbnVsbCB8fCByZXBvcnQgPT09IHVuZGVmaW5lZCB8fCByZXBvcnQuZXJyb3JzID09PSBudWxsIHx8IHJlcG9ydC5lcnJvcnMgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgICB2YXIgaGFzVGFyZ2V0TGV2ZWwgPSB0YXJnZXRMZXZlbCAhPT0gbnVsbCAmJiB0YXJnZXRMZXZlbCAhPT0gdW5kZWZpbmVkO1xuICAgICAgcmV0dXJuIF8uYW55KHJlcG9ydC5lcnJvcnMsIGZ1bmN0aW9uKGVycikge1xuICAgICAgICB2YXIgZm91bmRQcmVmaXggPSBlcnIudHJhY2UuaW5kZXhPZihwcmVmaXgpID09PSAwO1xuICAgICAgICByZXR1cm4gaGFzVGFyZ2V0TGV2ZWwgPyB0YXJnZXRMZXZlbCA9PT0gZXJyLmxldmVsICYmIGZvdW5kUHJlZml4IDogZm91bmRQcmVmaXg7XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBkZXNjcmliZShcIndoZW4gcGFzc2VkIG5vIGFyZ3VtZW50c1wiLCBmdW5jdGlvbigpIHtcbiAgICAgIGl0KFwicmV0dXJucyBub24tbnVsbCByZXBvcnRcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciByZXN1bHQgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KCk7XG4gICAgICAgIGV4cGVjdChyZXN1bHQpLnRvLmJlLm5vdC5udWxsO1xuICAgICAgICBleHBlY3QocmVzdWx0KS50by5iZS5hKFwiT2JqZWN0XCIpO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KFwiaW5jbHVkZXMgb25lIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgcmVzdWx0ID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudCgpO1xuICAgICAgICB2YXIgZXJyb3JzID0gcmVzdWx0LmVycm9ycztcbiAgICAgICAgZXhwZWN0KGVycm9ycykudG8uYmUuaW5zdGFuY2VPZihBcnJheSk7XG4gICAgICAgIGV4cGVjdChlcnJvcnMpLnRvLmhhdmUubGVuZ3RoKDEpO1xuICAgICAgICBleHBlY3QoZXJyb3JzWzBdKS50by5oYXZlLnByb3BlcnR5KFwibWVzc2FnZVwiKVxuICAgICAgICAgIC50aGF0LmlzLmEoJ3N0cmluZycpXG4gICAgICAgICAgLnRoYXQuZXF1YWxzKCdObyBzdGF0ZW1lbnQgYXJndW1lbnQgcHJvdmlkZWQuJyk7XG4gICAgICAgIGV4cGVjdChlcnJvcnNbMF0pLnRvLmhhdmUucHJvcGVydHkoXCJsZXZlbFwiKVxuICAgICAgICAgIC50aGF0LmVxdWFscyhcIk1VU1RfVklPTEFUSU9OXCIpO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KFwiaGFzIGEgbnVsbCBpbnN0YW5jZSBwcm9wZXJ0eSBpbiB0aGUgcmVwb3J0XCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICBleHBlY3QoeGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudCgpKVxuICAgICAgICAgIC50by5oYXZlLnByb3BlcnR5KFwiaW5zdGFuY2VcIilcbiAgICAgICAgICAgIC50aGF0LmlzLm51bGw7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGRlc2NyaWJlKFwid2hlbiBwYXNzZWQgYSBudWxsIGFyZ3VtZW50XCIsIGZ1bmN0aW9uKCkge1xuICAgICAgaXQoXCJyZXR1cm5zIG5vbi1udWxsIHJlcG9ydFwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIHJlc3VsdCA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQobnVsbCk7XG4gICAgICAgIGV4cGVjdChyZXN1bHQpLnRvLmJlLm5vdC5udWxsO1xuICAgICAgICBleHBlY3QocmVzdWx0KS50by5iZS5hKFwiT2JqZWN0XCIpO1xuICAgICAgICBleHBlY3QocmVzdWx0KS50by5oYXZlLnByb3BlcnR5KFwiZXJyb3JzXCIpXG4gICAgICAgICAgLnRoYXQuaXMuYShcIkFycmF5XCIpO1xuICAgICAgICBleHBlY3QocmVzdWx0KS50by5oYXZlLnByb3BlcnR5KFwiaW5zdGFuY2VcIik7XG4gICAgICB9KTtcblxuICAgICAgaXQoXCJpbmNsdWRlcyBvbmUgZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciByZXN1bHQgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KG51bGwpO1xuICAgICAgICB2YXIgZXJyb3JzID0gcmVzdWx0LmVycm9ycztcbiAgICAgICAgZXhwZWN0KGVycm9ycykudG8uYmUuaW5zdGFuY2VPZihBcnJheSk7XG4gICAgICAgIGV4cGVjdChlcnJvcnMpLnRvLmhhdmUubGVuZ3RoKDEpO1xuICAgICAgICBleHBlY3QoZXJyb3JzWzBdKS50by5oYXZlLnByb3BlcnR5KFwibWVzc2FnZVwiKVxuICAgICAgICAgIC50aGF0LmlzLmEoJ3N0cmluZycpXG4gICAgICAgICAgLnRoYXQuZXF1YWxzKCdOdWxsIHN0YXRlbWVudCBhcmd1bWVudCBwcm92aWRlZC4nKTtcbiAgICAgICAgZXhwZWN0KGVycm9yc1swXSkudG8uaGF2ZS5wcm9wZXJ0eShcImxldmVsXCIpXG4gICAgICAgICAgLnRoYXQuZXF1YWxzKFwiTVVTVF9WSU9MQVRJT05cIik7XG4gICAgICB9KTtcblxuICAgICAgaXQoXCJoYXMgYSBudWxsIGluc3RhbmNlIHByb3BlcnR5IGluIHRoZSByZXBvcnRcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIGV4cGVjdCh4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KG51bGwpKVxuICAgICAgICAgIC50by5oYXZlLnByb3BlcnR5KFwiaW5zdGFuY2VcIilcbiAgICAgICAgICAgIC50aGF0LmlzLm51bGw7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGRlc2NyaWJlKFwid2hlbiBwYXNzZWQgYSBqc29uIHN0cmluZyBhcmd1bWVudFwiLCBmdW5jdGlvbigpIHtcbiAgICAgIHZhciBtaW5pbWFsSnNvblN0cmluZyA9IFwie1xcXCJpZFxcXCI6XFxcIndoYXRldmVyXFxcIn1cIjtcbiAgICAgIGl0KFwicmV0dXJucyBub24tbnVsbCByZXBvcnRcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciByZXN1bHQgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KG1pbmltYWxKc29uU3RyaW5nKTtcbiAgICAgICAgZXhwZWN0KHJlc3VsdCkudG8uYmUubm90Lm51bGw7XG4gICAgICAgIGV4cGVjdChyZXN1bHQpLnRvLmJlLmEoXCJPYmplY3RcIik7XG4gICAgICAgIGV4cGVjdChyZXN1bHQpLnRvLmhhdmUucHJvcGVydHkoXCJlcnJvcnNcIilcbiAgICAgICAgICAudGhhdC5pcy5hKFwiQXJyYXlcIik7XG4gICAgICAgIGV4cGVjdChyZXN1bHQpLnRvLmhhdmUucHJvcGVydHkoXCJpbnN0YW5jZVwiKTtcbiAgICAgIH0pO1xuXG4gICAgICBpdChcImhhcyBhbiBpbnN0YW5jZSBwcm9wZXJ0eSB3aXRoIHRoZSBkZXNlcmlhbGl6ZWQgSlNPTiBpbiB0aGUgcmVwb3J0XCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgcmVzdWx0ID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChtaW5pbWFsSnNvblN0cmluZyk7XG4gICAgICAgIGV4cGVjdChyZXN1bHQpLnRvLmhhdmUucHJvcGVydHkoXCJpbnN0YW5jZVwiKVxuICAgICAgICAgIC50aGF0LmlzLmFuKFwiT2JqZWN0XCIpXG4gICAgICAgICAgLnRoYXQuZGVlcC5lcXVhbHMoe1wiaWRcIjpcIndoYXRldmVyXCJ9KTtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgZGVzY3JpYmUoXCJ3aGVuIHBhc3NlZCBhIGpzb24gc3RyaW5nIGFyZ3VtZW50IGVuY29kaW5nIG51bGxcIiwgZnVuY3Rpb24oKSB7XG4gICAgICB2YXIgbWluaW1hbEpzb25TdHJpbmcgPSBcIm51bGxcIjtcbiAgICAgIGl0KFwicmV0dXJucyBub24tbnVsbCByZXBvcnRcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciByZXN1bHQgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KG1pbmltYWxKc29uU3RyaW5nKTtcbiAgICAgICAgZXhwZWN0KHJlc3VsdCkudG8uYmUubm90Lm51bGw7XG4gICAgICAgIGV4cGVjdChyZXN1bHQpLnRvLmJlLmEoXCJPYmplY3RcIik7XG4gICAgICAgIGV4cGVjdChyZXN1bHQpLnRvLmhhdmUucHJvcGVydHkoXCJlcnJvcnNcIilcbiAgICAgICAgICAudGhhdC5pcy5hKFwiQXJyYXlcIik7XG4gICAgICAgIGV4cGVjdChyZXN1bHQpLnRvLmhhdmUucHJvcGVydHkoXCJpbnN0YW5jZVwiKTtcbiAgICAgIH0pO1xuXG4gICAgICBpdChcImluY2x1ZGVzIG9uZSBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIHJlc3VsdCA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQobWluaW1hbEpzb25TdHJpbmcpO1xuICAgICAgICB2YXIgZXJyb3JzID0gcmVzdWx0LmVycm9ycztcbiAgICAgICAgZXhwZWN0KGVycm9ycykudG8uYmUuaW5zdGFuY2VPZihBcnJheSk7XG4gICAgICAgIGV4cGVjdChlcnJvcnMpLnRvLmhhdmUubGVuZ3RoKDEpO1xuICAgICAgICBleHBlY3QoZXJyb3JzWzBdKS50by5oYXZlLnByb3BlcnR5KFwibWVzc2FnZVwiKTtcbiAgICAgICAgZXhwZWN0KGVycm9yc1swXSkudG8uaGF2ZS5wcm9wZXJ0eShcImxldmVsXCIpXG4gICAgICAgICAgLnRoYXQuZXF1YWxzKFwiTVVTVF9WSU9MQVRJT05cIik7XG4gICAgICB9KTtcblxuICAgICAgaXQoXCJoYXMgYW4gaW5zdGFuY2UgcHJvcGVydHkgd2l0aCBudWxsIHZhbHVlXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgcmVzdWx0ID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChtaW5pbWFsSnNvblN0cmluZyk7XG4gICAgICAgIGV4cGVjdChyZXN1bHQpLnRvLmhhdmUucHJvcGVydHkoXCJpbnN0YW5jZVwiKVxuICAgICAgICAgIC50aGF0LmlzLm51bGw7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGRlc2NyaWJlKFwid2hlbiBwYXNzZWQgYW4gaW52YWxpZCBqc29uIHN0cmluZyBhcmd1bWVudFwiLCBmdW5jdGlvbigpIHtcbiAgICAgIHZhciBtaW5pbWFsSnNvblN0cmluZyA9IFwiZGVycFwiO1xuICAgICAgaXQoXCJyZXR1cm5zIG5vbi1udWxsIHJlcG9ydFwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIHJlc3VsdCA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQobWluaW1hbEpzb25TdHJpbmcpO1xuICAgICAgICBleHBlY3QocmVzdWx0KS50by5iZS5ub3QubnVsbDtcbiAgICAgICAgZXhwZWN0KHJlc3VsdCkudG8uYmUuYShcIk9iamVjdFwiKTtcbiAgICAgICAgZXhwZWN0KHJlc3VsdCkudG8uaGF2ZS5wcm9wZXJ0eShcImVycm9yc1wiKVxuICAgICAgICAgIC50aGF0LmlzLmEoXCJBcnJheVwiKTtcbiAgICAgICAgZXhwZWN0KHJlc3VsdCkudG8uaGF2ZS5wcm9wZXJ0eShcImluc3RhbmNlXCIpO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KFwiaW5jbHVkZXMgb25lIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgcmVzdWx0ID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChtaW5pbWFsSnNvblN0cmluZyk7XG4gICAgICAgIHZhciBlcnJvcnMgPSByZXN1bHQuZXJyb3JzO1xuICAgICAgICBleHBlY3QoZXJyb3JzKS50by5iZS5pbnN0YW5jZU9mKEFycmF5KTtcbiAgICAgICAgZXhwZWN0KGVycm9ycykudG8uaGF2ZS5sZW5ndGgoMSk7XG4gICAgICAgIGV4cGVjdChlcnJvcnNbMF0pLnRvLmhhdmUucHJvcGVydHkoXCJtZXNzYWdlXCIpO1xuICAgICAgICBleHBlY3QoZXJyb3JzWzBdKS50by5oYXZlLnByb3BlcnR5KFwibGV2ZWxcIilcbiAgICAgICAgICAudGhhdC5lcXVhbHMoXCJNVVNUX1ZJT0xBVElPTlwiKTtcbiAgICAgIH0pO1xuXG4gICAgICBpdChcImhhcyBhbiBpbnN0YW5jZSBwcm9wZXJ0eSB3aXRoIG51bGwgdmFsdWVcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciByZXN1bHQgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KG1pbmltYWxKc29uU3RyaW5nKTtcbiAgICAgICAgZXhwZWN0KHJlc3VsdCkudG8uaGF2ZS5wcm9wZXJ0eShcImluc3RhbmNlXCIpXG4gICAgICAgICAgLnRoYXQuaXMubnVsbDtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgZGVzY3JpYmUoXCJ3aGVuIHBhc3NlZCBhIHN0YXRlbWVudCBvYmplY3RcIiwgZnVuY3Rpb24oKSB7XG4gICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9fTtcbiAgICAgIGl0KFwicmV0dXJucyBub24tbnVsbCByZXBvcnRcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciByZXN1bHQgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgZXhwZWN0KHJlc3VsdCkudG8uYmUubm90Lm51bGw7XG4gICAgICAgIGV4cGVjdChyZXN1bHQpLnRvLmJlLmEoXCJPYmplY3RcIik7XG4gICAgICAgIGV4cGVjdChyZXN1bHQpLnRvLmhhdmUucHJvcGVydHkoXCJlcnJvcnNcIilcbiAgICAgICAgICAudGhhdC5pcy5hKFwiQXJyYXlcIik7XG4gICAgICAgIGV4cGVjdChyZXN1bHQpLnRvLmhhdmUucHJvcGVydHkoXCJpbnN0YW5jZVwiKTtcbiAgICAgIH0pO1xuXG4gICAgICBpdChcImhhcyBhbiBpbnN0YW5jZSBwcm9wZXJ0eSB0aGF0IG1hdGNoZXMgdGhlIGlucHV0IG9iamVjdFwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIHJlc3VsdCA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICBleHBlY3QocmVzdWx0KS50by5oYXZlLnByb3BlcnR5KFwiaW5zdGFuY2VcIilcbiAgICAgICAgICAudGhhdC5kZWVwLmVxdWFscyhpbnB1dFN0YXRlbWVudCk7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGRlc2NyaWJlKFwid2hlbiBnaXZlbiBhIG51bGwgaWQgcHJvcGVydHlcIiwgZnVuY3Rpb24oKSB7XG4gICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBudWxsICxcbiAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9fTtcbiAgICAgIGl0KFwiaGFzIGFuIGVycm9yIGFib3V0IHRoZSBpZCBwcm9wZXJ0eVwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIHJlc3VsdCA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0LCBcInN0YXRlbWVudC5pZFwiKSkudG8uYmUudHJ1ZTtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgZGVzY3JpYmUoXCJ3aGVuIGdpdmVuIGFuIGludmFsaWQgVVVJRCBpZCBwcm9wZXJ0eVwiLCBmdW5jdGlvbigpIHtcbiAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiYWJjMTIzXCIsXG4gICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifX07XG4gICAgICBpdChcImhhcyBhbiBlcnJvciBhYm91dCB0aGUgaWQgcHJvcGVydHlcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciByZXN1bHQgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdCwgXCJzdGF0ZW1lbnQuaWRcIikpLnRvLmJlLnRydWU7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGRlc2NyaWJlKFwid2hlbiBnaXZlbiBhIHZhbGlkIFVVSUQgaWQgcHJvcGVydHlcIiwgZnVuY3Rpb24oKSB7XG4gICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiLFxuICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn19O1xuICAgICAgaXQoXCJoYXMgYW4gZXJyb3IgYWJvdXQgdGhlIGlkIHByb3BlcnR5XCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgcmVzdWx0ID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHQsIFwic3RhdGVtZW50LmlkXCIpKS50by5iZS5mYWxzZTtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgZGVzY3JpYmUoXCJ3aGVuIGdpdmVuIGEgbnVsbCBhY3RvciBwcm9wZXJ0eVwiLCBmdW5jdGlvbigpIHtcbiAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgIGFjdG9yIDogbnVsbCxcbiAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifX07XG4gICAgICBpdChcImhhcyBhbiBlcnJvciBhYm91dCB0aGUgYWN0b3IgcHJvcGVydHlcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciByZXN1bHQgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdCwgXCJzdGF0ZW1lbnQuYWN0b3JcIikpLnRvLmJlLnRydWU7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGRlc2NyaWJlKFwid2hlbiBnaXZlbiBhbiBlbXB0eSBub24tbnVsbCBhY3RvciBwcm9wZXJ0eVwiLCBmdW5jdGlvbigpIHtcbiAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgIGFjdG9yIDoge30sXG4gICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn19O1xuICAgICAgaXQoXCJoYXMgYW4gZXJyb3IgYWJvdXQgdGhlIGFjdG9yIHByb3BlcnR5XCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgcmVzdWx0ID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHQsIFwic3RhdGVtZW50LmFjdG9yXCIpKS50by5iZS50cnVlO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBkZXNjcmliZShcIndoZW4gZ2l2ZW4gYW4gb3RoZXJ3aXNlIHZhbGlkIGFjdG9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzpncm91cEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifX07XG4gICAgICBpdChcInRoZSBuYW1lIHByb3BlcnR5IGlzIG9wdGlvbmFsXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgcmVzdWx0ID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgIGV4cGVjdChyZXN1bHQuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDApO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KFwidGhlIG5hbWUgcHJvcGVydHkgcHJvZHVjZXMgbm8gZXJyb3JzIHdoZW4gYSBzaW1wbGUgc3RyaW5nXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICBpbnB1dFN0YXRlbWVudC5hY3Rvci5uYW1lID0gXCJoZWxsb1wiO1xuICAgICAgICB2YXIgcmVzdWx0ID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgIGV4cGVjdChyZXN1bHQuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDApO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KFwidGhlIG5hbWUgcHJvcGVydHkgcHJvZHVjZXMgbm8gZXJyb3JzIHdoZW4gYSBzaW1wbGUgc3RyaW5nXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICBpbnB1dFN0YXRlbWVudC5hY3Rvci5uYW1lID0gMS4yMztcbiAgICAgICAgdmFyIHJlc3VsdCA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0LCBcInN0YXRlbWVudC5hY3Rvci5uYW1lXCIpKS50by5iZS50cnVlO1xuICAgICAgICBleHBlY3QocmVzdWx0LmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgZGVzY3JpYmUoXCJ3aGVuIGdpdmVuIGFuIGFjdG9yIHdpdGggYW4gb2JqZWN0VHlwZSBvZiAnR3JvdXAnXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgdmFyIG1vcmVWYWxpZFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgIGFjdG9yIDoge29iamVjdFR5cGU6XCJHcm91cFwiLCBtZW1iZXI6W119LFxuICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9fTtcbiAgICAgIGl0KFwidGhlIG1lbWJlciBwcm9wZXJ0eSBoYXMgbm8gZXJyb3JzIGFib3V0IGl0IHdoZW4gcHJlc2VudFwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIHJlc3VsdCA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQobW9yZVZhbGlkU3RhdGVtZW50KTtcbiAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdCwgXCJzdGF0ZW1lbnQuYWN0b3IubWVtYmVyXCIpKS50by5iZS5mYWxzZTtcbiAgICAgIH0pO1xuXG4gICAgICBpdChcInRoZSBtZW1iZXIgcHJvcGVydHkgaXMgcmVxdWlyZWQgdG8gYmUgcHJlc2VudCBpZiB0aGUgYWN0b3IgaXMgdW5pZGVudGlmaWVkLCBhbmQgcHJvZHVjZXMgYW4gZXJyb3Igd2hlbiBhYnNlbnRcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBpbnB1dEludmFsaWRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICBhY3RvciA6IHtvYmplY3RUeXBlOlwiR3JvdXBcIn0sXG4gICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn19O1xuICAgICAgICB2YXIgcmVzdWx0ID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dEludmFsaWRTdGF0ZW1lbnQpO1xuICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0LCBcInN0YXRlbWVudC5hY3Rvci5tZW1iZXJcIikpLnRvLmJlLnRydWU7XG4gICAgICB9KTtcblxuICAgICAgaXQoXCJ0aGUgbWVtYmVyIHByb3BlcnR5IGlzIG5vdCByZXF1aXJlZCB0byBiZSBwcmVzZW50IGlmIHRoZSBhY3RvciBpcyBpZGVudGlmaWVkXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgcmVzdWx0ID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudCh7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICBhY3RvciA6IHtvYmplY3RUeXBlOlwiR3JvdXBcIiwgbWJveDpcIm1haWx0bzpncm91cEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifX0pO1xuICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0LCBcInN0YXRlbWVudC5hY3Rvci5tZW1iZXJcIikpLnRvLmJlLmZhbHNlO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KFwidGhlIG1lbWJlciBwcm9wZXJ0eSBpcyBhbGxvd2VkIHRvIGJlIHByZXNlbnQgaWYgdGhlIGFjdG9yIGlzIGlkZW50aWZpZWRcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciByZXN1bHQgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIsXG4gICAgICAgICAgYWN0b3IgOiB7b2JqZWN0VHlwZTpcIkdyb3VwXCIsIG1ib3g6XCJtYWlsdG86Z3JvdXBAZXhhbXBsZS5jb21cIiwgbWVtYmVyOltdfSxcbiAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifX0pO1xuICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0LCBcInN0YXRlbWVudC5hY3Rvci5tZW1iZXJcIikpLnRvLmJlLmZhbHNlO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBkZXNjcmliZShcIndoZW4gZ2l2ZW4gYW4gYWN0b3Igd2l0aCBhIG1lbWJlcnMgcHJvcGVydHlcIiwgZnVuY3Rpb24oKSB7XG4gICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICBhY3RvciA6IHttZW1iZXI6W119LFxuICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9fTtcbiAgICAgIGl0KFwidGhlIG1lbWJlciBwcm9wZXJ0eSBoYXMgbm8gZXJyb3JzIGFib3V0IGl0IHdoZW4gcHJlc2VudCBidXQgZW1wdHlcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIGV4cGVjdCh4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KS5lcnJvcnMpLnRvLmJlLmVtcHR5O1xuICAgICAgfSk7XG5cbiAgICAgIGl0KFwidGhlIG1lbWJlciBwcm9wZXJ0eSBoYXMgbm8gZXJyb3JzIHdoZW4gcG9wdWxhdGVkIHdpdGggYSBzaW1wbGUgYWdlbnRcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIGlucHV0U3RhdGVtZW50LmFjdG9yLm1lbWJlciA9IFt7bWJveDpcIm1haWx0bzpncm91cEBleGFtcGxlLmNvbVwifV07XG4gICAgICAgIGV4cGVjdCh4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KS5lcnJvcnMpLnRvLmJlLmVtcHR5O1xuICAgICAgfSk7XG5cbiAgICAgIGl0KFwidGhlIG1lbWJlciBwcm9wZXJ0eSByZXBvcnRzIGFuIGVycm9yIHdoZW4gcG9wdWxhdGVkIHdpdGggYSBHcm91cCBvYmplY3QgdmlhIG9iamVjdFR5cGVcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIGlucHV0U3RhdGVtZW50LmFjdG9yLm1lbWJlciA9IFt7bWJveDpcIm1haWx0bzpncm91cEBleGFtcGxlLmNvbVwiLCBvYmplY3RUeXBlOlwiR3JvdXBcIn1dO1xuICAgICAgICBleHBlY3QoeGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCkuZXJyb3JzKVxuICAgICAgICAgIC50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KFwidGhlIG1lbWJlciBwcm9wZXJ0eSdzIGFnZW50IHJlcG9ydHMgYW4gZXJyb3Igd2hlbiBnaXZlbiBhbiBhY2NvdW50IG1pc3NpbmcgaXRzIGhvbWVQYWdlXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICBpbnB1dFN0YXRlbWVudC5hY3Rvci5tZW1iZXIgPSBbe2FjY291bnQ6e25hbWU6XCJib2JcIn19XTtcbiAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpLCBcInN0YXRlbWVudC5hY3Rvci5tZW1iZXJbMF0uYWNjb3VudC5ob21lUGFnZVwiKSkudG8uYmUudHJ1ZTtcbiAgICAgIH0pO1xuXG4gICAgICBpdChcInRoZSBtZW1iZXIgcHJvcGVydHkncyBhZ2VudCByZXBvcnRzIGFuIGVycm9yIHdoZW4gZ2l2ZW4gYW4gYWNjb3VudCBtaXNzaW5nIGl0cyBuYW1lXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICBpbnB1dFN0YXRlbWVudC5hY3Rvci5tZW1iZXIgPSBbe2FjY291bnQ6e2hvbWVQYWdlOlwiaHR0cDovL2V4YW1wbGUuY29tXCJ9fV07XG4gICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeCh4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KSwgXCJzdGF0ZW1lbnQuYWN0b3IubWVtYmVyWzBdLmFjY291bnQubmFtZVwiKSkudG8uYmUudHJ1ZTtcbiAgICAgIH0pO1xuXG4gICAgICBpdChcInRoZSBtZW1iZXIgcHJvcGVydHkncyBhZ2VudCByZXBvcnRzIGFuIGVycm9yIHdoZW4gZ2l2ZW4gYW4gYWNjb3VudCB3aXRoIGFuIGFsbC1sb3dlcmNhc2UgaG9tZXBhZ2VcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIGlucHV0U3RhdGVtZW50LmFjdG9yLm1lbWJlciA9IFt7YWNjb3VudDp7aG9tZXBhZ2U6XCJodHRwOi8vZXhhbXBsZS5jb21cIiwgbmFtZTpcImJvYlwifX1dO1xuICAgICAgICB2YXIgcmVwb3J0ID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXBvcnQsIFwic3RhdGVtZW50LmFjdG9yLm1lbWJlclswXS5hY2NvdW50LmhvbWVwYWdlXCIpKS50by5iZS50cnVlO1xuICAgICAgICBleHBlY3QocmVwb3J0LmVycm9ycylcbiAgICAgICAgICAudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAyKTtcbiAgICAgIH0pO1xuXG4gICAgICBpdChcInRoZSBtZW1iZXIgcHJvcGVydHkncyBhZ2VudCByZXBvcnRzIG5vIGVycm9yIHdoZW4gZ2l2ZW4gYSBmdWxsIGFjY291bnRcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIGlucHV0U3RhdGVtZW50LmFjdG9yLm1lbWJlciA9IFt7YWNjb3VudDp7aG9tZVBhZ2U6XCJodHRwOi8vZXhhbXBsZS5jb21cIiwgbmFtZTogXCJib2JcIn19XTtcbiAgICAgICAgZXhwZWN0KHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpLmVycm9ycylcbiAgICAgICAgICAudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAwKTtcbiAgICAgIH0pO1xuXG4gICAgICBpdChcInRoZSBtZW1iZXIgcHJvcGVydHkncyBhZ2VudCByZXBvcnRzIG5vIGVycm9yIHdoZW4gZ2l2ZW4gYSB2YWxpZCBtYm94XCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICBpbnB1dFN0YXRlbWVudC5hY3Rvci5tZW1iZXIgPSBbe21ib3g6XCJtYWlsdG86Ym9iQGV4YW1wbGUuY29tXCJ9XTtcbiAgICAgICAgZXhwZWN0KHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpLmVycm9ycylcbiAgICAgICAgICAudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAwKTtcbiAgICAgIH0pO1xuXG4gICAgICBpdChcInRoZSBtZW1iZXIgcHJvcGVydHkncyBhZ2VudCByZXBvcnRzIGFuIGVycm9yIHdoZW4gZ2l2ZW4gYW4gaW52YWxpZCBtYm94XCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICBpbnB1dFN0YXRlbWVudC5hY3Rvci5tZW1iZXIgPSBbe21ib3g6XCJTT01FVEhJTkdXUk9ORzpib2JAZXhhbXBsZS5jb21cIn1dO1xuICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQuYWN0b3IubWVtYmVyWzBdLm1ib3hcIikpLnRvLmJlLnRydWU7XG4gICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgIH0pO1xuXG4gICAgICBpdChcInRoZSBtZW1iZXIgcHJvcGVydHkgcmVwb3J0cyBhbiBlcnJvciB3aGVuIHBvcHVsYXRlZCB3aXRoIGEgR3JvdXAgb2JqZWN0IHZpYSBtZW1iZXJcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIGlucHV0U3RhdGVtZW50LmFjdG9yLm1lbWJlciA9IFt7bWJveDpcIm1haWx0bzpncm91cEBleGFtcGxlLmNvbVwiLCBtZW1iZXI6W119XTtcbiAgICAgICAgZXhwZWN0KHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpLmVycm9ycylcbiAgICAgICAgICAudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgIH0pO1xuXG4gICAgfSk7XG5cbiAgICBkZXNjcmliZShcIndoZW4gZ2l2ZW4gYSBzdGF0ZW1lbnQgd2l0aG91dCBhIHZlcmIgcHJvcGVydHlcIiwgZnVuY3Rpb24oKSB7XG4gICAgICBpdChcInJlcG9ydHMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgIGFjdG9yIDoge21lbWJlcjpbXX0sXG4gICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn19O1xuICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHRzLCBcInN0YXRlbWVudC52ZXJiXCIpKS50by5iZS50cnVlO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBkZXNjcmliZShcIndoZW4gZ2l2ZW4gYSB2ZXJiIHdpdGhvdXQgYW4gaWQgcHJvcGVydHlcIiwgZnVuY3Rpb24oKSB7XG4gICAgICBpdChcInJlcG9ydHMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgIGFjdG9yIDoge21lbWJlcjpbXX0sXG4gICAgICAgICAgdmVyYjogeyBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn19O1xuICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHRzLCBcInN0YXRlbWVudC52ZXJiLmlkXCIsIFwiTVVTVF9WSU9MQVRJT05cIikpLnRvLmJlLnRydWU7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGRlc2NyaWJlKFwid2hlbiBnaXZlbiBhIHZlcmIgd2l0aCBhIG5vbi1zdHJpbmcgaWQgcHJvcGVydHlcIiwgZnVuY3Rpb24oKSB7XG4gICAgICBpdChcInJlcG9ydHMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgIGFjdG9yIDoge21lbWJlcjpbXX0sXG4gICAgICAgICAgdmVyYjogeyBcImlkXCI6MTIuMzQsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifX07XG4gICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LnZlcmIuaWRcIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgZGVzY3JpYmUoXCJ3aGVuIGdpdmVuIGEgdmVyYiB3aXRoIGEgcmVsYXRpdmUgVVJJIGlkIHByb3BlcnR5XCIsIGZ1bmN0aW9uKCkge1xuICAgICAgaXQoXCJyZXBvcnRzIGFuIFNIT1VMRF9WSU9MQVRJT04gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgIGFjdG9yIDoge21lbWJlcjpbXX0sXG4gICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJmcmFnbWVudFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn19O1xuICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHRzLCBcInN0YXRlbWVudC52ZXJiLmlkXCIsIFwiU0hPVUxEX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgZGVzY3JpYmUoXCJ3aGVuIGdpdmVuIGEgdmVyYiB3aXRob3V0IGEgZGlzcGxheSBwcm9wZXJ0eVwiLCBmdW5jdGlvbigpIHtcbiAgICAgIGl0KFwicmVwb3J0cyBhbiBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgYWN0b3IgOiB7bWVtYmVyOltdfSxcbiAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCJ9LFxuICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9fTtcbiAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQudmVyYi5kaXNwbGF5XCIsIFwiU0hPVUxEX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgZGVzY3JpYmUoXCJ3aGVuIGdpdmVuIGEgdmVyYiB3aXRoIGFuIGVtcHR5IGRpc3BsYXkgcHJvcGVydHlcIiwgZnVuY3Rpb24oKSB7XG4gICAgICBpdChcInJlcG9ydHMgbm8gZXJyb3JzXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICBhY3RvciA6IHttZW1iZXI6W119LFxuICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgZGlzcGxheSA6IHt9fSxcbiAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifX07XG4gICAgICAgIGV4cGVjdCh4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KS5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMCk7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGRlc2NyaWJlKFwid2hlbiBnaXZlbiBhIHZlcmIuZGlzcGxheSB3aXRoIFJGQyA1NjQ2IGtleSBhbmQgc3RyaW5nIHZhbHVlXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgaXQoXCJyZXBvcnRzIG5vIGVycm9yc1wiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgYWN0b3IgOiB7bWVtYmVyOltdfSxcbiAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIGRpc3BsYXkgOiB7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn19O1xuICAgICAgICBleHBlY3QoeGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCkuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDApO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBkZXNjcmliZShcIndoZW4gZ2l2ZW4gYSB2ZXJiLmRpc3BsYXkgd2l0aCBSRkMgNTY0NiBrZXkgYW5kIG5vbi1zdHJpbmcgdmFsdWVcIiwgZnVuY3Rpb24oKSB7XG4gICAgICBpdChcInJlcG9ydHMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgIGFjdG9yIDoge21lbWJlcjpbXX0sXG4gICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBkaXNwbGF5IDoge1wiZW4tVVNcIjogMS4yM319LFxuICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9fTtcbiAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQudmVyYi5kaXNwbGF5W1xcXCJlbi1VU1xcXCJdXCIsIFwiTVVTVF9WSU9MQVRJT05cIikpLnRvLmJlLnRydWU7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGRlc2NyaWJlKFwid2hlbiBnaXZlbiBhIHZlcmIuZGlzcGxheSB3aXRoIGludmFsaWQga2V5IGFuZCBzdHJpbmcgdmFsdWVcIiwgZnVuY3Rpb24oKSB7XG4gICAgICBpdChcInJlcG9ydHMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgIGFjdG9yIDoge21lbWJlcjpbXX0sXG4gICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBkaXNwbGF5IDoge1wiMTIzdG90YWxseVdyb25nXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifX07XG4gICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LnZlcmIuZGlzcGxheS4xMjN0b3RhbGx5V3JvbmdcIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgZGVzY3JpYmUoXCJ3aGVuIHRoZSBvYmplY3QgcHJvcGVydHkgaXMgYWJzZW50XCIsIGZ1bmN0aW9uKCkge1xuICAgICAgaXQoXCJyZXBvcnRzIGEgTVVTVF9WSU9MQVRJT04gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgIGFjdG9yIDoge21lbWJlcjpbXX0sXG4gICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBkaXNwbGF5IDoge1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19fTtcbiAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQub2JqZWN0XCIsIFwiTVVTVF9WSU9MQVRJT05cIikpLnRvLmJlLnRydWU7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGRlc2NyaWJlKFwid2hlbiB0aGUgb2JqZWN0IHByb3BlcnR5IGlzIG51bGxcIiwgZnVuY3Rpb24oKSB7XG4gICAgICBpdChcInJlcG9ydHMgYSBNVVNUX1ZJT0xBVElPTiBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgYWN0b3IgOiB7bWVtYmVyOltdfSxcbiAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIGRpc3BsYXkgOiB7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgb2JqZWN0IDogbnVsbH07XG4gICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50Lm9iamVjdFwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBkZXNjcmliZShcIndoZW4gdGhlIG9iamVjdCBsYWNrcyBhbiBvYmplY3RUeXBlIHByb3BlcnR5XCIsIGZ1bmN0aW9uKCkge1xuICAgICAgaXQoXCJyZXBvcnRzIGEgU0hPVUxEX1ZJT0xBVElPTiBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgYWN0b3IgOiB7bWVtYmVyOltdfSxcbiAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIGRpc3BsYXkgOiB7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwifX07XG4gICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50Lm9iamVjdC5vYmplY3RUeXBlXCIsIFwiU0hPVUxEX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgZGVzY3JpYmUoXCJ3aGVuIHRoZSBvYmplY3QgaXMgYW4gYWN0aXZpdHkgd2l0aCBhIG51bGwgZGVmaW5pdGlvbiBwcm9wZXJ0eVwiLCBmdW5jdGlvbigpIHtcbiAgICAgIGl0KFwicmVwb3J0cyBhIE1VU1RfVklPTEFUSU9OIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICBhY3RvciA6IHttZW1iZXI6W119LFxuICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgZGlzcGxheSA6IHtcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwiLFxuICAgICAgICAgICAgZGVmaW5pdGlvbjogbnVsbH19O1xuICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHRzLCBcInN0YXRlbWVudC5vYmplY3QuZGVmaW5pdGlvblwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBkZXNjcmliZShcIndoZW4gdGhlIG9iamVjdCBpcyBhbiBhY3Rpdml0eSB3aXRoIGFuIGFycmF5IGRlZmluaXRpb24gcHJvcGVydHlcIiwgZnVuY3Rpb24oKSB7XG4gICAgICBpdChcInJlcG9ydHMgYSBNVVNUX1ZJT0xBVElPTiBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgYWN0b3IgOiB7bWVtYmVyOltdfSxcbiAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIGRpc3BsYXkgOiB7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIixcbiAgICAgICAgICAgIGRlZmluaXRpb246IFtdfX07XG4gICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50Lm9iamVjdC5kZWZpbml0aW9uXCIsIFwiTVVTVF9WSU9MQVRJT05cIikpLnRvLmJlLnRydWU7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGRlc2NyaWJlKFwid2hlbiB0aGUgb2JqZWN0IGlzIGFuIEFjdGl2aXR5IHdpdGggYSBkZWZpbml0aW9uXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgaXQoXCJhbiBhcnJheSBmb3IgdGhlIG5hbWUgcHJvcGVydHkgcHJvZHVjZXMgYSBtdXN0IHZpb2xhdGlvbiBlcnJvci5cIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgIGFjdG9yIDoge21lbWJlcjpbXX0sXG4gICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBkaXNwbGF5IDoge1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCIsXG4gICAgICAgICAgICBkZWZpbml0aW9uOntuYW1lOltdfX19O1xuICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHRzLCBcInN0YXRlbWVudC5vYmplY3QuZGVmaW5pdGlvbi5uYW1lXCIsIFwiTVVTVF9WSU9MQVRJT05cIikpLnRvLmJlLnRydWU7XG4gICAgICB9KTtcblxuICAgICAgaXQoXCJhIG51bWJlciBmb3IgdGhlIG5hbWUgcHJvcGVydHkgcHJvZHVjZXMgYSBtdXN0IHZpb2xhdGlvbiBlcnJvci5cIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgIGFjdG9yIDoge21lbWJlcjpbXX0sXG4gICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBkaXNwbGF5IDoge1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCIsXG4gICAgICAgICAgICBkZWZpbml0aW9uOntuYW1lOjEuMjN9fX07XG4gICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50Lm9iamVjdC5kZWZpbml0aW9uLm5hbWVcIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgIH0pO1xuXG4gICAgICBpdChcImFuIGludmFsaWQgbGFuZ3VhZ2UgTWFwIGtleSBmb3IgdGhlIG5hbWUgcHJvcGVydHkgcHJvZHVjZXMgYSBtdXN0IHZpb2xhdGlvbiBlcnJvci5cIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgIGFjdG9yIDoge21lbWJlcjpbXX0sXG4gICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBkaXNwbGF5IDoge1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCIsXG4gICAgICAgICAgICBkZWZpbml0aW9uOntuYW1lOntcIjEyMyB0b3RhbGx5IG5vdCBhIGxhbmd1YWdlIGNvZGVcIiA6IFwiY3JlYXRlZFwifX19fTtcbiAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQub2JqZWN0LmRlZmluaXRpb24ubmFtZVwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KFwiYSBDTUkgaW50ZXJhY3Rpb25UeXBlIHZhbHVlIHByb2R1Y2VzIG5vIGVycm9yc1wiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgYWN0b3IgOiB7bWVtYmVyOltdfSxcbiAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIGRpc3BsYXkgOiB7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIixcbiAgICAgICAgICAgIGRlZmluaXRpb246e3R5cGU6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvYWN0aXZpdGllcy9jbWkuaW50ZXJhY3Rpb25cIiwgaW50ZXJhY3Rpb25UeXBlOlwidHJ1ZS1mYWxzZVwifX19O1xuICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMCk7XG4gICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHRzLCBcInN0YXRlbWVudC5vYmplY3QuZGVmaW5pdGlvbi5uYW1lXCIsIFwiTVVTVF9WSU9MQVRJT05cIikpLnRvLmJlLmZhbHNlO1xuICAgICAgfSk7XG5cblxuXG4gICAgICBpdChcImEgbm9uLUNNSSBpbnRlcmFjdGlvblR5cGUgdmFsdWUgcHJvZHVjZXMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgIGFjdG9yIDoge21lbWJlcjpbXX0sXG4gICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBkaXNwbGF5IDoge1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCIsXG4gICAgICAgICAgICBkZWZpbml0aW9uOnt0eXBlOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL2FjdGl2aXRpZXMvY21pLmludGVyYWN0aW9uXCIsIGludGVyYWN0aW9uVHlwZTpcImdyYXBoaWNHYXBNYXRjaEludGVyYWN0aW9uXCJ9fX07XG4gICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50Lm9iamVjdC5kZWZpbml0aW9uLmludGVyYWN0aW9uVHlwZVwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KFwiYSBudW1lcmljIGNvcnJlY3RSZXNwb25zZXNQYXR0ZXJuIHZhbHVlIHByb2R1Y2VzIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICBhY3RvciA6IHttZW1iZXI6W119LFxuICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgZGlzcGxheSA6IHtcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwiLFxuICAgICAgICAgICAgZGVmaW5pdGlvbjp7Y29ycmVjdFJlc3BvbnNlc1BhdHRlcm46IDEuMjN9fX07XG4gICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50Lm9iamVjdC5kZWZpbml0aW9uLmNvcnJlY3RSZXNwb25zZXNQYXR0ZXJuXCIsIFwiTVVTVF9WSU9MQVRJT05cIikpLnRvLmJlLnRydWU7XG4gICAgICB9KTtcblxuICAgICAgaXQoXCJhIGZsYXQgc3RyaW5nIGNvcnJlY3RSZXNwb25zZXNQYXR0ZXJuIHZhbHVlIHByb2R1Y2VzIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICBhY3RvciA6IHttZW1iZXI6W119LFxuICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgZGlzcGxheSA6IHtcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwiLFxuICAgICAgICAgICAgZGVmaW5pdGlvbjp7Y29ycmVjdFJlc3BvbnNlc1BhdHRlcm46IFwiMS4yM1wifX19O1xuICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHRzLCBcInN0YXRlbWVudC5vYmplY3QuZGVmaW5pdGlvbi5jb3JyZWN0UmVzcG9uc2VzUGF0dGVyblwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KFwiYSBuZXN0ZWQgbnVtYmVyIGluIGEgY29ycmVjdFJlc3BvbnNlc1BhdHRlcm4gQXJyYXkgdmFsdWUgcHJvZHVjZXMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgIGFjdG9yIDoge21lbWJlcjpbXX0sXG4gICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBkaXNwbGF5IDoge1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCIsXG4gICAgICAgICAgICBkZWZpbml0aW9uOntjb3JyZWN0UmVzcG9uc2VzUGF0dGVybjogWzEuMjNdfX19O1xuICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHRzLCBcInN0YXRlbWVudC5vYmplY3QuZGVmaW5pdGlvbi5jb3JyZWN0UmVzcG9uc2VzUGF0dGVyblswXVwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KFwiYSBuZXN0ZWQgc3RyaW5nIGluIGEgY29ycmVjdFJlc3BvbnNlc1BhdHRlcm4gQXJyYXkgdmFsdWUgcHJvZHVjZXMgbm8gZXJyb3JzXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICBhY3RvciA6IHttZW1iZXI6W119LFxuICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgZGlzcGxheSA6IHtcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwiLFxuICAgICAgICAgICAgZGVmaW5pdGlvbjp7Y29ycmVjdFJlc3BvbnNlc1BhdHRlcm46IFtcIjEuMjNcIl19fX07XG4gICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAwKTtcbiAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50Lm9iamVjdC5kZWZpbml0aW9uLmNvcnJlY3RSZXNwb25zZXNQYXR0ZXJuXCIsIFwiTVVTVF9WSU9MQVRJT05cIikpLnRvLmJlLmZhbHNlO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KFwiYW4gaW50ZXJhY3Rpb24gYWN0aXZpdHkgd2l0aG91dCB0aGUgc3RhbmRhcmQgXFxcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS9hY3Rpdml0aWVzL2NtaS5pbnRlcmFjdGlvblxcXCIgdmFsdWUgZm9yIHRoZSB0eXBlIHByb3BlcnR5IHNob3VsZCBwcm9kdWNlIGEgU0hPVUxEIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICBhY3RvciA6IHttZW1iZXI6W119LFxuICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgZGlzcGxheSA6IHtcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwiLFxuICAgICAgICAgICAgZGVmaW5pdGlvbjp7dHlwZTpcImh0dHA6Ly9leGFtcGxlLmNvbS9zb21ldGhpbmdFbHNlXCIsIGludGVyYWN0aW9uVHlwZTpcImNob2ljZVwiLCBjaG9pY2VzOltdfX1cbiAgICAgICAgfTtcbiAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQub2JqZWN0LmRlZmluaXRpb24udHlwZVwiLCBcIlNIT1VMRF9WSU9MQVRJT05cIikpLnRvLmJlLnRydWU7XG4gICAgICB9KTtcblxuICAgICAgaXQoXCJhbiBpbnRlcmFjdGlvbiBjb21wb25lbnQgYXJyYXkgcHJvcGVydHkgbm90IGFzc29jaWF0ZWQgd2l0aCB0aGUgY3VycmVudCBpbnRlcmFjdGlvblR5cGUgcHJvZHVjZXMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgIGFjdG9yIDoge21lbWJlcjpbXX0sXG4gICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBkaXNwbGF5IDoge1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCIsXG4gICAgICAgICAgICBkZWZpbml0aW9uOnt0eXBlOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL2FjdGl2aXRpZXMvY21pLmludGVyYWN0aW9uXCIsIGludGVyYWN0aW9uVHlwZTpcImNob2ljZVwiLCBzdGVwczpbXX19XG4gICAgICAgIH07XG4gICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50Lm9iamVjdC5kZWZpbml0aW9uLnN0ZXBzXCIsIFwiU0hPVUxEX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgIH0pO1xuXG4gICAgICBpdChcImFuIGludGVyYWN0aW9uIGNvbXBvbmVudCB3aXRoIHdoaXRlc3BhY2UgaW4gdGhlIGlkIHByb3BlcnR5IHByb2R1Y2VzIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICBhY3RvciA6IHttZW1iZXI6W119LFxuICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgZGlzcGxheSA6IHtcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwiLFxuICAgICAgICAgICAgZGVmaW5pdGlvbjp7dHlwZTpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS9hY3Rpdml0aWVzL2NtaS5pbnRlcmFjdGlvblwiLCBpbnRlcmFjdGlvblR5cGU6XCJjaG9pY2VcIixcbiAgICAgICAgICAgICAgICBjaG9pY2VzOlt7aWQ6XCJoZWxsbyBpbnZhbGlkIGlkXCIsIGRlc2NyaXB0aW9uOnt9fV19fVxuICAgICAgICB9O1xuICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHRzLCBcInN0YXRlbWVudC5vYmplY3QuZGVmaW5pdGlvbi5jaG9pY2VzWzBdXCIsIFwiU0hPVUxEX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgIH0pO1xuXG4gICAgICBpdChcImFuIGludGVyYWN0aW9uIGNvbXBvbmVudCB3aXRoIHJlcGVhdGVkIG5vbi11bmlxdWUgaWQgcHJvZHVjZXMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgIGFjdG9yIDoge21lbWJlcjpbXX0sXG4gICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBkaXNwbGF5IDoge1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCIsXG4gICAgICAgICAgICBkZWZpbml0aW9uOnt0eXBlOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL2FjdGl2aXRpZXMvY21pLmludGVyYWN0aW9uXCIsIGludGVyYWN0aW9uVHlwZTpcImNob2ljZVwiLFxuICAgICAgICAgICAgICAgIGNob2ljZXM6W3tpZDpcImlkQVwiLCBkZXNjcmlwdGlvbjp7fX0sIHtpZDpcImlkQVwiLCBkZXNjcmlwdGlvbjp7fX1dfX1cbiAgICAgICAgfTtcbiAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQub2JqZWN0LmRlZmluaXRpb24uY2hvaWNlc1sxXVwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgfSk7XG5cbiAgICAgIGRlc2NyaWJlKFwiZ2l2ZW4gYSBzdGF0ZW1lbnQgcmVmZXJlbmNlIHR5cGUgb2JqZWN0XCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICBpdChcInJlcG9ydHMgYSBNVVNUIGVycm9yIHdoZW4gdGhlIGlkIHByb3BlcnR5IGlzIG1pc3NpbmdcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtvYmplY3RUeXBlOlwiU3RhdGVtZW50UmVmXCJ9fTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQub2JqZWN0LmlkXCIsIFwiTVVTVF9WSU9MQVRJT05cIikpLnRvLmJlLnRydWU7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KFwicmVwb3J0cyBhIE1VU1QgZXJyb3Igd2hlbiB0aGUgaWQgcHJvcGVydHkgaXMgbm90IGEgVVVJRFwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkOiBcIm5vdCBhIFVVSURcIiwgb2JqZWN0VHlwZTpcIlN0YXRlbWVudFJlZlwifX07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50Lm9iamVjdC5pZFwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuXG4gICAgICBkZXNjcmliZShcImdpdmVuIGEgc3Vic3RhdGVtZW50IHR5cGUgb2JqZWN0XCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgIGl0KFwic2hvdWxkIG5vdCByZXBvcnQgYW4gZXJyb3Igd2hlbiB2YWxpZFwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIixcbiAgICAgICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgICAgIG9iamVjdCA6IHsgb2JqZWN0VHlwZTpcIlN1YlN0YXRlbWVudFwiLFxuICAgICAgICAgICAgICAgICAgICAgIGFjdG9yIDogeyBtYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgICAgICAgIG9iamVjdDogeyBpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9fX07XG4gICAgICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcblxuICAgICAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAwKTtcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIGl0KFwicmVwb3J0cyBhIE1VU1QgZXJyb3Igd2hlbiB0aGUgaWQgcHJvcGVydHkgaXMgcHJlc2VudFwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIixcbiAgICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICAgIG9iamVjdCA6IHsgaWQ6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWExXCIsXG4gICAgICAgICAgICAgICAgICAgIG9iamVjdFR5cGU6XCJTdWJTdGF0ZW1lbnRcIixcbiAgICAgICAgICAgICAgICAgICAgYWN0b3IgOiB7IG1ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgICAgICBvYmplY3Q6IHsgaWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifX19O1xuICAgICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuXG4gICAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50Lm9iamVjdC5pZFwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgaXQoXCJyZXBvcnRzIGEgTVVTVCBlcnJvciB3aGVuIHRoZSB2ZXJzaW9uIHByb3BlcnR5IGlzIHByZXNlbnRcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIsXG4gICAgICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgICAgICBvYmplY3QgOiB7IHZlcnNpb246IFwiMS4wLjBcIixcbiAgICAgICAgICAgICAgICAgICAgICBvYmplY3RUeXBlOlwiU3ViU3RhdGVtZW50XCIsXG4gICAgICAgICAgICAgICAgICAgICAgYWN0b3IgOiB7IG1ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgICAgICAgb2JqZWN0OiB7IGlkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn19fTtcbiAgICAgICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuXG4gICAgICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHRzLCBcInN0YXRlbWVudC5vYmplY3QudmVyc2lvblwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgaXQoXCJyZXBvcnRzIGEgTVVTVCBlcnJvciB3aGVuIHRoZSBzdG9yZWQgcHJvcGVydHkgaXMgcHJlc2VudFwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiLFxuICAgICAgICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgICAgICAgb2JqZWN0IDogeyBzdG9yZWQ6IFwiMjAxMy0wNS0yOFQwNzoxMjo1Ny4yNDVaXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBvYmplY3RUeXBlOlwiU3ViU3RhdGVtZW50XCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBhY3RvciA6IHsgbWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgICAgICAgICAgb2JqZWN0OiB7IGlkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn19fTtcbiAgICAgICAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG5cbiAgICAgICAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgICAgICAgICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHRzLCBcInN0YXRlbWVudC5vYmplY3Quc3RvcmVkXCIsIFwiTVVTVF9WSU9MQVRJT05cIikpLnRvLmJlLnRydWU7XG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgICBpdChcInJlcG9ydHMgYSBNVVNUIGVycm9yIHdoZW4gdGhlIGF1dGhvcml0eSBwcm9wZXJ0eSBpcyBwcmVzZW50XCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIsXG4gICAgICAgICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICAgICAgICBvYmplY3QgOiB7IGF1dGhvcml0eTogeyBtYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCIgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9iamVjdFR5cGU6XCJTdWJTdGF0ZW1lbnRcIixcbiAgICAgICAgICAgICAgICAgICAgICAgIGFjdG9yIDogeyBtYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgICAgICAgICBvYmplY3Q6IHsgaWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifX19O1xuICAgICAgICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcblxuICAgICAgICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50Lm9iamVjdC5hdXRob3JpdHlcIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgICB9KTtcbiAgICAgIH0pO1xuXG4gICAgICBkZXNjcmliZShcImdpdmVuIGEgbm9uLU9iamVjdCByZXN1bHRzIHByb3BlcnR5XCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICBpdChcImlmIG51bGwsIHByb2R1Y2VzIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICByZXN1bHQgOiBudWxsfTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQucmVzdWx0XCIsIFwiTVVTVF9WSU9MQVRJT05cIikpLnRvLmJlLnRydWU7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KFwiaWYgYW4gQXJyYXksIHByb2R1Y2VzIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICByZXN1bHQgOiBbXX07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LnJlc3VsdFwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImlmIGFuIG51bWJlciwgcHJvZHVjZXMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIHJlc3VsdCA6IDEuMjN9O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHRzLCBcInN0YXRlbWVudC5yZXN1bHRcIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcblxuICAgICAgZGVzY3JpYmUoXCJnaXZlbiBhIHJlc3VsdHMgcHJvcGVydHkgdGhhdCBpcyBhbiBvYmplY3RcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIGl0KFwiaWYgZW1wdHksIGFsbCBpcyBva2F5LCBubyBwcm9wZXJ0aWVzIHdlcmUgcmVxdWlyZWRcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIHJlc3VsdCA6IHt9fTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KFwiYSBub24tQm9vbGVhbiBzdWNjZXNzIHByb3BlcnR5IHByb2R1Y2VzIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICByZXN1bHQgOiB7c3VjY2VzczoxMjN9fTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQucmVzdWx0LnN1Y2Nlc3NcIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhIEJvb2xlYW4gc3VjY2VzcyBwcm9wZXJ0eSBwcm9kdWNlcyBubyBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgcmVzdWx0IDoge3N1Y2Nlc3M6ZmFsc2V9fTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KFwiYSBub24tQm9vbGVhbiBjb21wbGV0aW9uIHByb3BlcnR5IHByb2R1Y2VzIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICByZXN1bHQgOiB7Y29tcGxldGlvbjoxMjN9fTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQucmVzdWx0LmNvbXBsZXRpb25cIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhIEJvb2xlYW4gY29tcGxldGlvbiBwcm9wZXJ0eSBwcm9kdWNlcyBubyBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgcmVzdWx0IDoge2NvbXBsZXRpb246ZmFsc2V9fTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMCk7XG5cbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhIG5vbi1TdHJpbmcgcmVzcG9uc2UgcHJvcGVydHkgcHJvZHVjZXMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIHJlc3VsdCA6IHtyZXNwb25zZToxMjN9fTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQucmVzdWx0LnJlc3BvbnNlXCIsIFwiTVVTVF9WSU9MQVRJT05cIikpLnRvLmJlLnRydWU7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KFwiYSBTdHJpbmcgcmVzcG9uc2UgcHJvcGVydHkgcHJvZHVjZXMgbm8gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIHJlc3VsdCA6IHtyZXNwb25zZTpcImlkQVwifX07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDApO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImEgbm9uLVN0cmluZyBkdXJhdGlvbiBwcm9wZXJ0eSBwcm9kdWNlcyBhbiBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgcmVzdWx0IDoge2R1cmF0aW9uOjEyM319O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHRzLCBcInN0YXRlbWVudC5yZXN1bHQuZHVyYXRpb25cIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhIG5vbi1JU08gODYwMSBkdXJhdGlvbiBTdHJpbmcgZHVyYXRpb24gcHJvcGVydHkgcHJvZHVjZXMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIHJlc3VsdCA6IHtkdXJhdGlvbjpcIm5vdCBhbiBJU08gY29tcGxpYW50IGR1cmF0aW9uXCJ9fTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQucmVzdWx0LmR1cmF0aW9uXCIsIFwiTVVTVF9WSU9MQVRJT05cIikpLnRvLmJlLnRydWU7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KFwiYW4gSVNPIDg2MDEgZHVyYXRpb24gU3RyaW5nIHJlc3BvbnNlIHByb3BlcnR5IHByb2R1Y2VzIG5vIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICByZXN1bHQgOiB7ZHVyYXRpb246XCJQM1k2TTREVDEySDMwTTVTXCJ9fTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KFwiYW4gSVNPIDg2MDEgZHVyYXRpb24gU3RyaW5nIHJlc3BvbnNlIHByb3BlcnR5IHdpdGggZnJhY3Rpb25hbCBzZWNvbmRzIHByb2R1Y2VzIG5vIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICByZXN1bHQgOiB7ZHVyYXRpb246XCJQM1k2TTREVDEySDMwTTUuMDFTXCJ9fTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMCk7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIGRlc2NyaWJlKFwiZ2l2ZW4gYSBzY29yZSBwcm9wZXJ0eSBvbiB0aGUgcmVzdWx0c1wiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgaXQoXCJhIG5vbi1OdW1iZXIgcmF3IHByb3BlcnR5IHByb2R1Y2VzIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICByZXN1bHQgOiB7c2NvcmU6e3JhdzpcIjEyM1wifX19O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHRzLCBcInN0YXRlbWVudC5yZXN1bHQuc2NvcmUucmF3XCIsIFwiTVVTVF9WSU9MQVRJT05cIikpLnRvLmJlLnRydWU7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KFwiYSBOdW1iZXIgcmF3IHByb3BlcnR5IHByb2R1Y2VzIG5vIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICByZXN1bHQgOiB7c2NvcmU6e3JhdzoxMjN9fX07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDApO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImEgTnVtYmVyIHJhdyBwcm9wZXJ0eSBiZWxvdyBtaW4gcHJvZHVjZXMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIHJlc3VsdCA6IHtzY29yZTp7cmF3OjEyMywgbWluOjIwMH19fTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQucmVzdWx0LnNjb3JlLnJhd1wiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImEgTnVtYmVyIHJhdyBwcm9wZXJ0eSBhYm92ZSBtYXggcHJvZHVjZXMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIHJlc3VsdCA6IHtzY29yZTp7cmF3OjEyMywgbWF4OjEwMH19fTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQucmVzdWx0LnNjb3JlLnJhd1wiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImEgTnVtYmVyIHJhdyBwcm9wZXJ0eSBiZXR3ZWVuIG1pbiBhbmQgbWF4IHByb2R1Y2VzIG5vIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICByZXN1bHQgOiB7c2NvcmU6e3JhdzoxMjMsIG1pbjoxMjAsIG1heDoxMjV9fX07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDApO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImEgbm9uLU51bWJlciBzY2FsZWQgcHJvcGVydHkgcHJvZHVjZXMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIHJlc3VsdCA6IHtzY29yZTp7c2NhbGVkOlwiMC41XCJ9fX07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LnJlc3VsdC5zY29yZS5zY2FsZWRcIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhIE51bWJlciBzY2FsZWQgcHJvcGVydHkgcHJvZHVjZXMgbm8gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIHJlc3VsdCA6IHtzY29yZTp7c2NhbGVkOjAuNX19fTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KFwiYSBOdW1iZXIgc2NhbGVkIHByb3BlcnR5IGJlbG93IDAgcHJvZHVjZXMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIHJlc3VsdCA6IHtzY29yZTp7c2NhbGVkOi0wLjV9fX07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LnJlc3VsdC5zY29yZS5zY2FsZWRcIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhIE51bWJlciBzY2FsZWQgcHJvcGVydHkgYWJvdmUgMSBwcm9kdWNlcyBhbiBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgcmVzdWx0IDoge3Njb3JlOntzY2FsZWQ6Mn19fTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQucmVzdWx0LnNjb3JlLnNjYWxlZFwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImEgbm9uLU51bWJlciBtYXggcHJvcGVydHkgcHJvZHVjZXMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIHJlc3VsdCA6IHtzY29yZTp7bWF4OlwiMTIzXCJ9fX07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LnJlc3VsdC5zY29yZS5tYXhcIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhIE51bWJlciBtYXggcHJvcGVydHkgcHJvZHVjZXMgbm8gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIHJlc3VsdCA6IHtzY29yZTp7bWF4OjEyM319fTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KFwiYSBOdW1iZXIgbWF4IHByb3BlcnR5IGJlbG93IG1pbiBwcm9kdWNlcyBhbiBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgcmVzdWx0IDoge3Njb3JlOnttYXg6MTIzLCBtaW46MjAwfX19O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHRzLCBcInN0YXRlbWVudC5yZXN1bHQuc2NvcmUubWF4XCIsIFwiTVVTVF9WSU9MQVRJT05cIikpLnRvLmJlLnRydWU7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KFwiYSBub24tTnVtYmVyIG1pbiBwcm9wZXJ0eSBwcm9kdWNlcyBhbiBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgcmVzdWx0IDoge3Njb3JlOnttaW46XCIxMjNcIn19fTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQucmVzdWx0LnNjb3JlLm1pblwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImEgTnVtYmVyIG1pbiBwcm9wZXJ0eSBwcm9kdWNlcyBubyBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgcmVzdWx0IDoge3Njb3JlOnttaW46MTIzfX19O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAwKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhIE51bWJlciBtaW4gcHJvcGVydHkgYWJvdmUgbWF4IHByb2R1Y2VzIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICByZXN1bHQgOiB7c2NvcmU6e21heDoxMjMsIG1pbjoyMDB9fX07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LnJlc3VsdC5zY29yZS5tYXhcIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcblxuICAgICAgZGVzY3JpYmUoXCJmb3IgYSBnaXZlbiBkZWZpbmVkIGNvbnRleHQgcHJvcGVydHlcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIGl0KFwiYW4gZW1wdHkgb2JqZWN0IHByb2R1Y2VzIG5vIGVycm9yc1wiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgY29udGV4dDoge319O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAwKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhbiBub24tb2JqZWN0IGNvbnRleHQgdmFsdWUgcHJvZHVjZXMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIGNvbnRleHQ6IDEyM307XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LmNvbnRleHRcIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhbiBhcnJheSBjb250ZXh0IHZhbHVlIHByb2R1Y2VzIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICBjb250ZXh0OiBbXX07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LmNvbnRleHRcIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhIG5vbi1VVUlEIHJlZ2lzdHJhdGlvbiB2YWx1ZSBwcm9kdWNlcyBhbiBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgY29udGV4dDoge3JlZ2lzdHJhdGlvbjpcIm5vdCBhIFVVSURcIn19O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHRzLCBcInN0YXRlbWVudC5jb250ZXh0LnJlZ2lzdHJhdGlvblwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImEgVVVJRCByZWdpc3RyYXRpb24gdmFsdWUgcHJvZHVjZXMgbm8gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIGNvbnRleHQ6IHtyZWdpc3RyYXRpb246XCJlZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIn19O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAwKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhbiBlbXB0eSBtYXAgZm9yIGFuIGluc3RydWN0b3IgdmFsdWUgcHJvZHVjZXMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIGNvbnRleHQ6IHtpbnN0cnVjdG9yOnt9fX07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LmNvbnRleHQuaW5zdHJ1Y3RvclwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImFuIHVuaWRlbnRpZmllZCBBZ2VudCBmb3IgYW4gaW5zdHJ1Y3RvciB2YWx1ZSBwcm9kdWNlcyBhbiBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgY29udGV4dDoge2luc3RydWN0b3I6e29iamVjdFR5cGU6XCJBZ2VudFwifX19O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHRzLCBcInN0YXRlbWVudC5jb250ZXh0Lmluc3RydWN0b3JcIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhbiB1bmlkZW50aWZpZWQgR3JvdXAgd2l0aCBubyBtZW1iZXIgcHJvcGVydHkgZm9yIGFuIGluc3RydWN0b3IgdmFsdWUgcHJvZHVjZXMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIGNvbnRleHQ6IHtpbnN0cnVjdG9yOntvYmplY3RUeXBlOlwiR3JvdXBcIn19fTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQuY29udGV4dC5pbnN0cnVjdG9yXCIsIFwiTVVTVF9WSU9MQVRJT05cIikpLnRvLmJlLnRydWU7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KFwiYW4gQWdlbnQgaW5zdHJ1Y3RvciB2YWx1ZSBwcm9kdWNlcyBubyBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgY29udGV4dDoge2luc3RydWN0b3I6e21ib3g6XCJtYWlsdG86Ym9iQGV4YW1wbGUuY29tXCJ9fX07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDApO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImEgR3JvdXAgaW5zdHJ1Y3RvciBpZGVudGlmaWVkIGJ5IG1lbWJlciBwcm9wZXJ0eSBwcm9kdWNlcyBubyBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgY29udGV4dDoge2luc3RydWN0b3I6e21ib3g6XCJtYWlsdG86Ym9iQGV4YW1wbGUuY29tXCIsIG1lbWJlcjpbXX19fTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KFwiYSBHcm91cCBpbnN0cnVjdG9yIGlkZW50aWZpZWQgYnkgb2JqZWN0VHlwZSBwcm9wZXJ0eSBwcm9kdWNlcyBubyBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgY29udGV4dDoge2luc3RydWN0b3I6e21ib3g6XCJtYWlsdG86Ym9iQGV4YW1wbGUuY29tXCIsIG9iamVjdFR5cGU6XCJHcm91cFwifX19O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAwKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJpZiB0aGUgc3RhdGVtZW50J3Mgb2JqZWN0IGlzIGFuIEFnZW50LCB0aGUgcHJlc2VuY2Ugb2YgdGhlIHJldmlzaW9uIHByb3BlcnR5IHdpbGwgcmVzdWx0IGluIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7bWJveCA6IFwibWFpbHRvOmJvYkBleGFtcGxlLmNvbVwiLCBvYmplY3RUeXBlOlwiQWdlbnRcIn0sXG4gICAgICAgICAgICAgICAgY29udGV4dDoge3JldmlzaW9uOlwiMS4wXCJ9fTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQuY29udGV4dC5yZXZpc2lvblwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImlmIHRoZSBzdGF0ZW1lbnQncyBvYmplY3QgaXMgYW4gR3JvdXAsIHRoZSBwcmVzZW5jZSBvZiB0aGUgcmV2aXNpb24gcHJvcGVydHkgd2lsbCByZXN1bHQgaW4gYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHttYm94IDogXCJtYWlsdG86Z3JvdXBAZXhhbXBsZS5jb21cIiwgb2JqZWN0VHlwZTpcIkdyb3VwXCJ9LFxuICAgICAgICAgICAgICAgIGNvbnRleHQ6IHtyZXZpc2lvbjpcIjEuMFwifX07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LmNvbnRleHQucmV2aXNpb25cIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhIFN0cmluZyByZXZpc2lvbiBwcm9wZXJ0eSBwcm9kdWNlcyBubyBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgY29udGV4dDoge3JldmlzaW9uOlwiMS4wXCJ9fTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KFwiYSBub24tU3RyaW5nIG51bWVyaWMgcmV2aXNpb24gcHJvcGVydHkgd2lsbCByZXN1bHQgaW4gYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIGNvbnRleHQ6IHtyZXZpc2lvbjoxLjB9fTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQuY29udGV4dC5yZXZpc2lvblwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImEgbnVsbCByZXZpc2lvbiBwcm9wZXJ0eSB3aWxsIHJlc3VsdCBpbiBhbiBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgY29udGV4dDoge3JldmlzaW9uOm51bGx9fTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQuY29udGV4dC5yZXZpc2lvblwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgICB9KTtcblxuICAgICAgICAvLy9cbiAgICAgICAgaXQoXCJpZiB0aGUgc3RhdGVtZW50J3Mgb2JqZWN0IGlzIGFuIEFnZW50LCB0aGUgcHJlc2VuY2Ugb2YgdGhlIHBsYXRmb3JtIHByb3BlcnR5IHdpbGwgcmVzdWx0IGluIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7bWJveCA6IFwibWFpbHRvOmJvYkBleGFtcGxlLmNvbVwiLCBvYmplY3RUeXBlOlwiQWdlbnRcIn0sXG4gICAgICAgICAgICAgICAgY29udGV4dDoge3BsYXRmb3JtOlwiMS4wXCJ9fTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQuY29udGV4dC5wbGF0Zm9ybVwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImlmIHRoZSBzdGF0ZW1lbnQncyBvYmplY3QgaXMgYW4gR3JvdXAsIHRoZSBwcmVzZW5jZSBvZiB0aGUgcGxhdGZvcm0gcHJvcGVydHkgd2lsbCByZXN1bHQgaW4gYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHttYm94IDogXCJtYWlsdG86Z3JvdXBAZXhhbXBsZS5jb21cIiwgb2JqZWN0VHlwZTpcIkdyb3VwXCJ9LFxuICAgICAgICAgICAgICAgIGNvbnRleHQ6IHtwbGF0Zm9ybTpcIjEuMFwifX07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LmNvbnRleHQucGxhdGZvcm1cIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhIFN0cmluZyBwbGF0Zm9ybSBwcm9wZXJ0eSBwcm9kdWNlcyBubyBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgY29udGV4dDoge3BsYXRmb3JtOlwiMS4wXCJ9fTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KFwiYSBub24tU3RyaW5nIG51bWVyaWMgcGxhdGZvcm0gcHJvcGVydHkgd2lsbCByZXN1bHQgaW4gYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIGNvbnRleHQ6IHtwbGF0Zm9ybToxLjB9fTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQuY29udGV4dC5wbGF0Zm9ybVwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImEgbnVsbCBwbGF0Zm9ybSBwcm9wZXJ0eSB3aWxsIHJlc3VsdCBpbiBhbiBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgY29udGV4dDoge3BsYXRmb3JtOm51bGx9fTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQuY29udGV4dC5wbGF0Zm9ybVwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImEgbnVsbCB0ZWFtIHByb3BlcnR5IHdpbGwgcmVzdWx0IGluIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICBjb250ZXh0OiB7dGVhbTpudWxsfX07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LmNvbnRleHQudGVhbVwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImEgR3JvdXAgb2JqZWN0IHRlYW0gcHJvcGVydHkgd2lsbCByZXN1bHQgaW4gbm8gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIGNvbnRleHQ6IHt0ZWFtOntvYmplY3RUeXBlOlwiR3JvdXBcIiwgbWJveDpcIm1haWx0bzpncm91cEBleGFtcGxlLmNvbVwifX19O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAwKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhIFJGQyA1NjQ2IHN0cmluZyB2YWx1ZSBmb3IgdGhlIGxhbmd1YWdlIHByb3BlcnR5IHdpbGwgcmVzdWx0IGluIG5vIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICBjb250ZXh0OiB7bGFuZ3VhZ2U6XCJlbi1VU1wifX07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDApO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImEgbm9uLVJGQyA1NjQ2IHN0cmluZyB2YWx1ZSBmb3IgdGhlIGxhbmd1YWdlIHByb3BlcnR5IHdpbGwgcmVzdWx0IGluIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICBjb250ZXh0OiB7bGFuZ3VhZ2U6XCIxMjMgdG90YWxseSBub3QgUkZDIGNvbXBsaWFudFwifX07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LmNvbnRleHQubGFuZ3VhZ2VcIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhIG51bGwgdmFsdWUgZm9yIHRoZSBsYW5ndWFnZSBwcm9wZXJ0eSB3aWxsIHJlc3VsdCBpbiBhbiBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgY29udGV4dDoge2xhbmd1YWdlOm51bGx9fTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQuY29udGV4dC5sYW5ndWFnZVwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImEgbm9uLVN0cmluZyB2YWx1ZSBmb3IgdGhlIGxhbmd1YWdlIHByb3BlcnR5IHdpbGwgcmVzdWx0IGluIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICBjb250ZXh0OiB7bGFuZ3VhZ2U6MX19O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHRzLCBcInN0YXRlbWVudC5jb250ZXh0Lmxhbmd1YWdlXCIsIFwiTVVTVF9WSU9MQVRJT05cIikpLnRvLmJlLnRydWU7XG4gICAgICAgIH0pO1xuXG5cbiAgICAgICAgaXQoXCJhIG51bGwgdmFsdWUgZm9yIHRoZSBjb250ZXh0J3Mgc3RhdGVtZW50IHByb3BlcnR5IHdpbGwgcmVzdWx0IGluIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICBjb250ZXh0OiB7c3RhdGVtZW50Om51bGx9fTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQuY29udGV4dC5zdGF0ZW1lbnRcIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhbiBBcnJheSB2YWx1ZSBmb3IgdGhlIGNvbnRleHQncyBzdGF0ZW1lbnQgcHJvcGVydHkgd2lsbCByZXN1bHQgaW4gYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIGNvbnRleHQ6IHtzdGF0ZW1lbnQ6W119fTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQuY29udGV4dC5zdGF0ZW1lbnRcIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhbiBlbXB0eSBvYmplY3QgdmFsdWUgZm9yIHRoZSBjb250ZXh0J3Mgc3RhdGVtZW50IHByb3BlcnR5IHdpbGwgcmVzdWx0IGluIGVycm9yc1wiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgY29udGV4dDoge3N0YXRlbWVudDp7fX19O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAyKTtcbiAgICAgICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHRzLCBcInN0YXRlbWVudC5jb250ZXh0LnN0YXRlbWVudC5vYmplY3RUeXBlXCIsIFwiTVVTVF9WSU9MQVRJT05cIikpLnRvLmJlLnRydWU7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQuY29udGV4dC5zdGF0ZW1lbnQuaWRcIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhIHZhbGlkIHN0YXRlbWVudCByZWZlcmVuY2UgZm9yIHRoZSBjb250ZXh0J3Mgc3RhdGVtZW50IHByb3BlcnR5IHdpbGwgcmVzdWx0IGluIG5vIGVycm9yc1wiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgY29udGV4dDoge3N0YXRlbWVudDp7b2JqZWN0VHlwZTpcIlN0YXRlbWVudFJlZlwiLCBpZDpcImFiY2RjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwifX19O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAwKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcblxuICAgICAgZGVzY3JpYmUoXCJmb3IgYSBjb250ZXh0IHByb3BlcnR5IHdpdGggYSBjb250ZXh0QWN0aXZpdGllcyBwcm9wZXJ0eVwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgaXQoXCJhIG51bGwgY29udGV4dEFjdGl2aXRpZXMgdmFsdWUgcHJvZHVjZXMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIGNvbnRleHQ6IHtjb250ZXh0QWN0aXZpdGllczpudWxsfX07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LmNvbnRleHQuY29udGV4dEFjdGl2aXRpZXNcIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhbiBBcnJheSBjb250ZXh0QWN0aXZpdGllcyB2YWx1ZSBwcm9kdWNlcyBhbiBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgY29udGV4dDoge2NvbnRleHRBY3Rpdml0aWVzOltdfX07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LmNvbnRleHQuY29udGV4dEFjdGl2aXRpZXNcIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhbiBOdW1lcmljIGNvbnRleHRBY3Rpdml0aWVzIHZhbHVlIHByb2R1Y2VzIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICBjb250ZXh0OiB7Y29udGV4dEFjdGl2aXRpZXM6MS4yM319O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHRzLCBcInN0YXRlbWVudC5jb250ZXh0LmNvbnRleHRBY3Rpdml0aWVzXCIsIFwiTVVTVF9WSU9MQVRJT05cIikpLnRvLmJlLnRydWU7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KFwiYW4gZW1wdHkgY29udGV4dEFjdGl2aXRpZXMgb2JqZWN0IHZhbHVlIHByb2R1Y2VzIG5vIGVycm9yc1wiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgY29udGV4dDoge2NvbnRleHRBY3Rpdml0aWVzOnt9fX07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDApO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImEgc2luZ2xlIEFjdGl2aXR5IHBhcmVudCBwcm9wZXJ0eSB2YWx1ZSBwcm9kdWNlcyBhIFNIT1VMRCB3YXJuaW5nXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICBjb250ZXh0OiB7Y29udGV4dEFjdGl2aXRpZXM6e3BhcmVudDp7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teU90aGVyQWN0aXZpdHlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn19fX07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LmNvbnRleHQuY29udGV4dEFjdGl2aXRpZXNcIiwgXCJTSE9VTERfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImFuIGVtcHR5IEFycmF5IHBhcmVudCBwcm9wZXJ0eSB2YWx1ZSBwcm9kdWNlcyBubyBlcnJvcnNcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIGNvbnRleHQ6IHtjb250ZXh0QWN0aXZpdGllczp7cGFyZW50OltdfX19O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAwKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhbiBBcnJheSB3aXRoIGEgdmFsaWQgQWN0aXZpdHkgaW4gdGhlIHBhcmVudCBwcm9wZXJ0eSBwcm9kdWNlcyBubyBlcnJvcnNcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIGNvbnRleHQ6IHtjb250ZXh0QWN0aXZpdGllczp7cGFyZW50Olt7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teU90aGVyQWN0aXZpdHlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn1dfX19O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAwKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhbiBBcnJheSB3aXRoIGEgaW52YWxpZCBBY3Rpdml0eSBpbiB0aGUgcGFyZW50IHByb3BlcnR5IHByb2R1Y2VzIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICBjb250ZXh0OiB7Y29udGV4dEFjdGl2aXRpZXM6e3BhcmVudDpbe29iamVjdFR5cGU6XCJBY3Rpdml0eVwifV19fX07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LmNvbnRleHQuY29udGV4dEFjdGl2aXRpZXMucGFyZW50WzBdLmlkXCIsIFwiTVVTVF9WSU9MQVRJT05cIikpLnRvLmJlLnRydWU7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIGRlc2NyaWJlKFwiZ2l2ZW4gYSB0aW1lc3RhbXAgcHJvcGVydHkgb24gdGhlIHN0YXRlbWVudFwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgaXQoXCJhIG51bGwgdmFsdWUgcHJvZHVjZXMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIHRpbWVzdGFtcDogbnVsbH07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LnRpbWVzdGFtcFwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImEgbnVtZXJpYyB2YWx1ZSBwcm9kdWNlcyBhbiBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgdGltZXN0YW1wOiAxLjIzfTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQudGltZXN0YW1wXCIsIFwiTVVTVF9WSU9MQVRJT05cIikpLnRvLmJlLnRydWU7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KFwiYSBEYXRlIHZhbHVlIHByb2R1Y2VzIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICB0aW1lc3RhbXA6IG5ldyBEYXRlKCl9O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHRzLCBcInN0YXRlbWVudC50aW1lc3RhbXBcIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhIFN0cmluZyB2YWx1ZSBub3QgaW4gSVNPIDg2MDEgcHJvZHVjZXMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIHRpbWVzdGFtcDogXCJ0b3RhbGx5IHdyb25nXCJ9O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHRzLCBcInN0YXRlbWVudC50aW1lc3RhbXBcIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhIFN0cmluZyB2YWx1ZSB3aXRoIElTTyA4NjAxIGF0IFVUQyB2aWEgWiBwcm9kdWNlcyBubyBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgdGltZXN0YW1wOiBcIjIwMTMtMDUtMDlUMTQ6NDU6MTVaXCJ9O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAwKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhIFN0cmluZyB2YWx1ZSB3aXRoIElTTyA4NjAxIGF0IFVUQyB2aWEgWiB3aXRoIG1pbGxpc2Vjb25kIHByZWNpc2lvbiBwcm9kdWNlcyBubyBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgdGltZXN0YW1wOiBcIjIwMTMtMDUtMDlUMTQ6NDU6MTUuMDA4WlwifTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KFwiYSBTdHJpbmcgdmFsdWUgd2l0aCBJU08gODYwMSB3aXRoIGEgcG9zaXRpdmUgdGltZXpvbmUgb2Zmc2V0IGhvdXIgcHJvZHVjZXMgbm8gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIHRpbWVzdGFtcDogXCIyMDEzLTA1LTA5VDE0OjQ1OjE1KzAxXCJ9O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAwKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhIFN0cmluZyB2YWx1ZSB3aXRoIElTTyA4NjAxIHdpdGggYSBwb3NpdGl2ZSB0aW1lem9uZSBvZmZzZXQgaG91ciBhbmQgbWludXRlcyBwcm9kdWNlcyBubyBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgdGltZXN0YW1wOiBcIjIwMTMtMDUtMDlUMTQ6NDU6MTUrMDE6MDJcIn07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDApO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImEgU3RyaW5nIHZhbHVlIHdpdGggSVNPIDg2MDEgd2l0aCBhIG5lZ2F0aXZlIHRpbWV6b25lIG9mZnNldCBob3VyIHByb2R1Y2VzIG5vIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICB0aW1lc3RhbXA6IFwiMjAxMy0wNS0wOVQxNDo0NToxNS0wMVwifTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KFwiYSBTdHJpbmcgdmFsdWUgd2l0aCBJU08gODYwMSB3aXRoIGEgbmVnYXRpdmUgdGltZXpvbmUgb2Zmc2V0IGhvdXIgYW5kIG1pbnV0ZXMgcHJvZHVjZXMgbm8gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIHRpbWVzdGFtcDogXCIyMDEzLTA1LTA5VDE0OjQ1OjE1LTAxOjAyXCJ9O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAwKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhIFN0cmluZyB2YWx1ZSB3aXRoIElTTzg2MDEgd2l0aCBubyB0aW1lem9uZSBvZmZzZXQgb3IgWiBwcm9kdWNlcyBhIFNIT1VMRCBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgdGltZXN0YW1wOiBcIjIwMTMtMDUtMDlUMTQ6NDU6MTVcIn07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LnRpbWVzdGFtcFwiLCBcIlNIT1VMRF9WSU9MQVRJT05cIikpLnRvLmJlLnRydWU7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIGRlc2NyaWJlKFwiZ2l2ZW4gYSBzdG9yZWQgcHJvcGVydHkgb24gdGhlIHN0YXRlbWVudFwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgaXQoXCJhIG51bGwgdmFsdWUgcHJvZHVjZXMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIHN0b3JlZDogbnVsbH07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LnN0b3JlZFwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImEgbnVtZXJpYyB2YWx1ZSBwcm9kdWNlcyBhbiBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgc3RvcmVkOiAxLjIzfTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQuc3RvcmVkXCIsIFwiTVVTVF9WSU9MQVRJT05cIikpLnRvLmJlLnRydWU7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KFwiYSBEYXRlIHZhbHVlIHByb2R1Y2VzIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICBzdG9yZWQ6IG5ldyBEYXRlKCl9O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHRzLCBcInN0YXRlbWVudC5zdG9yZWRcIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhIFN0cmluZyB2YWx1ZSBub3QgaW4gSVNPIDg2MDEgcHJvZHVjZXMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIHN0b3JlZDogXCJ0b3RhbGx5IHdyb25nXCJ9O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHRzLCBcInN0YXRlbWVudC5zdG9yZWRcIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhIFN0cmluZyB2YWx1ZSB3aXRoIElTTyA4NjAxIGF0IFVUQyB2aWEgWiBwcm9kdWNlcyBubyBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgc3RvcmVkOiBcIjIwMTMtMDUtMDlUMTQ6NDU6MTVaXCJ9O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAwKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhIFN0cmluZyB2YWx1ZSB3aXRoIElTTyA4NjAxIGF0IFVUQyB2aWEgWiB3aXRoIG1pbGxpc2Vjb25kIHByZWNpc2lvbiBwcm9kdWNlcyBubyBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgc3RvcmVkOiBcIjIwMTMtMDUtMDlUMTQ6NDU6MTUuMDA4WlwifTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KFwiYSBTdHJpbmcgdmFsdWUgd2l0aCBJU08gODYwMSB3aXRoIGEgcG9zaXRpdmUgdGltZXpvbmUgb2Zmc2V0IGhvdXIgcHJvZHVjZXMgbm8gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIHN0b3JlZDogXCIyMDEzLTA1LTA5VDE0OjQ1OjE1KzAxXCJ9O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAwKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhIFN0cmluZyB2YWx1ZSB3aXRoIElTTyA4NjAxIHdpdGggYSBwb3NpdGl2ZSB0aW1lem9uZSBvZmZzZXQgaG91ciBhbmQgbWludXRlcyBwcm9kdWNlcyBubyBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgc3RvcmVkOiBcIjIwMTMtMDUtMDlUMTQ6NDU6MTUrMDE6MDJcIn07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDApO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImEgU3RyaW5nIHZhbHVlIHdpdGggSVNPIDg2MDEgd2l0aCBhIG5lZ2F0aXZlIHRpbWV6b25lIG9mZnNldCBob3VyIHByb2R1Y2VzIG5vIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICBzdG9yZWQ6IFwiMjAxMy0wNS0wOVQxNDo0NToxNS0wMVwifTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KFwiYSBTdHJpbmcgdmFsdWUgd2l0aCBJU08gODYwMSB3aXRoIGEgbmVnYXRpdmUgdGltZXpvbmUgb2Zmc2V0IGhvdXIgYW5kIG1pbnV0ZXMgcHJvZHVjZXMgbm8gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIHN0b3JlZDogXCIyMDEzLTA1LTA5VDE0OjQ1OjE1LTAxOjAyXCJ9O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAwKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhIFN0cmluZyB2YWx1ZSB3aXRoIElTTzg2MDEgd2l0aCBubyB0aW1lem9uZSBvZmZzZXQgb3IgWiBwcm9kdWNlcyBhIFNIT1VMRCBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgc3RvcmVkOiBcIjIwMTMtMDUtMDlUMTQ6NDU6MTVcIn07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LnN0b3JlZFwiLCBcIlNIT1VMRF9WSU9MQVRJT05cIikpLnRvLmJlLnRydWU7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIGRlc2NyaWJlKFwiZm9yIGEgbm9uLW9iamVjdCBhdXRob3JpdHkgcHJvcGVydHkgb24gdGhlIHN0YXRlbWVudFwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgaXQoXCJhIG51bGwgYXV0aG9yaXR5IHZhbHVlIHByb2R1Y2VzIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICBhdXRob3JpdHk6IG51bGx9O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHRzLCBcInN0YXRlbWVudC5hdXRob3JpdHlcIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhbiBBcnJheSBhdXRob3JpdHkgdmFsdWUgcHJvZHVjZXMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIGF1dGhvcml0eTogW119O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHRzLCBcInN0YXRlbWVudC5hdXRob3JpdHlcIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhbiBOdW1lcmljIGF1dGhvcml0eSB2YWx1ZSBwcm9kdWNlcyBhbiBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgYXV0aG9yaXR5OiBbXX07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LmF1dGhvcml0eVwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuXG4gICAgICBkZXNjcmliZShcImZvciBhbiBhdXRob3JpdHkgcHJvcGVydHkgd2l0aCBhbiBvYmplY3QgdmFsdWUgb24gdGhlIHN0YXRlbWVudFwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgaXQoXCJhbiBBZ2VudCBhdXRob3JpdHkgdmFsdWUgcHJvZHVjZXMgbm8gZXJyb3JzXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICBhdXRob3JpdHk6IHtvYmplY3RUeXBlOlwiQWdlbnRcIiwgbWJveDpcIm1haWx0bzpib2JAZXhhbXBsZS5jb21cIn19O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAwKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhbiBBZ2VudCBhdXRob3JpdHkgdmFsdWUgcHJvZHVjZXMgYW4gZXJyb3IgaWYgYW4gaW52YWxpZCBBZ2VudFwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgYXV0aG9yaXR5OiB7b2JqZWN0VHlwZTpcIkFnZW50XCJ9fTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQuYXV0aG9yaXR5XCIsIFwiTVVTVF9WSU9MQVRJT05cIikpLnRvLmJlLnRydWU7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KFwiYW4gR3JvdXAgYXV0aG9yaXR5IHZhbHVlIHdpdGggdHdvIG1lbWJlcnMgcHJvZHVjZXMgbm8gZXJyb3JzXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICBhdXRob3JpdHk6IHtvYmplY3RUeXBlOlwiR3JvdXBcIiwgbWVtYmVyOlt7b2JqZWN0VHlwZTpcIkFnZW50XCIsIG1ib3g6XCJtYWlsdG86Ym9iQGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgICAgICB7b2JqZWN0VHlwZTpcIkFnZW50XCIsIG1ib3g6XCJtYWlsdG86dG9tQGV4YW1wbGUuY29tXCJ9XX19O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAwKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhbiBHcm91cCBhdXRob3JpdHkgdmFsdWUgd2l0aCBsZXNzIHRoYW4gdHdvIG1lbWJlcnMgcHJvZHVjZXMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIGF1dGhvcml0eToge29iamVjdFR5cGU6XCJHcm91cFwiLCBtZW1iZXI6W3tvYmplY3RUeXBlOlwiQWdlbnRcIiwgbWJveDpcIm1haWx0bzpib2JAZXhhbXBsZS5jb21cIn1dfX07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LmF1dGhvcml0eS5tZW1iZXJcIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhbiBHcm91cCBhdXRob3JpdHkgdmFsdWUgd2l0aCBtb3JlIHRoYW4gdHdvIG1lbWJlcnMgcHJvZHVjZXMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIGF1dGhvcml0eToge29iamVjdFR5cGU6XCJHcm91cFwiLCBtZW1iZXI6W3tvYmplY3RUeXBlOlwiQWdlbnRcIiwgbWJveDpcIm1haWx0bzpib2JAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgICAgIHtvYmplY3RUeXBlOlwiQWdlbnRcIiwgbWJveDpcIm1haWx0bzp0b21AZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgICAgIHtvYmplY3RUeXBlOlwiQWdlbnRcIiwgbWJveDpcIm1haWx0bzpmcmFua0BleGFtcGxlLmNvbVwifV19fTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQuYXV0aG9yaXR5Lm1lbWJlclwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImFuIEdyb3VwIGF1dGhvcml0eSB2YWx1ZSB3aXRoIGFuIGludmFsaWQgbWVtYmVyIHByb2R1Y2VzIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICBhdXRob3JpdHk6IHtvYmplY3RUeXBlOlwiR3JvdXBcIiwgbWVtYmVyOlt7b2JqZWN0VHlwZTpcIkFnZW50XCIsIG1ib3g6XCJtYWlsdG86Ym9iQGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgICAgICB7b2JqZWN0VHlwZTpcIkFnZW50XCJ9XX19O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHRzLCBcInN0YXRlbWVudC5hdXRob3JpdHkubWVtYmVyWzFdXCIsIFwiTVVTVF9WSU9MQVRJT05cIikpLnRvLmJlLnRydWU7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIGRlc2NyaWJlKFwiZm9yIGFuIHZlcnNpb24gcHJvcGVydHkgb24gdGhlIHN0YXRlbWVudCB3aXRoIGEgbm9uLXN0cmluZyB2YWx1ZVwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgaXQoXCJhIG51bGwgdmFsdWUgcHJvZHVjZXMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIHZlcnNpb246IG51bGx9O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHRzLCBcInN0YXRlbWVudC52ZXJzaW9uXCIsIFwiTVVTVF9WSU9MQVRJT05cIikpLnRvLmJlLnRydWU7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KFwiYSBudW1lcmljIHZhbHVlIHByb2R1Y2VzIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICB2ZXJzaW9uOiAxLjB9O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHRzLCBcInN0YXRlbWVudC52ZXJzaW9uXCIsIFwiTVVTVF9WSU9MQVRJT05cIikpLnRvLmJlLnRydWU7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIGRlc2NyaWJlKFwiZm9yIGFuIHZlcnNpb24gcHJvcGVydHkgd2l0aCBhIHN0cmluZyB2YWx1ZVwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgaXQoXCJhIHNpbXBsZSBzZW1hbnRpYyB2ZXJzaW9uIHByb2R1Y2VzIG5vIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICB2ZXJzaW9uOiBcIjEuMC4wXCJ9O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAwKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhIHNlbWFudGljIHZlcnNpb24gd2l0aCBpbnRlcm1peGVkIG5vbi1udW1iZXJzIGluIHRoZSBtYWpvci9taW5vci9wYXRjaCBwcm9kdWNlcyBhbiBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgdmVyc2lvbjogXCIxLjAuYVwifTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQudmVyc2lvblwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImEgc2VtYW50aWMgdmVyc2lvbiB3aXRoIHZhbGlkIHByZS1yZWxlYXNlIGluZm8gcHJvZHVjZXMgbm8gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIHZlcnNpb246IFwiMS4wLjAtcmMxXCJ9O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAwKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhIHNlbWFudGljIHZlcnNpb24gd2l0aCBpbnZhbGlkIHByZS1yZWxlYXNlIGluZm8gcHJvZHVjZXMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIHZlcnNpb246IFwiMS4wLjAtcmMuMVwifTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQudmVyc2lvblwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImEgc2VtYW50aWMgdmVyc2lvbiB3aXRoIFNlbVZlciAyLjAuMCBidWlsZCByZWxlYXNlIGluZm8gY2hhcmFjdGVycyBub3QgaW4gU2VtVmVyIDEuMC4wIHByb2R1Y2VzIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICB2ZXJzaW9uOiBcIjEuMC4wLWFscGhhLjFcIn07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LnZlcnNpb25cIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhIHNlbWFudGljIHZlcnNpb24gd2l0aCBTZW1WZXIgMi4wLjAgYnVpbGQgcmVsZWFzZSBtZXRhZGF0YSBub3QgaW4gU2VtVmVyIDEuMC4wIHByb2R1Y2VzIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICB2ZXJzaW9uOiBcIjEuMC4wLWFscGhhKzAwMVwifTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQudmVyc2lvblwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuXG4gICAgICBkZXNjcmliZShcImZvciBhbiBhdHRhY2htZW50cyBwcm9wZXJ0eSBvbiB0aGUgc3RhdGVtZW50IHdpdGggYSBub24tQXJyYXkgdmFsdWVcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIGl0KFwiYSBudWxsIHZhbHVlIHByb2R1Y2VzIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICBhdHRhY2htZW50czogbnVsbH07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LmF0dGFjaG1lbnRzXCIsIFwiTVVTVF9WSU9MQVRJT05cIikpLnRvLmJlLnRydWU7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KFwiYSBudW1lcmljIHZhbHVlIHByb2R1Y2VzIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICBhdHRhY2htZW50czogMS4wfTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQuYXR0YWNobWVudHNcIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhbiBvYmplY3QgbWFwIHZhbHVlIHByb2R1Y2VzIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICBhdHRhY2htZW50czoge319O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHRzLCBcInN0YXRlbWVudC5hdHRhY2htZW50c1wiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuXG4gICAgICBkZXNjcmliZShcImZvciBhbiBhdHRhY2htZW50cyBwcm9wZXJ0eSBvbiB0aGUgc3RhdGVtZW50IHdpdGggYW4gQXJyYXkgdmFsdWVcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIGl0KFwiYW4gZW1wdHkgQXJyYXkgcHJvZHVjZXMgbm8gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIGF0dGFjaG1lbnRzOiBbXX07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDApO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuXG4gICAgICBkZXNjcmliZShcImZvciBhbiBhdHRhY2htZW50IG9iamVjdCB3aXRoaW4gdGhlIGF0dGFjaG1lbnRzIHByb3BlcnR5J3MgQXJyYXkgb24gdGhlIHN0YXRlbWVudFwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgaXQoXCJhIG51bGwgb2JqZWN0IHByb2R1Y2VzIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICBhdHRhY2htZW50czogW251bGxdfTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQuYXR0YWNobWVudHNbMF1cIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJtaW5pbWFsIHZhbGlkIGF0dGFjaG1lbnQgb2JqZWN0IHByb2R1Y2VzIG5vIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICBhdHRhY2htZW50czogW3t1c2FnZVR5cGU6XCJodHRwOi8vZXhhbXBsZS5jb20vdXNhZ2UvaW5mby9BXCIsIGRpc3BsYXk6e30sIGNvbnRlbnRUeXBlOlwidGV4dC9wbGFpblwiLCBsZW5ndGg6MTEsIHNoYTI6XCJ1VTBudVpOTlBnaWxMbExYMm4ycitzU0U3K042VTREdWtJajNyT0x2emVrPVwifV19O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAwKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhbiBhYnNlbnQgdXNhZ2VUeXBlIHByb3BlcnR5IG9iamVjdCBwcm9kdWNlcyBhbiBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgYXR0YWNobWVudHM6IFt7ZGlzcGxheTp7fSwgY29udGVudFR5cGU6XCJ0ZXh0L3BsYWluXCIsIGxlbmd0aDoxMSwgc2hhMjpcInVVMG51Wk5OUGdpbExsTFgybjJyK3NTRTcrTjZVNER1a0lqM3JPTHZ6ZWs9XCJ9XX07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LmF0dGFjaG1lbnRzWzBdLnVzYWdlVHlwZVwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImEgbnVsbCB1c2FnZVR5cGUgcHJvcGVydHkgb2JqZWN0IHByb2R1Y2VzIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICBhdHRhY2htZW50czogW3t1c2FnZVR5cGU6bnVsbCwgZGlzcGxheTp7fSwgY29udGVudFR5cGU6XCJ0ZXh0L3BsYWluXCIsIGxlbmd0aDoxMSwgc2hhMjpcInVVMG51Wk5OUGdpbExsTFgybjJyK3NTRTcrTjZVNER1a0lqM3JPTHZ6ZWs9XCJ9XX07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LmF0dGFjaG1lbnRzWzBdLnVzYWdlVHlwZVwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImEgbnVtZXJpYyB1c2FnZVR5cGUgcHJvcGVydHkgb2JqZWN0IHByb2R1Y2VzIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICBhdHRhY2htZW50czogW3t1c2FnZVR5cGU6MTIzLCBkaXNwbGF5Ont9LCBjb250ZW50VHlwZTpcInRleHQvcGxhaW5cIiwgbGVuZ3RoOjExLCBzaGEyOlwidVUwbnVaTk5QZ2lsTGxMWDJuMnIrc1NFNytONlU0RHVrSWozck9Mdnplaz1cIn1dfTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQuYXR0YWNobWVudHNbMF0udXNhZ2VUeXBlXCIsIFwiTVVTVF9WSU9MQVRJT05cIikpLnRvLmJlLnRydWU7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KFwiYW4gb2JqZWN0IHVzYWdlVHlwZSBwcm9wZXJ0eSBvYmplY3QgcHJvZHVjZXMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIGF0dGFjaG1lbnRzOiBbe3VzYWdlVHlwZTp7fSwgZGlzcGxheTp7fSwgY29udGVudFR5cGU6XCJ0ZXh0L3BsYWluXCIsIGxlbmd0aDoxMSwgc2hhMjpcInVVMG51Wk5OUGdpbExsTFgybjJyK3NTRTcrTjZVNER1a0lqM3JPTHZ6ZWs9XCJ9XX07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LmF0dGFjaG1lbnRzWzBdLnVzYWdlVHlwZVwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImFuIGFic2VudCBjb250ZW50VHlwZSBwcm9wZXJ0eSBvYmplY3QgcHJvZHVjZXMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIGF0dGFjaG1lbnRzOiBbe3VzYWdlVHlwZTpcImh0dHA6Ly9leGFtcGxlLmNvbS91c2FnZS9pbmZvL0FcIiwgZGlzcGxheTp7fSwgbGVuZ3RoOjExLCBzaGEyOlwidVUwbnVaTk5QZ2lsTGxMWDJuMnIrc1NFNytONlU0RHVrSWozck9Mdnplaz1cIn1dfTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQuYXR0YWNobWVudHNbMF0uY29udGVudFR5cGVcIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhIG51bGwgY29udGVudFR5cGUgcHJvcGVydHkgb2JqZWN0IHByb2R1Y2VzIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICBhdHRhY2htZW50czogW3t1c2FnZVR5cGU6XCJodHRwOi8vZXhhbXBsZS5jb20vdXNhZ2UvaW5mby9BXCIsIGRpc3BsYXk6e30sIGNvbnRlbnRUeXBlOm51bGwsIGxlbmd0aDoxMSwgc2hhMjpcInVVMG51Wk5OUGdpbExsTFgybjJyK3NTRTcrTjZVNER1a0lqM3JPTHZ6ZWs9XCJ9XX07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LmF0dGFjaG1lbnRzWzBdLmNvbnRlbnRUeXBlXCIsIFwiTVVTVF9WSU9MQVRJT05cIikpLnRvLmJlLnRydWU7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KFwiYW4gYWJzZW50IGxlbmd0aCBwcm9wZXJ0eSBvYmplY3QgcHJvZHVjZXMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIGF0dGFjaG1lbnRzOiBbe3VzYWdlVHlwZTpcImh0dHA6Ly9leGFtcGxlLmNvbS91c2FnZS9pbmZvL0FcIiwgZGlzcGxheTp7fSwgY29udGVudFR5cGU6XCJ0ZXh0L3BsYWluXCIsIHNoYTI6XCJ1VTBudVpOTlBnaWxMbExYMm4ycitzU0U3K042VTREdWtJajNyT0x2emVrPVwifV19O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHRzLCBcInN0YXRlbWVudC5hdHRhY2htZW50c1swXS5sZW5ndGhcIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhIG51bGwgbGVuZ3RoIHByb3BlcnR5IG9iamVjdCBwcm9kdWNlcyBhbiBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgYXR0YWNobWVudHM6IFt7dXNhZ2VUeXBlOlwiaHR0cDovL2V4YW1wbGUuY29tL3VzYWdlL2luZm8vQVwiLCBkaXNwbGF5Ont9LCBjb250ZW50VHlwZTpcInRleHQvcGxhaW5cIiwgbGVuZ3RoOm51bGwsIHNoYTI6XCJ1VTBudVpOTlBnaWxMbExYMm4ycitzU0U3K042VTREdWtJajNyT0x2emVrPVwifV19O1xuICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSB4YXBpVmFsaWRhdG9yLnZhbGlkYXRlU3RhdGVtZW50KGlucHV0U3RhdGVtZW50KTtcbiAgICAgICAgICAgIGV4cGVjdChyZXN1bHRzLmVycm9ycykudG8uaGF2ZS5wcm9wZXJ0eShcImxlbmd0aFwiLCAxKTtcbiAgICAgICAgICAgIGV4cGVjdChyZXBvcnRIYXNFcnJvcldpdGhUcmFjZVByZWZpeChyZXN1bHRzLCBcInN0YXRlbWVudC5hdHRhY2htZW50c1swXS5sZW5ndGhcIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhIHN0cmluZyBsZW5ndGggcHJvcGVydHkgb2JqZWN0IHByb2R1Y2VzIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICBhdHRhY2htZW50czogW3t1c2FnZVR5cGU6XCJodHRwOi8vZXhhbXBsZS5jb20vdXNhZ2UvaW5mby9BXCIsIGRpc3BsYXk6e30sIGNvbnRlbnRUeXBlOlwidGV4dC9wbGFpblwiLCBsZW5ndGg6XCIxMVwiLCBzaGEyOlwidVUwbnVaTk5QZ2lsTGxMWDJuMnIrc1NFNytONlU0RHVrSWozck9Mdnplaz1cIn1dfTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQuYXR0YWNobWVudHNbMF0ubGVuZ3RoXCIsIFwiTVVTVF9WSU9MQVRJT05cIikpLnRvLmJlLnRydWU7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KFwiYSBub24taW50ZWdlciBsZW5ndGggcHJvcGVydHkgb2JqZWN0IHByb2R1Y2VzIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICBhdHRhY2htZW50czogW3t1c2FnZVR5cGU6XCJodHRwOi8vZXhhbXBsZS5jb20vdXNhZ2UvaW5mby9BXCIsIGRpc3BsYXk6e30sIGNvbnRlbnRUeXBlOlwidGV4dC9wbGFpblwiLCBsZW5ndGg6MTEuNSwgc2hhMjpcInVVMG51Wk5OUGdpbExsTFgybjJyK3NTRTcrTjZVNER1a0lqM3JPTHZ6ZWs9XCJ9XX07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LmF0dGFjaG1lbnRzWzBdLmxlbmd0aFwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImEgbnVsbCBzaGEyIHByb3BlcnR5IHByb2R1Y2VzIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICBhdHRhY2htZW50czogW3t1c2FnZVR5cGU6XCJodHRwOi8vZXhhbXBsZS5jb20vdXNhZ2UvaW5mby9BXCIsIGRpc3BsYXk6e30sIGNvbnRlbnRUeXBlOlwidGV4dC9wbGFpblwiLCBsZW5ndGg6MTEsIHNoYTI6bnVsbH1dfTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQuYXR0YWNobWVudHNbMF0uc2hhMlwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImFuIGFic2VudCBzaGEyIHByb3BlcnR5IHByb2R1Y2VzIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICBhdHRhY2htZW50czogW3t1c2FnZVR5cGU6XCJodHRwOi8vZXhhbXBsZS5jb20vdXNhZ2UvaW5mby9BXCIsIGRpc3BsYXk6e30sIGNvbnRlbnRUeXBlOlwidGV4dC9wbGFpblwiLCBsZW5ndGg6MTF9XX07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LmF0dGFjaG1lbnRzWzBdLnNoYTJcIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhIG51bWVyaWMgc2hhMiBwcm9wZXJ0eSBwcm9kdWNlcyBhbiBlcnJvclwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBpbnB1dFN0YXRlbWVudCA9IHtpZCA6IFwiZmQ0MWM5MTgtYjg4Yi00YjIwLWEwYTUtYTRjMzIzOTFhYWEwXCIgLFxuICAgICAgICAgICAgICAgIGFjdG9yIDoge21ib3g6XCJtYWlsdG86YWdlbnRAZXhhbXBsZS5jb21cIn0sXG4gICAgICAgICAgICAgICAgdmVyYjogeyBcImlkXCI6XCJodHRwOi8vYWRsbmV0Lmdvdi9leHBhcGkvdmVyYnMvY3JlYXRlZFwiLCBcImRpc3BsYXlcIjp7XCJlbi1VU1wiOlwiY3JlYXRlZFwifX0sXG4gICAgICAgICAgICAgICAgb2JqZWN0IDoge2lkIDogXCJodHRwOi8vZXhhbXBsZS5jb20vbXlVbmlxdWVJZFwiLCBvYmplY3RUeXBlOlwiQWN0aXZpdHlcIn0sXG4gICAgICAgICAgICAgICAgYXR0YWNobWVudHM6IFt7dXNhZ2VUeXBlOlwiaHR0cDovL2V4YW1wbGUuY29tL3VzYWdlL2luZm8vQVwiLCBkaXNwbGF5Ont9LCBjb250ZW50VHlwZTpcInRleHQvcGxhaW5cIiwgbGVuZ3RoOjExLCBzaGEyOjEuMjN9XX07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LmF0dGFjaG1lbnRzWzBdLnNoYTJcIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoXCJhIG5vbi1iYXNlNjQgc2hhMiBwcm9wZXJ0eSBvYmplY3QgcHJvZHVjZXMgYW4gZXJyb3JcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXRTdGF0ZW1lbnQgPSB7aWQgOiBcImZkNDFjOTE4LWI4OGItNGIyMC1hMGE1LWE0YzMyMzkxYWFhMFwiICxcbiAgICAgICAgICAgICAgICBhY3RvciA6IHttYm94OlwibWFpbHRvOmFnZW50QGV4YW1wbGUuY29tXCJ9LFxuICAgICAgICAgICAgICAgIHZlcmI6IHsgXCJpZFwiOlwiaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL3ZlcmJzL2NyZWF0ZWRcIiwgXCJkaXNwbGF5XCI6e1wiZW4tVVNcIjpcImNyZWF0ZWRcIn19LFxuICAgICAgICAgICAgICAgIG9iamVjdCA6IHtpZCA6IFwiaHR0cDovL2V4YW1wbGUuY29tL215VW5pcXVlSWRcIiwgb2JqZWN0VHlwZTpcIkFjdGl2aXR5XCJ9LFxuICAgICAgICAgICAgICAgIGF0dGFjaG1lbnRzOiBbe3VzYWdlVHlwZTpcImh0dHA6Ly9leGFtcGxlLmNvbS91c2FnZS9pbmZvL0FcIiwgZGlzcGxheTp7fSwgY29udGVudFR5cGU6XCJ0ZXh0L3BsYWluXCIsIGxlbmd0aDoxMSwgc2hhMjpcInVzZXMgfiAtIGNoYXJhY3RlcnMgJl4lIG5vdCBpbiBiYXNlNjRcIn1dfTtcbiAgICAgICAgICAgIHZhciByZXN1bHRzID0geGFwaVZhbGlkYXRvci52YWxpZGF0ZVN0YXRlbWVudChpbnB1dFN0YXRlbWVudCk7XG4gICAgICAgICAgICBleHBlY3QocmVzdWx0cy5lcnJvcnMpLnRvLmhhdmUucHJvcGVydHkoXCJsZW5ndGhcIiwgMSk7XG4gICAgICAgICAgICBleHBlY3QocmVwb3J0SGFzRXJyb3JXaXRoVHJhY2VQcmVmaXgocmVzdWx0cywgXCJzdGF0ZW1lbnQuYXR0YWNobWVudHNbMF0uc2hhMlwiLCBcIk1VU1RfVklPTEFUSU9OXCIpKS50by5iZS50cnVlO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdChcImEgbnVsbCBmaWxlVXJsIHByb3BlcnR5IHByb2R1Y2VzIGFuIGVycm9yXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGlucHV0U3RhdGVtZW50ID0ge2lkIDogXCJmZDQxYzkxOC1iODhiLTRiMjAtYTBhNS1hNGMzMjM5MWFhYTBcIiAsXG4gICAgICAgICAgICAgICAgYWN0b3IgOiB7bWJveDpcIm1haWx0bzphZ2VudEBleGFtcGxlLmNvbVwifSxcbiAgICAgICAgICAgICAgICB2ZXJiOiB7IFwiaWRcIjpcImh0dHA6Ly9hZGxuZXQuZ292L2V4cGFwaS92ZXJicy9jcmVhdGVkXCIsIFwiZGlzcGxheVwiOntcImVuLVVTXCI6XCJjcmVhdGVkXCJ9fSxcbiAgICAgICAgICAgICAgICBvYmplY3QgOiB7aWQgOiBcImh0dHA6Ly9leGFtcGxlLmNvbS9teVVuaXF1ZUlkXCIsIG9iamVjdFR5cGU6XCJBY3Rpdml0eVwifSxcbiAgICAgICAgICAgICAgICBhdHRhY2htZW50czogW3t1c2FnZVR5cGU6XCJodHRwOi8vZXhhbXBsZS5jb20vdXNhZ2UvaW5mby9BXCIsIGRpc3BsYXk6e30sIGZpbGVVcmw6bnVsbCwgY29udGVudFR5cGU6XCJ0ZXh0L3BsYWluXCIsIGxlbmd0aDoxMSwgc2hhMjpcInVVMG51Wk5OUGdpbExsTFgybjJyK3NTRTcrTjZVNER1a0lqM3JPTHZ6ZWs9XCJ9XX07XG4gICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHhhcGlWYWxpZGF0b3IudmFsaWRhdGVTdGF0ZW1lbnQoaW5wdXRTdGF0ZW1lbnQpO1xuICAgICAgICAgICAgZXhwZWN0KHJlc3VsdHMuZXJyb3JzKS50by5oYXZlLnByb3BlcnR5KFwibGVuZ3RoXCIsIDEpO1xuICAgICAgICAgICAgZXhwZWN0KHJlcG9ydEhhc0Vycm9yV2l0aFRyYWNlUHJlZml4KHJlc3VsdHMsIFwic3RhdGVtZW50LmF0dGFjaG1lbnRzWzBdLmZpbGVVcmxcIiwgXCJNVVNUX1ZJT0xBVElPTlwiKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfSk7XG59KTtcbiJdfQ== diff --git a/src/constants/errors.js b/src/constants/errors.js new file mode 100644 index 0000000..d6ed3ce --- /dev/null +++ b/src/constants/errors.js @@ -0,0 +1,89 @@ +'use strict'; + +const xapiErrorLevels = Object.freeze({ + MAY_VIOLATION: 'MAY_VIOLATION', + MUST_VIOLATION: 'MUST_VIOLATION', + SHOULD_VIOLATION: 'SHOULD_VIOLATION' +}); + +const xapiValidationErrors = Object.freeze({ + ACTIVITIES_MUST_NOT_BE_NULL_MAP_OBJECTS: 'Activities must be non-null map objects', + ACTOR_MUST_BE_PROVIDED: 'Actor must be provided.', + AGENT_IFI_PROPERTIES_MUST_BE_SPECIFIED: 'Exactly one Inverse Functional Identifier property must be specified for an "agent".', + AGENT_MUST_BE_NON_NULL_MAP_OBJECT: '"agent" must be a non-null map object', + AGENT_MUST_NOT_HAVE_GROUP_CHARACTERISTICS: 'Invalid object with characteristics of a Group when an Agent was expected.', + ATTACHMENTS_MUST_BE_NOT_NULL_ARRAY: '"attachments" must be a non-null Array.', + ATTACHMENTS_MUST_NOT_BE_NULL_MAP_OBJECTS: '"attachment" instances must be non-null map objects.', + AUTHORITY_MUST_BE_NON_NULL_MAP_OBJECT: 'If present, the "authority" property must be a non-null map object.', + CONTEXT_ACTIVITIES_MUST_BE_ARRAY_OR_ACTIVITY_OBJ: 'Context Activities property values must be an array of Activity Objects or a single Activity Object.', + CONTEXT_ACTIVITIES_MUST_BE_NON_NULL_MAP_OBJECT: 'The Context Activities instances must be a non-null map object.', + CONTEXT_ACTIVITIES_MUST_NOT_BE_NULL: '"Context Activities" property values must not be null.', + CONTEXT_ACTIVITIES_SHOULD_BE_AN_ARRAY: 'Context Activities property values should prefer to be an array of Activities rather than a single Activity object.', + CONTEXT_MUST_BE_NON_NUL_MAP_OBJECT: 'If present, the "context" property must be a non-null map object.', + CORRECT_RESPONSES_PATTERN_MUST_BE_ARRAY: 'If present, the "correctResponsesPattern" value must be an Array of strings.', + CORRECT_RESPONSES_PATTERN_MUST_BE_STRINGS: '"correctResponsesPattern" items must be strings.', + DATE_MUST_BE_VALID: 'This propertys string value must be conformant to ISO 8601 for Date Times.', + DATE_SHOULD_INCLUDE_ZONE_INFORMATION: 'ISO 8601 date time strings used in the xAPI should include time zone information.', + DEFINITIONS_MUST_BE_OBJECTS: '"definitions", when present, must be map objects', + DISPLAY_SHOULD_BE_PROVIDED: '"display" property should be provided.', + DURATION_MUST_BE_VALID: 'If present, the "duration" property value must be an ISO 8601 duration', + EXTENSIONS_MUST_NOT_BE_NULL: 'If present, the extensions property must be a non-null map object.', + GROUP_AUTHORITY_AGENT_MEMBERS_MUST_BE_TWO: 'If used as a Group, the "authority" property must contain a "member" property that is an array containing exactly two Agent objects.', + GROUP_IFI_PROPERTIES_MUST_BE_SPECIFIED: 'Exactly one Inverse Functional Identifier property must be specified for a "group".', + GROUP_MEMBER_MUST_BE_ARRAY: 'If present, the member property of a Group must be an Array', + GROUP_MUST_BE_NON_NULL_MAP_OBJECT: '"group" must be a non-null map object', + ID_MUST_BE_UNIQUE: '"id" properties must be unique within each interaction component array', + ID_MUST_BE_VALID_UUID_REF: '"id" property value must be a valid UUID string for statement reference objects.', + ID_MUST_BE_VALID: 'Id was not a valid UUID', + ID_SHOULD_NOT_CONTAIN_WHITESPACES: '"id" properties on interaction components should not contain whitespace', + IDS_SHOULD_BE_GENERATED_BY_LRS: 'Ids should be generated by the Activity Provider, and must be generated by the LRS', + IFI_MUST_BE_MBOX_URI: '"mbox" property was required to be a mailto URI string but was not a string at all.', + IFI_MUST_BE_VALID_MBOX_FORMAT: '"mbox" property was required to be a mailto URI string but did not match the mailto format.', + INTERACTION_ACTIVITY_SHOULD_HAVE: 'Interaction Activity Definitions should have a type property of', + INTERACTION_COMPONENT_MUST_NOT_BE_NULL: 'This interaction component collection member must be a non-null map object', + INTERACTION_COMPONENT_SHOULD_BE_ARRAY: 'This interaction component collection property should be an array.', + INTERACTION_TYPE_MUST_BE_CMI: 'If present, the "interactionType" value must be a CMI interaction type option.', + INTERACTION_TYPE_MUST_BE_VALID: 'This interaction component collection property is not associated with the present interactionType of: ', + INVALID_JSON: 'Invalid JSON. The statement could not be parsed.', + LANGUAGE_MAP_KEY_INVALID: 'key, Language does not conform to RFC 5646', + LANGUAGE_MAP_KEY_MUST_BE_STRING: 'key: Language Map value should be a String, but was not', + LANGUAGE_MAPS_MUST_NOT_BE_NULL: 'Language Maps, when present, must be non-null map objects', + LANGUAGE_MUST_BE_STRING: 'The language property must be encoded as an RFC 5646 compliant string, but was not.', + LENGTH_MUST_BE_INTEGER: '"length" property must be provided with an integer value', + MAX_MUST_BE_GREATER_THAN_MIN: 'If both "max" and "min" are present, the max property value should be greater than min', + MEMBER_MUST_BE_PROVIDED_FOR_ANONYMOUS_GROUPS: '"member" property must be provided for Anonymous Groups.', + MUST_BE_BOOLEAN_PRESENT: 'property was required to be a Boolean but was absent.', + MUST_BE_BOOLEAN: 'property, if present, must be a Boolean.', + MUST_BE_IRI_STRING: 'property, if present, should be a IRI-like absolute URI per RFC 3987.', + MUST_BE_NUMBER_PRESENT: 'property was required to be a Number but was absent.', + MUST_BE_NUMBER: 'property, if present, must be a Number.', + MUST_BE_PRESENT: 'property was required to be a string but was absent.', + MUST_BE_STRING: 'property, if present, must be a string.', + MUST_BE_URI_PRESENT: 'property was required to be a URI string but was absent.', + MUST_BE_URI_STRING: 'property, if present, must be a URI string.', + OBJECT_MUST_BE_DEFINED: '"object" property must be provided.', + OBJECT_MUST_BE_NON_NULL_MAP_OBJECT: '"object" property must be a non-null map object.', + OBJECT_TYPE_MUST_BE_STATEMENT_REF: '"objectType" property value must be "StatementRef" for statement reference objects.', + OBJECT_TYPE_MUST_BE_VALID_OPTION: 'object\'s "objectType" did not match a valid option', + RAW_MUST_BE_GREATER_THAN_MIN: 'If both "raw" and "min" are present, the raw property value should be greater than min', + RAW_MUST_BE_LESS_THAN_MAX: 'If both "raw" and "max" are present, the raw property value should be less than max', + REGISTRATION_MUST_BE_UUID_STRING: 'If present, the registration property must be a UUID string.', + RESULT_MUST_BE_MAP_OBJECT: 'If present, the result must be a map object', + REVISION_MUST_BE_AGENT_OR_GROUP: 'The revision property must not be used if the Statement\'s Object is an Agent or Group.', + SCALED_MUST_BE_BETWEEN_0_1: 'If present, the scaled property value must be between 0 and 1', + SHA2_MUST_BE_PROVIDED_ON_ATTACHMENT_OBJECTS: '"sha2" property must be provided on attachment objects', + SHA2_MUST_CONTAIN_BASE_64_STRING: '"sha2" property must contain a string with base64 contents', + STATEMENT_ARGUMENT_IS_NOT_VALID: 'Statement argument provided was not a valid object or a valid JSON string.', + STATEMENT_ARGUMENT_MUST_BE_PROVIDED: 'No statement argument provided.', + STATEMENT_MUST_BE_PARSED_CORRECTLY: 'Null or non-object statement value parsed from provided statment JSON.', + STATEMENT_MUST_NOT_BE_NULL: 'Null statement argument provided.', + STATEMENT_REF_MUST_NOT_BE_NULL_MAP_OBJECTS: 'StatementRef instances must be non-null map objects', + SUB_STATEMENT_MUST_NOT_CONTAIN_SUB_STATEMENT: 'A SubStatement must not contain a SubStatement', + UNEXPECTED: 'Unexpected property not permitted', + VERB_MUST_BE_PROVIDED: 'Verb must be provided', + VERB_MUST_NOT_BE_NULL: 'Verb property value must a non-null map object.', + VERSION_MUST_COMPLY_SEMANTIC_VERSIONING: '"version" must be a non-null string that complies with Semantic Versioning 1.0.0' +}); + +export {xapiErrorLevels}; +export {xapiValidationErrors}; diff --git a/src/constants/general.js b/src/constants/general.js new file mode 100644 index 0000000..0a0fd99 --- /dev/null +++ b/src/constants/general.js @@ -0,0 +1,13 @@ +'use strict'; + +const xapiGeneral = Object.freeze({ + FIRST_REPORT_VERSTION : '1.0.0', + GROUP_AUTHORITY_AGENT_MEMBERS : 2, + INTERACTION_DEFINITION_TYPE : 'http://adlnet.gov/expapi/activities/cmi.interaction', + MAX_SCALED_VALUE : 1, + MIN_SCALED_VALUE : 0, + NO_INDEX_FOUND : -1, + NUMER_OF_SPECIFIED_IFI_PROPERTIES : 1 +}); + +export {xapiGeneral}; diff --git a/src/constants/interaction-types.js b/src/constants/interaction-types.js new file mode 100644 index 0000000..af3eced --- /dev/null +++ b/src/constants/interaction-types.js @@ -0,0 +1,27 @@ +'use strict'; + +export const interactionTypes = Object.freeze({ + CHOICE: 'choice', + FILL_IN: 'fill-in', + LIKERT: 'likert', + LONG_FILL_IN: 'long-fill-in', + MATCHING: 'matching', + NUMERIC: 'numeric', + OTHER: 'other', + PERFORMANCE: 'performance', + SEQUENCING: 'sequencing', + TRUE_FALSE: 'true-false' +}); + +export const xapiValidationInteractionTypes = Object.freeze([ + interactionTypes.CHOICE, + interactionTypes.FILL_IN, + interactionTypes.LIKERT, + interactionTypes.LONG_FILL_IN, + interactionTypes.MATCHING, + interactionTypes.NUMERIC, + interactionTypes.OTHER, + interactionTypes.PERFORMANCE, + interactionTypes.SEQUENCING, + interactionTypes.TRUE_FALSE +]); diff --git a/src/constants/properties.js b/src/constants/properties.js new file mode 100644 index 0000000..8f20330 --- /dev/null +++ b/src/constants/properties.js @@ -0,0 +1,223 @@ +'use strict'; + +const properties = Object.freeze({ + ACCOUNT: 'account', + ACTIVITY: 'activity', + ACTOR: 'actor', + AGENT: 'agent', + ATTACHMENT: 'attachment', + ATTACHMENTS: 'attachments', + AUTHORITY: 'authority', + CATEGORY: 'category', + CHOICE: 'choice', + CHOICES: 'choices', + COMPLETION: 'completion', + CONTENT_TYPE: 'contentType', + CONTEXT_ACTIVITIES: 'contextActivities', + CONTEXT: 'context', + CORRECT_RESPONSES_PATTERN: 'correctResponsesPattern', + DATE_TIME: 'dateTime', + DEFINITION: 'definition', + DESCRIPTION: 'description', + DISPLAY: 'display', + DURATION: 'duration', + EXTENSIONS: 'extensions', + FILE_URL: 'fileUrl', + GROUP: 'group', + GROUPING: 'grouping', + HOME_PAGE: 'homePage', + ID: 'id', + INSTRUCTOR: 'instructor', + INTERACTION_COMPONENTS: 'interactionComponents', + INTERACTION_TYPE: 'interactionType', + LANGUAGE_MAP: 'languageMap', + LANGUAGE: 'language', + LENGTH: 'length', + LIKERT: 'likert', + MATCHING: 'matching', + MAX: 'max', + MBOX_SHA_1_SUM: 'mbox_sha1sum', + MBOX: 'mbox', + MEMBER: 'member', + MIN: 'min', + MORE_INFO: 'moreInfo', + NAME: 'name', + OBJECT_TYPE: 'objectType', + OBJECT: 'object', + OPEN_ID: 'openID', + OTHER: 'other', + PARENT: 'parent', + PERFORMANCE: 'performance', + PLATFORM: 'platform', + RAW: 'raw', + REGISTRATION: 'registration', + RESPONSE: 'response', + RESULT: 'result', + REVISION: 'revision', + SCALE: 'scale', + SCALED: 'scaled', + SCORE: 'score', + SEQUENCING: 'sequencing', + SHA2: 'sha2', + SOURCE: 'source', + STATEMENT_REF: 'statementRef', + STATEMENT: 'statement', + STEPS: 'steps', + STORED: 'stored', + SUB_CONTEXT: 'subContext', + SUCCESS: 'success', + TARGET: 'target', + TEAM: 'team', + TIMESTAMP: 'timestamp', + TYPE: 'type', + USAGE_TYPE: 'usageType', + VERB: 'verb', + VERSION: 'version' +}); + +const objectTypes = Object.freeze({ + GROUP: 'Group', + AGENT: 'Agent', + ACTIVITY: 'Activity', + STATEMENT_REF: 'StatementRef', + SUB_STATEMENT: 'SubStatement' +}); + +const xapiValidationIfiPropertyNames = Object.freeze([ + properties.ACCOUNT, + properties.MBOX_SHA_1_SUM, + properties.MBOX, + properties.OPEN_ID +]); + +const xApiValidObjectTypes = Object.freeze([ + objectTypes.GROUP, + objectTypes.AGENT, + objectTypes.ACTIVITY, + objectTypes.STATEMENT_REF, + objectTypes.SUB_STATEMENT +]); + +const xapiWhiteListProperties = Object.freeze({ + IFI: [ + properties.HOME_PAGE, + properties.NAME + ], + URI: [ + properties.ID, + properties.DISPLAY + ], + COMPONENT_ARRAY: [ + properties.ID, + properties.DESCRIPTION + ], + ACTIVITY_DEFINITION: [ + properties.NAME, + properties.DESCRIPTION, + properties.TYPE, + properties.MORE_INFO, + properties.EXTENSIONS, + properties.INTERACTION_TYPE, + properties.CORRECT_RESPONSES_PATTERN, + properties.CHOICES, + properties.SCALE, + properties.SOURCE, + properties.TARGET, + properties.STEPS + ], + ACTIVITY: [ + properties.OBJECT_TYPE, + properties.ID, + properties.DEFINITION + ], + STATEMENT_REF: [ + properties.ID, + properties.OBJECT_TYPE + ], + SCORE: [ + properties.SCALED, + properties.RAW, + properties.MIN, + properties.MAX + ], + RESULT: [ + properties.SCORE, + properties.SUCCESS, + properties.COMPLETION, + properties.RESPONSE, + properties.DURATION, + properties.EXTENSIONS + ], + ATTACHMENT: [ + properties.USAGE_TYPE, + properties.DISPLAY, + properties.DESCRIPTION, + properties.CONTENT_TYPE, + properties.LENGTH, + properties.SHA2, + properties.FILE_URL + ], + AGENT: [ + properties.OBJECT_TYPE, + properties.NAME, + properties.ACCOUNT, + properties.MBOX_SHA_1_SUM, + properties.MBOX, + properties.OPEN_ID + ], + GROUP: [ + properties.OBJECT_TYPE, + properties.NAME, + properties.MEMBER, + properties.ACCOUNT, + properties.MBOX_SHA_1_SUM, + properties.MBOX, + properties.OPEN_ID + ], + CONTEXT_ACTIVITIES: [ + properties.PARENT, + properties.GROUPING, + properties.CATEGORY, + properties.OTHER + ], + STATEMENT: [ + properties.ID, + properties.ACTOR, + properties.VERB, + properties.OBJECT, + properties.RESULT, + properties.CONTEXT, + properties.TIMESTAMP, + properties.STORED, + properties.AUTHORITY, + properties.VERSION, + properties.ATTACHMENTS + ], + SUB_STATEMENT: [ + properties.ACTOR, + properties.VERB, + properties.OBJECT, + properties.RESULT, + properties.CONTEXT, + properties.TIMESTAMP, + properties.ATTACHMENTS, + properties.OBJECT_TYPE + ], + EXTENSIONS: [ + properties.REGISTRATION, + properties.INSTRUCTOR, + properties.TEAM, + properties.CONTEXT_ACTIVITIES, + properties.REVISION, + properties.PLATFORM, + properties.LANGUAGE, + properties.STATEMENT, + properties.EXTENSIONS + ] +}); + +export {properties}; +export {objectTypes}; +export {xapiValidationIfiPropertyNames}; +export {xApiValidObjectTypes}; +export {xapiWhiteListProperties}; diff --git a/src/constants/regex.js b/src/constants/regex.js new file mode 100644 index 0000000..d2edb1d --- /dev/null +++ b/src/constants/regex.js @@ -0,0 +1,30 @@ +'use strict'; + +const xapiValidationRegex = Object.freeze({ + UUID: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i, + ISO_8601_DURATION: /^P((\d+([\.,]\d+)?Y)?(\d+([\.,]\d+)?M)?(\d+([\.,]\d+)?W)?(\d+([\.,]\d+)?D)?)?(T(\d+([\.,]\d+)?H)?(\d+([\.,]\d+)?M)?(\d+([\.,]\d+)?S)?)?$/, + ISO_8601_DATE_TIME: /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/, + MAILTO_URI: /^mailto:/, + CONTAINS_WHITESPACE: /\s/g, + SEMVER_1_P_0_P_0: /^((\d+)\.(\d+)\.(\d+))(?:-([\dA-Za-z\-]+))?$/, + BASE_64: /^(?:[A-Za-z0-9\+\/]{4})*(?:[A-Za-z0-9\+\/]{2}==|[A-Za-z0-9\+\/]{3}=|[A-Za-z0-9\+\/]{4})$/, + IRI: /^[a-z](?:[\-a-z0-9\+\.])*:(?:\/\/(?:(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:])*@)?(?:\[(?:(?:(?:[0-9a-f]{1,4}:){6}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|::(?:[0-9a-f]{1,4}:){5}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:[0-9a-f]{1,4}:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+[\-a-z0-9\._~!\$&'\(\)\*\+,;=:]+)\]|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}|(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=@])*)(?::[0-9]*)?(?:\/(?:(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@]))*)*|\/(?:(?:(?:(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@]))+)(?:\/(?:(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@]))*)*)?|(?:(?:(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@]))+)(?:\/(?:(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@]))*)*|(?!(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@])))(?:\?(?:(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@])|[\uE000-\uF8FF\uF0000-\uFFFFD|\u100000-\u10FFFD\/\?])*)?(?:\#(?:(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@])|[\/\?])*)?$/i, + BCP_47: /^(?:(en-GB-oed|i-(?:ami|bnn|default|enochian|hak|klingon|lux|mingo|navajo|pwn|tao|tay|tsu)|sgn-(?:BE-FR|BE-NL|CH-DE))|(art-lojban|cel-gaulish|no-(?:bok|nyn)|zh-(?:guoyu|hakka|min|min-nan|xiang)))$|^(x(?:-[0-9a-z]{1,8})+)$|^(?:((?:[a-z]{2,3}(?:(?:-[a-z]{3}){1,3})?)|[a-z]{4}|[a-z]{5,8})(?:-([a-z]{4}))?(?:-([a-z]{2}|[0-9]{3}))?((?:-(?:[a-z0-9]{5,8}|[0-9][a-z0-9]{3}))*)?((?:-[0-9a-wy-z](?:-[a-z0-9]{2,8}){1,})*)?(-x(?:-[0-9a-z]{1,8})+)?)$/i +}); + +const dateFormatRegexPositions = Object.freeze({ + YEAR: 1, + MONTH: 2, + DAY: 3, + HOUR: 4, + MINUTE: 5, + SECOND: 6, + MSECOND: 7, + ZONE: 8, + RELATIVE_TIME: 9, + TIME_ZONE_HOUR: 10, + TIME_ZONE_MINUTE: 11 +}); + +export {xapiValidationRegex}; +export {dateFormatRegexPositions}; diff --git a/src/utils/utils.js b/src/utils/utils.js new file mode 100644 index 0000000..ff5bbe2 --- /dev/null +++ b/src/utils/utils.js @@ -0,0 +1,66 @@ +'use strict'; + +const + IS_STRING = '[object String]', + IS_ARRAY = '[object Array]', + IS_BOOLEAN = '[object Boolean]', + IS_NUMBER = '[object Number]' +; + +var toString = Object.prototype.toString; +var xapiValidationUtils; + +xapiValidationUtils = { + isString(obj) { + return toString.call(obj) === IS_STRING; + }, + + isObject(obj) { + return obj === Object(obj); + }, + + isArray: Array.isArray || function(obj) { + return toString.call(obj) === IS_ARRAY; + }, + + isBoolean(obj) { + return obj === true || obj === false || toString.call(obj) === IS_BOOLEAN; + }, + + isNumber(obj) { + return toString.call(obj) === IS_NUMBER; + }, + + isDefined(obj) { + return (obj !== null || obj !== undefined); + }, + + isNonNullMapObject(target) { + return this.isDefined(target) && this.isObject(target) && !this.isArray(target); + }, + + isValidLanguageTag(target, validLanguageRegex) { + // TODO - use more precise 5646 handling, rather than this simplified BCP 47 regex, which combines RFC 5646 and RFC 4647. + // return this.isDefined(target) && this.isString(target) && xapiValidationRegex.BCP_47.test(target); + return this.isDefined(target) && this.isString(target) && validLanguageRegex.test(target); + }, + + addPropToTrace(trace, addendum) { + return this.isDefined(addendum) ? `${trace}.${addendum}` : trace; + }, + + addLookupToTrace(trace, key) { + return (!this.isDefined(key)) ? trace : (this.isNumber(key) ? `${trace}[${key}]` : `${trace}["${key}"]`); + }, + + localTraceToString(trace, addendum) { + return this.addPropToTrace(trace, addendum); + }, + + isGroup(actorOrGroup, groupType) { + // return (actorOrGroup.member !== null && actorOrGroup.member !== undefined) || actorOrGroup.objectType === objectTypes.GROUP; + return (actorOrGroup.member !== null && actorOrGroup.member !== undefined) || actorOrGroup.objectType === groupType; + } +}; + +export {xapiValidationUtils}; diff --git a/src/xapiValidator-old.js b/src/xapiValidator-old.js new file mode 100644 index 0000000..37ec62c --- /dev/null +++ b/src/xapiValidator-old.js @@ -0,0 +1,875 @@ +// UMD flavor "commonjsStrictGlobal.js" from https://github.com/umdjs/umd +(function (root, factory) { + "use strict"; + if (typeof exports === 'object') { + // CommonJS + factory(exports); + } else if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['exports'], function (exports) { + root.xapiValidator = exports; + factory(exports); + }); + } else { + // Browser globals + root.xapiValidator = {}; + factory(root.xapiValidator); + } +} (this, function (exports) { + "use strict"; + var MUST_VIOLATION = "MUST_VIOLATION", + SHOULD_VIOLATION = "SHOULD_VIOLATION", + MAY_VIOLATION = "MAY_VIOLATION", + toString = Object.prototype.toString, + uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i, + iso8601DurationRegex = /^P((\d+([\.,]\d+)?Y)?(\d+([\.,]\d+)?M)?(\d+([\.,]\d+)?W)?(\d+([\.,]\d+)?D)?)?(T(\d+([\.,]\d+)?H)?(\d+([\.,]\d+)?M)?(\d+([\.,]\d+)?S)?)?$/, + iso8601DateTimeRegex, + mailtoUriRegex = /^mailto:/, + semVer1p0p0Regex = /^((\d+)\.(\d+)\.(\d+))(?:-([\dA-Za-z\-]+))?$/, + base64Regex = /^(?:[A-Za-z0-9\+\/]{4})*(?:[A-Za-z0-9\+\/]{2}==|[A-Za-z0-9\+\/]{3}=|[A-Za-z0-9\+\/]{4})$/, + iriRegex, + bcp47Regex, + isArray, + ifiPropertyNames = ["mbox", "mbox_sha1sum", "openID", "account"], + cmiInteractionTypes = ["true-false", "choice", "fill-in", + "long-fill-in", "matching", "performance", + "sequencing", "likert", "numeric", + "other"]; + iriRegex = /^[a-z](?:[\-a-z0-9\+\.])*:(?:\/\/(?:(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:])*@)?(?:\[(?:(?:(?:[0-9a-f]{1,4}:){6}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|::(?:[0-9a-f]{1,4}:){5}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:[0-9a-f]{1,4}:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+[\-a-z0-9\._~!\$&'\(\)\*\+,;=:]+)\]|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}|(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=@])*)(?::[0-9]*)?(?:\/(?:(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@]))*)*|\/(?:(?:(?:(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@]))+)(?:\/(?:(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@]))*)*)?|(?:(?:(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@]))+)(?:\/(?:(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@]))*)*|(?!(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@])))(?:\?(?:(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@])|[\uE000-\uF8FF\uF0000-\uFFFFD|\u100000-\u10FFFD\/\?])*)?(?:\#(?:(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@])|[\/\?])*)?$/i; + + // 1 YYYY 2 MM 3 DD 4 HH 5 mm 6 ss 7 msec 8 Z 9 ± 10 tzHH 11 tzmm + iso8601DateTimeRegex = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/; + + bcp47Regex = /^(?:(en-GB-oed|i-(?:ami|bnn|default|enochian|hak|klingon|lux|mingo|navajo|pwn|tao|tay|tsu)|sgn-(?:BE-FR|BE-NL|CH-DE))|(art-lojban|cel-gaulish|no-(?:bok|nyn)|zh-(?:guoyu|hakka|min|min-nan|xiang)))$|^(x(?:-[0-9a-z]{1,8})+)$|^(?:((?:[a-z]{2,3}(?:(?:-[a-z]{3}){1,3})?)|[a-z]{4}|[a-z]{5,8})(?:-([a-z]{4}))?(?:-([a-z]{2}|[0-9]{3}))?((?:-(?:[a-z0-9]{5,8}|[0-9][a-z0-9]{3}))*)?((?:-[0-9a-wy-z](?:-[a-z0-9]{2,8}){1,})*)?(-x(?:-[0-9a-z]{1,8})+)?)$/i; + + function isString(obj) { + return toString.call(obj) === '[object String]'; + } + + function isObject(obj) { + return obj === Object(obj); + } + + isArray = Array.isArray || function (obj) { + return toString.call(obj) === '[object Array]'; + }; + + function isBoolean(obj) { + return obj === true || obj === false || toString.call(obj) === '[object Boolean]'; + } + + function isNumber(obj) { + return toString.call(obj) === '[object Number]'; + } + + function isNonNullMapObject(target) { + return target !== null && isObject(target) && !isArray(target); + } + + function isValidLanguageTag(target) { + // TODO - use more precise 5646 handling, rather than this simplified BCP 47 regex, which combines RFC 5646 and RFC 4647. + return target !== undefined && target !== null && isString(target) && bcp47Regex.test(target); + } + + function addPropToTrace(trace, addendum) { + if (addendum !== null && addendum !== undefined) { + return trace + "." + addendum; + } + return trace; + } + + function addLookupToTrace(trace, key) { + if (key === null || key === undefined) { + return trace; + } + if (isString(key)) { + return trace + "[\"" + key + "\"]"; + } + return trace + "[" + key + "]"; + } + + function localTraceToString(trace, addendum) { + return addPropToTrace(trace, addendum); + } + + function Report(instance, errors, version) { + this.instance = instance === null || instance === undefined ? null : instance; + this.errors = errors === null || errors === undefined ? [] : errors; + this.version = version; + } + + function ValidationError(trace, message, level) { + this.trace = trace; + this.message = message; + this.level = level; + } + + function makeV1Report(instance, errors) { + return new Report(instance, errors, "1.0.0"); + } + + function makeV1SingleErrorReport(instance, error) { + return makeV1Report(instance, error === null || error === undefined ? [] : + [error]); + } + + function validateAbsenceOfNonWhitelistedProperties(target, allowedProperties, trace, errors) { + var localErrors = errors || [], + localTrace = trace || "", + propertyName; + for (propertyName in target) { + if (target.hasOwnProperty(propertyName) && allowedProperties.indexOf(propertyName) === -1) { + localErrors.push(new ValidationError(addPropToTrace(localTrace, propertyName), "Unexpected property not permitted", MUST_VIOLATION)); + } + } + return localErrors; + } + + function validatePropertyIsString(parent, propertyName, trace, errors, isRequired, violationType) { + var localErrors = errors || [], + localTrace = trace || "", + propValue = parent[propertyName], + localViolationType = violationType || MUST_VIOLATION; + if (propValue !== undefined) { + if (propValue === null || !isString(propValue)) { + localErrors.push(new ValidationError(localTraceToString(localTrace, propertyName), propertyName + " property, if present, must be a string.", localViolationType)); + } + } else if (isRequired) { + localErrors.push(new ValidationError(localTraceToString(localTrace, propertyName), propertyName + " property was required to be a string but was absent.", localViolationType)); + } + return localErrors; + } + + function validatePropertyIsUri(target, propertyName, trace, errors, isRequired) { + var localErrors = errors || [], + localTrace = trace || "", + propValue = target[propertyName]; + if (propValue !== undefined) { + if (propValue === null || !isString(propValue)) { + localErrors.push(new ValidationError(localTraceToString(localTrace, propertyName), propertyName + " property, if present, must be a URI string.", MUST_VIOLATION)); + } else if (!iriRegex.test(propValue)) { + localErrors.push(new ValidationError(localTraceToString(localTrace, propertyName), propertyName + " property, if present, should be a IRI-like absolute URI per RFC 3987.", SHOULD_VIOLATION)); + } + } else if (isRequired) { + localErrors.push(new ValidationError(localTraceToString(localTrace, propertyName), propertyName + " property was required to be a URI string but was absent.", MUST_VIOLATION)); + } + return localErrors; + } + + function validatePropertyIsUrl(target, propertyName, trace, errors, isRequired) { + // TODO - check whether a formal URL format definition is recommended/enforced for xAPI + return validatePropertyIsString(target, propertyName, trace, errors, isRequired); + } + + function validatePropertyIsBoolean(parent, propertyName, trace, errors, isRequired) { + var localErrors = errors || [], + localTrace = trace || "", + propValue = parent[propertyName]; + if (propValue !== undefined) { + if (propValue === null || !isBoolean(propValue)) { + localErrors.push(new ValidationError(localTraceToString(localTrace, propertyName), propertyName + " property, if present, must be a Boolean.", MUST_VIOLATION)); + } + } else if (isRequired) { + localErrors.push(new ValidationError(localTraceToString(localTrace, propertyName), propertyName + " property was required to be a Boolean but was absent.", MUST_VIOLATION)); + } + return localErrors; + } + + function validatePropertyIsNumber(parent, propertyName, trace, errors, isRequired) { + var localErrors = errors || [], + localTrace = trace || "", + propValue = parent[propertyName]; + if (propValue !== undefined) { + if (propValue === null || !isNumber(propValue)) { + localErrors.push(new ValidationError(localTraceToString(localTrace, propertyName), propertyName + " property, if present, must be a Number.", MUST_VIOLATION)); + } + } else if (isRequired) { + localErrors.push(new ValidationError(localTraceToString(localTrace, propertyName), propertyName + " property was required to be a Number but was absent.", MUST_VIOLATION)); + } + return localErrors; + } + + function validateIFIProperties(target, trace, errors) { + var localErrors = errors || [], + localTrace = trace || "", + accountTrace; + if (target.mbox !== undefined && target.mbox !== null) { + if (!isString(target.mbox)) { + localErrors.push(new ValidationError(localTraceToString(localTrace, "mbox"), "mbox property was required to be a mailto URI string but was not a string at all.", MUST_VIOLATION)); + } else if (!mailtoUriRegex.test(target.mbox)) { + localErrors.push(new ValidationError(localTraceToString(localTrace, "mbox"), "mbox property was required to be a mailto URI string but did not match the mailto format.", MUST_VIOLATION)); + } + } + validatePropertyIsString(target, "mbox_sha1sum", localTrace, localErrors, false); + validatePropertyIsUri(target, "openID", localTrace, localErrors, false); + if (target.account !== undefined && target.account !== null) { + accountTrace = addPropToTrace(localTrace, "account"); + validatePropertyIsUri(target.account, "homePage", accountTrace, localErrors, true); + validatePropertyIsString(target.account, "name", accountTrace, localErrors, true); + validateAbsenceOfNonWhitelistedProperties(target.account, ["homePage", "name"], accountTrace, localErrors); + } + return localErrors; + } + + function getIFIs(target) { + var ifis = [], + i, + propName, + propValue; + if (target === null || target === undefined) { + return ifis; + } + for (i = 0; i < ifiPropertyNames.length; i += 1) { + propName = ifiPropertyNames[i]; + propValue = target[propName]; + if (propValue !== undefined && propValue !== null) { + ifis.push({ key: propName, value: propValue }); + } + } + return ifis; + } + + function getIFICount(target) { + return getIFIs(target).length; + } + + function validateExtensions(extensions, trace, errors) { + var localErrors = errors || [], + localTrace = trace || "extensions"; + if (extensions === undefined) { + return localErrors; + } + if (!isNonNullMapObject(extensions)) { + localErrors.push(new ValidationError(localTrace, "If present, the extensions property must be a non-null map object.", MUST_VIOLATION)); + } + // TODO - double-check what further enforceable constraints exist on extension object properties + return localErrors; + } + + function validateLanguageMap(languageMap, trace, errors) { + var localErrors = errors || [], + localTrace = trace || "languageMap", + propName, + mappedValue; + if (languageMap === undefined) { + return localErrors; + } + if (!isNonNullMapObject(languageMap)) { + localErrors.push(new ValidationError(addPropToTrace(localTrace), "Language Maps, when present, must be non-null map objects", MUST_VIOLATION)); + return localErrors; + } + for (propName in languageMap) { + if (languageMap.hasOwnProperty(propName)) { + + if (!isValidLanguageTag(propName)) { + localErrors.push(new ValidationError(addPropToTrace(localTrace, propName), "Language Map key " + propName + "does not conform to RFC 5646.", MUST_VIOLATION)); + } + mappedValue = languageMap[propName]; + if (mappedValue === null || mappedValue === undefined || !isString(mappedValue)) { + localErrors.push(new ValidationError(addLookupToTrace(localTrace, propName), "Language Map value for key " + propName + "should be a String, but was not.", MUST_VIOLATION)); + } + } + } + return localErrors; + } + + function validateVerb(verb, trace, errors) { + var localErrors = errors || [], + localTrace = trace || "verb"; + if (verb === undefined) { + localErrors.push(new ValidationError(localTraceToString(localTrace), "verb property must be provided.", MUST_VIOLATION)); + return localErrors; + } + if (!isNonNullMapObject(verb)) { + localErrors.push(new ValidationError(localTraceToString(localTrace), "verb property value must a non-null map object.", MUST_VIOLATION)); + return localErrors; + } + validatePropertyIsUri(verb, "id", localTrace, localErrors, true); + if (verb.display === undefined) { + localErrors.push(new ValidationError(addPropToTrace(localTrace, "display"), "display property should be provided.", SHOULD_VIOLATION)); + } else { + validateLanguageMap(verb.display, addPropToTrace(localTrace, "display"), localErrors); + } + + validateAbsenceOfNonWhitelistedProperties(verb, ["id", "display"], localTrace, localErrors); + + return localErrors; + } + + function validateInteractionComponentArray(components, interactionType, allowedInteractionTypes, trace, errors) { + var localErrors = errors || [], + localTrace = trace || "interactionComponents", + isAllowedComponentType = allowedInteractionTypes.indexOf(interactionType) !== -1, + ids = [], + interactionComponent, + perComponentTrace, + i; + if (isAllowedComponentType && components !== undefined) { + if (components === null || !isArray(components)) { + localErrors.push(new ValidationError(localTrace, "This interaction component collection property should be an array.", SHOULD_VIOLATION)); + } else { + for (i = 0; i < components.length; i += 1) { + interactionComponent = components[i]; + perComponentTrace = addLookupToTrace(localTrace, i); + if (!isNonNullMapObject(interactionComponent)) { + localErrors.push(new ValidationError(perComponentTrace, "This interaction component collection member must be a non-null map object", MUST_VIOLATION)); + } else { + validatePropertyIsString(interactionComponent, "id", perComponentTrace, localErrors, true, MUST_VIOLATION); + if (ids.indexOf(interactionComponent.id) !== -1) { + localErrors.push(new ValidationError(addPropToTrace(perComponentTrace, "id"), "id properties must be unique within each interaction component array", MUST_VIOLATION)); + } else { + ids.push(interactionComponent.id); + } + if (interactionComponent.id && /\s/g.test(interactionComponent.id)) { + localErrors.push(new ValidationError(addPropToTrace(perComponentTrace, "id"), "id properties on interaction components should not contain whitespace", SHOULD_VIOLATION)); + } + validateLanguageMap(interactionComponent.description, addPropToTrace(perComponentTrace, "description"), localErrors); + + validateAbsenceOfNonWhitelistedProperties(interactionComponent, ["id", "description"], perComponentTrace, localErrors); + } + } + } + } else if (interactionType && components) { + localErrors.push(new ValidationError(localTrace, "This interaction component collection property is not associated with the present interactionType of " + interactionType, SHOULD_VIOLATION)); + } + return localErrors; + } + + function validateActivityDefintion(definition, trace, errors) { + var localErrors = errors || [], + localTrace = trace || "definition", + correctResponsesPatternTrace = addPropToTrace(localTrace, "correctResponsesPattern"), + crpLen, + i, + crpItem; + + if (!isNonNullMapObject(definition)) { + localErrors.push(new ValidationError(addPropToTrace(localTrace), "definitions, when present, must be map objects", MUST_VIOLATION)); + return localErrors; + } + + validateLanguageMap(definition.name, addPropToTrace(localTrace, "name"), localErrors); + validateLanguageMap(definition.description, addPropToTrace(localTrace, "description"), localErrors); + + validatePropertyIsUri(definition, "type", localTrace, localErrors, false); + validatePropertyIsUrl(definition, "moreInfo", localTrace, localErrors, false); + validateExtensions(definition.extensions, addPropToTrace(localTrace, "extensions"), localErrors); + + if (definition.interactionType !== undefined) { + if (definition.type !== "http://adlnet.gov/expapi/activities/cmi.interaction") { + localErrors.push(new ValidationError(localTraceToString(localTrace, "type"), "Interaction Activity Definitions should have a type property of \"http://adlnet.gov/expapi/activities/cmi.interaction\" ", SHOULD_VIOLATION)); + } + if (cmiInteractionTypes.indexOf(definition.interactionType) === -1) { + localErrors.push(new ValidationError(localTraceToString(localTrace, "interactionType"), "If present, the interactionType value must be a CMI interaction type option.", MUST_VIOLATION)); + } + } + + if (definition.correctResponsesPattern !== undefined) { + if (!isArray(definition.correctResponsesPattern)) { + localErrors.push(new ValidationError(correctResponsesPatternTrace, "If present, the correctResponsesPattern value must be an Array of strings.", MUST_VIOLATION)); + } else { + crpLen = definition.correctResponsesPattern.length; + for (i = 0; i < crpLen; i+=1) { + crpItem = definition.correctResponsesPattern[i]; + if (crpItem === null || crpItem === undefined || !isString(crpItem)) { + localErrors.push(new ValidationError(addLookupToTrace(correctResponsesPatternTrace, i), "correctResponsesPattern items must be strings.", MUST_VIOLATION)); + } + } + } + } + validateInteractionComponentArray(definition.choices, definition.interactionType, ["choice", "sequencing"], addPropToTrace(localTrace, "choices"), localErrors); + validateInteractionComponentArray(definition.scale, definition.interactionType, ["likert"], addPropToTrace(localTrace, "scale"), localErrors); + validateInteractionComponentArray(definition.source, definition.interactionType, ["matching"], addPropToTrace(localTrace, "source"), localErrors); + validateInteractionComponentArray(definition.target, definition.interactionType, ["matching"], addPropToTrace(localTrace, "target"), localErrors); + validateInteractionComponentArray(definition.steps, definition.interactionType, ["performance"], addPropToTrace(localTrace, "steps"), localErrors); + + validateAbsenceOfNonWhitelistedProperties(definition, + ["name", "description", "type", "moreInfo", "extensions", "interactionType", "correctResponsesPattern", "choices", "scale", "source", "target", "steps"], + localTrace, localErrors); + return localErrors; + } + + function validateActivity(activity, trace, errors) { + var localErrors = errors || [], + localTrace = trace || "activity"; + if (!isNonNullMapObject(activity)) { + localErrors.push(new ValidationError(localTraceToString(localTrace), "Activities must be non-null map objects", MUST_VIOLATION)); + return localErrors; + } + validatePropertyIsUri(activity, "id", localTrace, localErrors, true); + + if (activity.definition !== undefined) { + validateActivityDefintion(activity.definition, addPropToTrace(localTrace, "definition"), localErrors); + } + validateAbsenceOfNonWhitelistedProperties(activity, ["objectType", "id", "definition"], localTrace, localErrors); + return localErrors; + } + + function validateStatementRef(statementRef, trace, errors) { + var localErrors = errors || [], + localTrace = trace || "statementRef"; + if (!isNonNullMapObject(statementRef)) { + localErrors.push(new ValidationError(localTraceToString(localTrace), "StatementRef instances must be non-null map objects.", MUST_VIOLATION)); + return localErrors; + } + if (statementRef.objectType !== "StatementRef") { + localErrors.push(new ValidationError(addPropToTrace(localTrace, "objectType"), "objectType property value must be 'StatementRef' for statement reference objects.", MUST_VIOLATION)); + } + if (!statementRef.id || !uuidRegex.test(statementRef.id)) { + localErrors.push(new ValidationError(addPropToTrace(localTrace, "id"), "id property value must be a valid UUID string for statement reference objects.", MUST_VIOLATION)); + } + validateAbsenceOfNonWhitelistedProperties(statementRef, ["id", "objectType"], localTrace, localErrors); + return localErrors; + } + + + function validateScore(score, trace, errors) { + var localErrors = errors || [], + localTrace = trace || "score"; + if (score === undefined) { + return localErrors; + } + validatePropertyIsNumber(score, "scaled", localTrace, localErrors, false); + if (score.scaled !== undefined) { + if (score.scaled < 0 || score.scaled > 1) { + localErrors.push(new ValidationError(addPropToTrace(localTrace, "scaled"), "If present, the scaled property value must be between 0 and 1", MUST_VIOLATION)); + } + } + if (score.min !== undefined) { + validatePropertyIsNumber(score, "min", localTrace, localErrors, false); + if (score.raw !== undefined && score.raw < score.min) { + localErrors.push(new ValidationError(addPropToTrace(localTrace, "raw"), "If both 'raw' and 'min' are present, the raw property value should be greater than min", MUST_VIOLATION)); + } + if (score.max !== undefined && score.max < score.min) { + localErrors.push(new ValidationError(addPropToTrace(localTrace, "max"), "If both 'max' and 'min' are present, the max property value should be greater than min", MUST_VIOLATION)); + } + } + if (score.max !== undefined) { + validatePropertyIsNumber(score, "max", localTrace, localErrors, false); + if (score.raw !== undefined && score.raw > score.max) { + localErrors.push(new ValidationError(addPropToTrace(localTrace, "raw"), "If both 'raw' and 'max' are present, the raw property value should be less than max", MUST_VIOLATION)); + } + } + validatePropertyIsNumber(score, "raw", localTrace, localErrors, false); + validateAbsenceOfNonWhitelistedProperties(score, ["scaled", "raw", "min", "max"], localTrace, localErrors); + return localErrors; + } + + function validateResult(result, trace, errors) { + var localErrors = errors || [], + localTrace = trace || "result"; + if (result === undefined) { + return localErrors; + } + if (!isNonNullMapObject(result)) { + localErrors.push(new ValidationError(addPropToTrace(localTrace), "If present, the result must be a map object", MUST_VIOLATION)); + return localErrors; + } + validateScore(result.score, addPropToTrace(localTrace, "score"), localErrors); + validatePropertyIsBoolean(result, "success", localTrace, localErrors, false); + validatePropertyIsBoolean(result, "completion", localTrace, localErrors, false); + validatePropertyIsString(result, "response", localTrace, localErrors, false); + validateExtensions(result.extensions, addPropToTrace(localTrace, "extensions"), localErrors); + if (result.duration !== undefined && (result.duration === null || !isString(result.duration) || !iso8601DurationRegex.test(result.duration))) { + localErrors.push(new ValidationError(addPropToTrace(localTrace, "duration"), "If present, the duration property value must be an ISO 8601 duration", MUST_VIOLATION)); + } + validateAbsenceOfNonWhitelistedProperties(result, ["score", "success", "completion", "response", "duration", "extensions"], localTrace, localErrors); + + return localErrors; + } + + + function validatePropertyIsISO8601String(parent, propertyName, trace, errors) { + var localErrors = errors || [], + localTrace = trace || "datetime", + matched, + datetime = parent[propertyName]; + if (datetime === undefined) { + return localErrors; + } + if (datetime === null || !isString(datetime)) { + localErrors.push(new ValidationError(localTraceToString(localTrace, propertyName), "This property must be a string value, but was null or another value type.", MUST_VIOLATION)); + return localErrors; + } + matched = iso8601DateTimeRegex.exec(datetime); + if (matched) { + if (!(matched[8] || (matched[9] && matched[10]))) { + localErrors.push(new ValidationError(localTraceToString(localTrace, propertyName), "ISO 8601 date time strings used in the xAPI should include time zone information.", SHOULD_VIOLATION)); + } + } else { + localErrors.push(new ValidationError(localTraceToString(localTrace, propertyName), "This property's string value must be conformant to ISO 8601 for Date Times.", MUST_VIOLATION)); + } + + return localErrors; + } + + + + function validateVersion(version, trace, errors) { + var localErrors = errors || [], + localTrace = trace || "version"; + if (version === undefined) { + return localErrors; + } + if (version === null || !isString(version) || !semVer1p0p0Regex.test(version)) { + localErrors.push(new ValidationError(localTraceToString(localTrace), "version must be a non-null string that complies with Semantic Versioning 1.0.0", MUST_VIOLATION)); + } + return localErrors; + } + + function validateAttachmentObject(attachment, trace, errors) { + var localErrors = errors || [], + localTrace = trace || "attachment"; + if (!isNonNullMapObject(attachment)) { + localErrors.push(new ValidationError(localTraceToString(localTrace), "attachment instances must be non-null map objects.", MUST_VIOLATION)); + return localErrors; + } + if (attachment.display === undefined) { + localErrors.push(new ValidationError(localTraceToString(localTrace, "display"), "display property must be provided.", MUST_VIOLATION)); + } else { + validateLanguageMap(attachment.display, addPropToTrace(localTrace, "display"), localErrors); + } + validateLanguageMap(attachment.description, addPropToTrace(localTrace, "description"), localErrors); + + validatePropertyIsUri(attachment, "usageType", localTrace, localErrors, true, MUST_VIOLATION); + validatePropertyIsUri(attachment, "fileUrl", localTrace, localErrors, false, MUST_VIOLATION); + + // TODO - more complete validation for Internet Media Type via RFC 2046 + validatePropertyIsString(attachment, "contentType", localTrace, localErrors, true, MUST_VIOLATION); + if (attachment.length === undefined || attachment.length === null || !isNumber(attachment.length) || !(attachment.length % 1 === 0)) { + localErrors.push(new ValidationError(localTraceToString(localTrace, "length"), "length property must be provided with an integer value", MUST_VIOLATION)); + } + + if (attachment.sha2 === undefined) { + localErrors.push(new ValidationError(localTraceToString(localTrace, "sha2"), "sha2 property must be provided on attachment objects", MUST_VIOLATION)); + } else if (attachment.sha2 === null || !isString(attachment.sha2) || !base64Regex.test(attachment.sha2)) { + localErrors.push(new ValidationError(localTraceToString(localTrace, "sha2"), "sha2 property must contain a string with bas64 contents", MUST_VIOLATION)); + } + + validateAbsenceOfNonWhitelistedProperties(attachment, ["usageType", "display", "description", "contentType", "length", "sha2", "fileUrl"], localTrace, localErrors); + return localErrors; + } + + function validateAttachments(attachments, trace, errors) { + var localErrors = errors || [], + localTrace = trace || "attachments", + numAttachments, + i; + if (attachments === undefined) { + return localErrors; + } + if (attachments === null || !isArray(attachments)) { + localErrors.push(new ValidationError(localTraceToString(localTrace), "attachments must be a non-null Array.", MUST_VIOLATION)); + return localErrors; + } + numAttachments = attachments.length; + for (i = 0; i < numAttachments; i+=1) { + validateAttachmentObject(attachments[i], addLookupToTrace(localTrace, i), localErrors); + } + return localErrors; + } + + function isGroup(actorOrGroup) { + return (actorOrGroup.member !== null && actorOrGroup.member !== undefined) || actorOrGroup.objectType === "Group"; + } + + function validateAgent(agent, trace, errors) { + var localErrors = errors || [], + localTrace = trace || "agent", + ifiCount; + if (!isNonNullMapObject(agent)) { + localErrors.push(new ValidationError(localTraceToString(localTrace), "Agent must be a non-null map object", MUST_VIOLATION)); + return localErrors; + } + + ifiCount = getIFICount(agent); + + if (ifiCount !== 1) { + localErrors.push(new ValidationError(localTraceToString(localTrace), "Exactly one Inverse Functional Identifier property must be specified.", MUST_VIOLATION)); + } + if (agent.objectType === "Group") { + localErrors.push(new ValidationError(localTraceToString(localTrace), "Invalid object with characteristics of a Group when an Agent was expected.", MUST_VIOLATION)); + } + validateIFIProperties(agent, localTrace, localErrors); + validatePropertyIsString(agent, "name", localTrace, localErrors, false); + + validateAbsenceOfNonWhitelistedProperties(agent, ["objectType", "name"].concat(ifiPropertyNames), localTrace, localErrors); + + return localErrors; + } + + function validateGroup(group, trace, errors) { + var localErrors = errors || [], + localTrace = trace || "group", + memberTrace = addPropToTrace(localTrace, "member"), + ifiCount, + numMembers, + i; + if (!isNonNullMapObject(group)) { + localErrors.push(new ValidationError(localTraceToString(localTrace), "Group must be a non-null map object", MUST_VIOLATION)); + return localErrors; + } + + ifiCount = getIFICount(group); + if (ifiCount === 0) { + if (group.member === null || group.member === undefined) { + localErrors.push(new ValidationError(memberTrace, "member property must be provided for Anonymous Groups.", MUST_VIOLATION)); + } + } else if (ifiCount > 1) { + localErrors.push(new ValidationError(localTraceToString(localTrace), "Only one Inverse Functional Identifier property must be specified.", MUST_VIOLATION)); + } + validateIFIProperties(group, localTrace, localErrors); + validatePropertyIsString(group, "name", localTrace, localErrors, false); + + if (group.member !== undefined) { + if (group.member === null || !isArray(group.member)) { + localErrors.push(new ValidationError(localTraceToString(localTrace, "member"), "If present, the member property of a Group must be an Array", MUST_VIOLATION)); + } else { + numMembers = group.member.length; + for (i = 0; i < numMembers; i+=1) { + validateAgent(group.member[i], addLookupToTrace(memberTrace, i), localErrors); + } + } + } + + validateAbsenceOfNonWhitelistedProperties(group, ["objectType", "name", "member"].concat(ifiPropertyNames), localTrace, localErrors); + + return localErrors; + } + + function validateActor(actor, trace, errors) { + var localErrors = errors || [], + localTrace = trace || "actor"; + if (actor === null || actor === undefined) { + localErrors.push(new ValidationError(localTraceToString(localTrace), "Actor must be provided.", MUST_VIOLATION)); + return localErrors; + } + if (isGroup(actor)) { + validateGroup(actor, localTrace, localErrors); + } else { + validateAgent(actor, localTrace, localErrors); + } + return localErrors; + } + + function validateAuthority(authority, trace, errors) { + var localErrors = errors || [], + localTrace = trace || "authority"; + if (authority === undefined) { + return localErrors; + } + if (!isNonNullMapObject(authority)) { + localErrors.push(new ValidationError(localTraceToString(localTrace), "If present, the authority property must be a non-null map object.", MUST_VIOLATION)); + return localErrors; + } + if (isGroup(authority)) { + validateGroup(authority, localTrace, localErrors); + if (!authority.member || !authority.member.length || authority.member.length !== 2) { + localErrors.push(new ValidationError(localTraceToString(localTrace, "member"), "If used as a Group, the authority property must contain a member property that is an array containing exactly two Agent objects.", MUST_VIOLATION)); + } + } else { + validateAgent(authority, localTrace, localErrors); + } + return localErrors; + } + + function validateContextActivitySubContext(subContext, trace, errors) { + var localErrors = errors || [], + localTrace = trace || "subContext", + numActivities, + i; + if (subContext === undefined) { + return localErrors; + } + if (subContext === null) { + localErrors.push(new ValidationError(localTraceToString(localTrace), "Context Activities property values must not be null.", MUST_VIOLATION)); + } else if (isArray(subContext)) { + numActivities = subContext.length; + for (i = 0; i < numActivities; i+=1) { + validateActivity(subContext[i], addLookupToTrace(localTrace, i), localErrors); + } + } else if (isObject(subContext)) { + localErrors.push(new ValidationError(localTraceToString(localTrace), "Context Activities property values should prefer to be an array of Activities rather than a single Activity object.", SHOULD_VIOLATION)); + validateActivity(subContext, localTrace, localErrors); + } else { + localErrors.push(new ValidationError(localTraceToString(localTrace), "Context Activities property values must be an array of Activity Objects or a single Activity Object.", MUST_VIOLATION)); + } + return localErrors; + } + + function validateContextActivities(contextActivities, trace, errors) { + var localErrors = errors || [], + localTrace = trace || "contextActivities"; + if (contextActivities === undefined) { + return localErrors; + } + if (!isNonNullMapObject(contextActivities)) { + localErrors.push(new ValidationError(localTraceToString(localTrace), "The Context Activities instances must be a non-null map object.", MUST_VIOLATION)); + return localErrors; + } + validateContextActivitySubContext(contextActivities.parent, addPropToTrace(localTrace, "parent"), localErrors); + validateContextActivitySubContext(contextActivities.grouping, addPropToTrace(localTrace, "grouping"), localErrors); + validateContextActivitySubContext(contextActivities.category, addPropToTrace(localTrace, "category"), localErrors); + validateContextActivitySubContext(contextActivities.other, addPropToTrace(localTrace, "other"), localErrors); + + validateAbsenceOfNonWhitelistedProperties(contextActivities, ["parent", "grouping", "category", "other"], localTrace, localErrors); + return localErrors; + } + + function validateContext(context, trace, errors, statementObjectObjectType) { + var localErrors = errors || [], + localTrace = trace || "context"; + if (context === undefined) { + return localErrors; + } + if (!isNonNullMapObject(context)) { + localErrors.push(new ValidationError(localTrace, "If present, the context must be a non-null map object.", MUST_VIOLATION)); + return localErrors; + } + if (context.registration !== undefined && (context.registration === null || !isString(context.registration) || !uuidRegex.test(context.registration))) { + localErrors.push(new ValidationError(localTraceToString(localTrace, "registration"), "If present, the registration property must be a UUID string.", MUST_VIOLATION)); + } + if (["Group", "Agent"].indexOf(statementObjectObjectType) !== -1) { + if (context.revision !== undefined) { + localErrors.push(new ValidationError(localTraceToString(localTrace, "revision"), "The revision property must not be used if the Statement's Object is an Agent or Group.", MUST_VIOLATION)); + } + if (context.platform !== undefined) { + localErrors.push(new ValidationError(localTraceToString(localTrace, "platform"), "The platform property must not be used if the Statement's Object is an Agent or Group.", MUST_VIOLATION)); + } + } + + validatePropertyIsString(context, "revision", localTrace, localErrors, false, MUST_VIOLATION); + validatePropertyIsString(context, "platform", localTrace, localErrors, false, MUST_VIOLATION); + if (context.team !== undefined) { + validateGroup(context.team, addPropToTrace(localTrace, "team"), localErrors); + } + if (context.contextActivities !== undefined) { + validateContextActivities(context.contextActivities, addPropToTrace(localTrace, "contextActivities"), localErrors); + } + if (context.language !== undefined && !isValidLanguageTag(context.language)) { + localErrors.push(new ValidationError(localTraceToString(localTrace, "language"), "The language property must be encoded as an RFC 5646 compliant string, but was not.", MUST_VIOLATION)); + } + if (context.statement !== undefined) { + validateStatementRef(context.statement, addPropToTrace(localTrace, "statement"), localErrors); + } + + if (context.instructor !== undefined) { + if (isGroup(context.instructor)) { + validateGroup(context.instructor, addPropToTrace(localTrace, "instructor"), localErrors); + } else { + validateAgent(context.instructor, addPropToTrace(localTrace, "instructor"), localErrors); + } + } + validateExtensions(context.extensions, addPropToTrace(localTrace, "extensions"), localErrors); + validateAbsenceOfNonWhitelistedProperties(context, + ["registration", "instructor", "team", "contextActivities", "revision", "platform", "language", "statement", "extensions"], + localTrace, localErrors); + return localErrors; + } + + function validateObject(object, trace, errors, isWithinSubStatement) { + var localErrors = errors || [], + localTrace = trace || "object", + objectType; + if (object === undefined) { + localErrors.push(new ValidationError(localTraceToString(localTrace), "object property must be provided.", MUST_VIOLATION)); + return localErrors; + } + if (!isNonNullMapObject(object)) { + localErrors.push(new ValidationError(localTraceToString(localTrace), "object property must be a non-null map object.", MUST_VIOLATION)); + return localErrors; + } + validatePropertyIsString(object, "objectType", localTrace, localErrors, true, SHOULD_VIOLATION); + objectType = object.objectType || "Activity"; + if (objectType === "Activity") { + validateActivity(object, localTrace, localErrors); + } else if (objectType === "Agent") { + validateAgent(object, localTrace, localErrors); + } else if (objectType === "Group") { + validateGroup(object, localTrace, localErrors); + } else if (objectType === "StatementRef") { + validateStatementRef(object, localTrace, localErrors); + } else if (objectType === "SubStatement") { + if (isWithinSubStatement) { + localErrors.push(new ValidationError(localTraceToString(localTrace, "objectType"), "A SubStatement must not contain a SubStatement", MUST_VIOLATION)); + } + validateStatement(object, localTrace, localErrors, true); + } else { + localErrors.push(new ValidationError(localTraceToString(localTrace, "objectType"), "object's objectType did not match a valid option ['Activity', 'Agent', 'Group', 'StatementRef', 'SubStatement']", MUST_VIOLATION)); + } + return localErrors; + } + + function validateStatement(statement, trace, errors, isSubStatement) { + var localErrors = errors || [], + localTrace = trace || "statement", + statementObjectObjectType, + whitelistedProperties = ["id", "actor", "verb", "object", "result", "context", "timestamp", "stored", "authority", "version", "attachments"]; + + if (!isNonNullMapObject(statement)) { + localErrors.push(new ValidationError(localTraceToString(localTrace), "Statements must be non-null map objects", MUST_VIOLATION)); + return localErrors; + } + + if (!isSubStatement) { + if (statement.id === null || statement.id === undefined || !isString(statement.id)) { + localErrors.push(new ValidationError(localTraceToString(localTrace, "id"), "Ids should be generated by the Activity Provider, and must be generated by the LRS", SHOULD_VIOLATION)); + } else if (!uuidRegex.test(statement.id)) { + localErrors.push(new ValidationError(localTraceToString(localTrace, "id"), "Id was not a valid UUID", MUST_VIOLATION)); + } + } else { + whitelistedProperties = ["actor", "verb", "object", "result", "context", "timestamp", "attachments", "objectType"]; + } + + validateActor(statement.actor, addPropToTrace(localTrace, "actor"), localErrors); + validateVerb(statement.verb, addPropToTrace(localTrace, "verb"), localErrors); + validateObject(statement.object, addPropToTrace(localTrace, "object"), localErrors, isSubStatement); + validateResult(statement.result, addPropToTrace(localTrace, "result"), localErrors); + + statementObjectObjectType = statement.object && statement.object.objectType ? statement.object.objectType : "Activity"; + validateContext(statement.context, addPropToTrace(localTrace, "context"), localErrors, statementObjectObjectType); + validatePropertyIsISO8601String(statement, "timestamp", localTrace, localErrors); + validatePropertyIsISO8601String(statement, "stored", localTrace, localErrors); + + validateAuthority(statement.authority, addPropToTrace(localTrace, "authority"), localErrors); + validateVersion(statement.version, addPropToTrace(localTrace, "version"), localErrors); + validateAttachments(statement.attachments, addPropToTrace(localTrace, "attachments"), localErrors); + + validateAbsenceOfNonWhitelistedProperties(statement, whitelistedProperties, localTrace, localErrors); + + return localErrors; + } + + function makeStatementReport(statement) { + var localErrors = []; + validateStatement(statement, "statement", localErrors, false); + return makeV1Report(statement, localErrors); + } + + function validateAmbiguousTypeStatement(statement) { + var statementObject; + if (statement === undefined) { + return makeV1SingleErrorReport(null, new ValidationError("statement", "No statement argument provided.", MUST_VIOLATION)); + } + if (statement === null) { + return makeV1SingleErrorReport(null, new ValidationError("statement", "Null statement argument provided.", MUST_VIOLATION)); + } + if (isString(statement)) { + try { + statementObject = JSON.parse(statement); + if (statementObject === null || !isObject(statementObject) || isArray(statementObject)) { + return makeV1SingleErrorReport(statementObject, new ValidationError("statement", "Null or non-object statement value parsed from provided statment JSON.", MUST_VIOLATION)); + } + } catch (e) { + return makeV1SingleErrorReport(statementObject, new ValidationError("statement", "Invalid JSON. The statement could not be parsed: " + e.message, MUST_VIOLATION)); + } + return makeStatementReport(statementObject); + } + if (isObject(statement) && !isArray(statement)) { + return makeStatementReport(statement); + } + return makeV1SingleErrorReport(null, new ValidationError("statement", "Statement argument provided was not a valid object or a valid JSON string.", MUST_VIOLATION)); + } + + exports.validateStatement = validateAmbiguousTypeStatement; +})); diff --git a/src/xapiValidator.js b/src/xapiValidator.js new file mode 100644 index 0000000..9311e2c --- /dev/null +++ b/src/xapiValidator.js @@ -0,0 +1,1286 @@ +'use strict'; + +import {properties, objectTypes, xapiValidationIfiPropertyNames, xApiValidObjectTypes, xapiWhiteListProperties} from './constants/properties'; +import {xapiErrorLevels, xapiValidationErrors} from './constants/errors'; +import {xapiValidationInteractionTypes} from './constants/interaction-types'; +import {xapiValidationRegex, dateFormatRegexPositions} from './constants/regex'; +import {xapiGeneral} from './constants/general'; +import {xapiValidationUtils} from './utils/utils'; + +var xapiValidation; + +function makeV1Report(instance, errors) { + var version; + + instance = instance || null; + errors = errors || null; + version = xapiGeneral.FIRST_REPORT_VERSTION; + return {instance, errors, version}; +} + +function makeV1SingleErrorReport(instance, error) { + return makeV1Report(instance, error === null || error === undefined ? [] : [error]); +} + +function validateAbsenceOfNonWhitelistedProperties(target, allowedProperties, trace, errors) { + var localErrors, localTrace, propertyName; + + localErrors = errors || []; + localTrace = trace || ''; + + for (propertyName in target) { + if (target.hasOwnProperty(propertyName) && allowedProperties.indexOf(propertyName) === xapiGeneral.NO_INDEX_FOUND) { + localErrors.push({ + trace: xapiValidationUtils.addPropToTrace(localTrace, propertyName), + message: xapiValidationErrors.UNEXPECTED, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + } + + return localErrors; +} + +function validatePropertyIsString(parent, propertyName, trace, errors, isRequired, violationType) { + var localErrors, localTrace, propValue, localViolationType; + + localErrors = errors || []; + localTrace = trace || ''; + propValue = parent[propertyName], + localViolationType = violationType || xapiErrorLevels.MUST_VIOLATION; + + if (propValue !== undefined) { + if (propValue === null || !xapiValidationUtils.isString(propValue)) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace, propertyName), + message: `${propertyName} ${xapiValidationErrors.MUST_BE_STRING}`, + level: localViolationType + }); + } + } else if (isRequired) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace, propertyName), + message: `${propertyName} ${xapiValidationErrors.MUST_BE_PRESENT}`, + level: localViolationType + }); + } + + return localErrors; +} + +function validatePropertyIsUri(target, propertyName, trace, errors, isRequired) { + var localErrors, localTrace, propValue; + + localErrors = errors || []; + localTrace = trace || ''; + propValue = target[propertyName]; + + if (propValue !== undefined) { + if (propValue === null || !xapiValidationUtils.isString(propValue)) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace, propertyName), + message: `${propertyName} ${xapiValidationErrors.MUST_BE_URI_STRING}`, + level: xapiErrorLevels.MUST_VIOLATION + }); + } else if (!xapiValidationRegex.IRI.test(propValue)) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace, propertyName), + message: `${propertyName} ${xapiValidationErrors.MUST_BE_IRI_STRING}`, + level: xapiErrorLevels.SHOULD_VIOLATION + }); + } + } else if (isRequired) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace, propertyName), + message: `${propertyName} ${xapiValidationErrors.MUST_BE_URI_PRESENT}`, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + return localErrors; +} + +function validatePropertyIsUrl(target, propertyName, trace, errors, isRequired) { + // TODO - check whether a formal URL format definition is recommended/enforced for xAPI + return validatePropertyIsString(target, propertyName, trace, errors, isRequired); +} + +function validatePropertyIsBoolean(parent, propertyName, trace, errors, isRequired) { + var localErrors, localTrace, propValue; + + localErrors = errors || []; + localTrace = trace || ''; + propValue = parent[propertyName]; + + if (propValue !== undefined) { + if (propValue === null || !xapiValidationUtils.isBoolean(propValue)) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace, propertyName), + message: `${propertyName} ${xapiValidationErrors.MUST_BE_BOOLEAN}`, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + } else if (isRequired) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace, propertyName), + message: `${propertyName} ${xapiValidationErrors.MUST_BE_BOOLEAN_PRESENT}`, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + return localErrors; +} + +function validatePropertyIsNumber(parent, propertyName, trace, errors, isRequired) { + var localErrors, localTrace, propValue; + + localErrors = errors || []; + localTrace = trace || ''; + propValue = parent[propertyName]; + + if (propValue !== undefined) { + if (propValue === null || !xapiValidationUtils.isNumber(propValue)) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace, propertyName), + message: `${propertyName} ${xapiValidationErrors.MUST_BE_NUMBER}`, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + } else if (isRequired) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace, propertyName), + message: `${propertyName} ${xapiValidationErrors.MUST_BE_NUMBER_PRESENT}`, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + return localErrors; +} + +function validateIFIProperties(target, trace, errors) { + var localErrors, localTrace, accountTrace; + + localErrors = errors || []; + localTrace = trace || ''; + + if (target.mbox !== undefined && target.mbox !== null) { + if (!xapiValidationUtils.isString(target.mbox)) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace, properties.MBOX), + message: xapiValidationErrors.IFI_MUST_BE_MBOX_URI, + level: xapiErrorLevels.MUST_VIOLATION + }); + } else if (!xapiValidationRegex.MAILTO_URI.test(target.mbox)) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace, properties.MBOX), + message: xapiValidationErrors.IFI_MUST_BE_VALID_MBOX_FORMAT, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + } + + validatePropertyIsString(target, properties.MBOX_SHA_1_SUM, localTrace, localErrors, /*isRequired*/false); + validatePropertyIsUri(target, properties.OPEN_ID, localTrace, localErrors, /*isRequired*/false); + + if (target.account !== undefined && target.account !== null) { + accountTrace = xapiValidationUtils.addPropToTrace(localTrace, properties.ACCOUNT); + validatePropertyIsUri(target.account, properties.HOME_PAGE,accountTrace, localErrors, /*isRequired*/true); + validatePropertyIsString(target.account, properties.NAME, accountTrace, localErrors, /*isRequired*/true); + validateAbsenceOfNonWhitelistedProperties(target.account, xapiWhiteListProperties.IFI, accountTrace, localErrors); + } + + return localErrors; +} + +function getIFIs(target) { + var ifis; + + if (target === null || target === undefined) {return [];} + + ifis = xapiValidationIfiPropertyNames.filter((name) => { + if (target[name] !== undefined && target[name] !== null) { + return {key: name, value: target[name]}; + } + }); + + return ifis; +} + +function getIFICount(target) { + return getIFIs(target).length; +} + +function validateExtensions(extensions, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || [], + localTrace = trace || properties.EXTENSIONS; + + if (extensions === undefined) {return localErrors;} + + if (!xapiValidationUtils.isNonNullMapObject(extensions)) { + localErrors.push({ + trace: localTrace, + message: xapiValidationErrors.EXTENSIONS_MUST_NOT_BE_NULL, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + // TODO - double-check what further enforceable constraints exist on extension object properties + return localErrors; +} + +function validateLanguageMap(languageMap, trace, errors) { + var localErrors, localTrace, propName, mappedValue; + + localErrors = errors || []; + localTrace = trace || properties.LANGUAGE_MAP; + + if (languageMap === undefined) {return localErrors;} + + if (!xapiValidationUtils.isNonNullMapObject(languageMap)) { + localErrors.push({ + trace: xapiValidationUtils.addPropToTrace(localTrace), + message: xapiValidationErrors.LANGUAGE_MAPS_MUST_NOT_BE_NULL, + level: xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + for (propName in languageMap) { + + if (languageMap.hasOwnProperty(propName)) { + if (!xapiValidationUtils.isValidLanguageTag(propName, xapiValidationRegex.BCP_47)) { + localErrors.push({ + trace: xapiValidationUtils.addPropToTrace(localTrace, propName), + message: `${propName} ${xapiValidationErrors.LANGUAGE_MAP_KEY_INVALID}`, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + + mappedValue = languageMap[propName]; + + if (mappedValue === null || mappedValue === undefined || !xapiValidationUtils.isString(mappedValue)) { + localErrors.push({ + trace: xapiValidationUtils.addLookupToTrace(localTrace, propName), + message: `${propName} ${xapiValidationErrors.LANGUAGE_MAP_KEY_MUST_BE_STRING}`, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + } + } + + return localErrors; +} + +function validateVerb(verb, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || properties.VERB; + + if (verb === undefined) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace), + message: xapiValidationErrors.VERB_MUST_BE_PROVIDED, + level: xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + if (!xapiValidationUtils.isNonNullMapObject(verb)) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace), + message: xapiValidationErrors.VERB_MUST_NOT_BE_NULL, + level: xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + validatePropertyIsUri(verb, properties.ID, localTrace, localErrors, /*isRequired*/true); + + if (verb.display === undefined) { + localErrors.push({ + trace: xapiValidationUtils.addPropToTrace(localTrace, properties.DISPLAY), + message: xapiValidationErrors.DISPLAY_SHOULD_BE_PROVIDED, + level: xapiErrorLevels.SHOULD_VIOLATION + }); + } else { + validateLanguageMap(verb.display, xapiValidationUtils.addPropToTrace(localTrace, properties.DISPLAY), localErrors); + } + + validateAbsenceOfNonWhitelistedProperties(verb, xapiWhiteListProperties.URI, localTrace, localErrors); + + return localErrors; +} + +function validateInteractionComponentArray(components, interactionType, allowedInteractionTypes, trace, errors) { + var localErrors, localTrace, isAllowedComponentType, ids, perComponentTrace; + + localErrors = errors || []; + localTrace = trace || properties.INTERACTION_COMPONENTS; + isAllowedComponentType = allowedInteractionTypes.indexOf(interactionType) !== xapiGeneral.NO_INDEX_FOUND; + ids = []; + + if (isAllowedComponentType && components !== undefined) { + if (components === null || !xapiValidationUtils.isArray(components)) { + localErrors.push({ + trace: localTrace, + message: xapiValidationErrors.INTERACTION_COMPONENT_SHOULD_BE_ARRAY, + level: xapiErrorLevels.SHOULD_VIOLATION + }); + } else { + components.forEach((interactionComponent, i) => { + perComponentTrace = xapiValidationUtils.addLookupToTrace(localTrace, i); + + if (!xapiValidationUtils.isNonNullMapObject(interactionComponent)) { + localErrors.push({ + trace: perComponentTrace, + message: xapiValidationErrors.INTERACTION_COMPONENT_MUST_NOT_BE_NULL, + level: xapiErrorLevels.MUST_VIOLATION + }); + } else { + validatePropertyIsString(interactionComponent, properties.ID, perComponentTrace, localErrors, /*isRequired*/true, xapiErrorLevels.MUST_VIOLATION); + if (ids.indexOf(interactionComponent.id) !== xapiGeneral.NO_INDEX_FOUND) { + localErrors.push({ + trace: xapiValidationUtils.addPropToTrace(perComponentTrace, properties.ID), + message: xapiValidationErrors.ID_MUST_BE_UNIQUE, + level: xapiErrorLevels.MUST_VIOLATION + }); + } else { + ids.push(interactionComponent.id); + } + + if (interactionComponent.id && xapiValidationRegex.CONTAINS_WHITESPACE.test(interactionComponent.id)) { + localErrors.push({ + trace: xapiValidationUtils.addPropToTrace(perComponentTrace, properties.ID), + message: xapiValidationErrors.ID_SHOULD_NOT_CONTAIN_WHITESPACES, + level: xapiErrorLevels.SHOULD_VIOLATION + }); + } + + validateLanguageMap(interactionComponent.description, xapiValidationUtils.addPropToTrace(perComponentTrace, properties.DESCRIPTION), localErrors); + validateAbsenceOfNonWhitelistedProperties(interactionComponent, xapiWhiteListProperties.COMPONENT_ARRAY, perComponentTrace, localErrors); + } + }); + + } + } else if (interactionType && components) { + localErrors.push({ + trace: localTrace, + message: `${xapiValidationErrors.INTERACTION_TYPE_MUST_BE_VALID} ${interactionType}`, + level: xapiErrorLevels.SHOULD_VIOLATION + }); + } + + return localErrors; +} + +function validateActivityDefintion(definition, trace, errors) { + var localErrors, localTrace, correctResponsesPatternTrace; + + localErrors = errors || []; + localTrace = trace || properties.DEFINITION; + correctResponsesPatternTrace = xapiValidationUtils.addPropToTrace(localTrace, properties.CORRECT_RESPONSES_PATTERN); + + if (!xapiValidationUtils.isNonNullMapObject(definition)) { + localErrors.push({ + trace: xapiValidationUtils.addPropToTrace(localTrace), + message: xapiValidationErrors.DEFINITIONS_MUST_BE_OBJECTS, + level: xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + validateLanguageMap(definition.name, xapiValidationUtils.addPropToTrace(localTrace, properties.NAME), localErrors); + validateLanguageMap(definition.description, xapiValidationUtils.addPropToTrace(localTrace, properties.DESCRIPTION), localErrors); + + validatePropertyIsUri(definition, properties.TYPE, localTrace, localErrors, /*isRequired*/false); + validatePropertyIsUrl(definition, properties.MORE_INFO, localTrace, localErrors, /*isRequired*/false); + validateExtensions(definition.extensions, xapiValidationUtils.addPropToTrace(localTrace, properties.EXTENSIONS), localErrors); + + if (definition.interactionType !== undefined) { + if (definition.type !== xapiGeneral.INTERACTION_DEFINITION_TYPE) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace, properties.TYPE), + message: `${xapiValidationErrors.INTERACTION_ACTIVITY_SHOULD_HAVE} "${xapiGeneral.INTERACTION_DEFINITION_TYPE}"`, + level: xapiErrorLevels.SHOULD_VIOLATION + }); + } + + if (xapiValidationInteractionTypes.indexOf(definition.interactionType) === xapiGeneral.NO_INDEX_FOUND) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace, properties.INTERACTION_TYPE), + message: xapiValidationErrors.INTERACTION_TYPE_MUST_BE_CMI, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + } + + if (definition.correctResponsesPattern !== undefined) { + if (!xapiValidationUtils.isArray(definition.correctResponsesPattern)) { + localErrors.push({ + trace: correctResponsesPatternTrace, + message: xapiValidationErrors.CORRECT_RESPONSES_PATTERN_MUST_BE_ARRAY, + level: xapiErrorLevels.MUST_VIOLATION + }); + } else { + definition.correctResponsesPattern.forEach((response, i) => { + if (response === null || response === undefined || !xapiValidationUtils.isString(response)) { + localErrors.push({ + trace: xapiValidationUtils.addLookupToTrace(correctResponsesPatternTrace, i), + message: xapiValidationErrors.CORRECT_RESPONSES_PATTERN_MUST_BE_STRINGS, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + }); + } + } + + validateInteractionComponentArray( + definition.choices, + definition.interactionType, + [properties.CHOICE, properties.SEQUENCING], + xapiValidationUtils.addPropToTrace(localTrace, properties.CHOICES), + localErrors + ); + + validateInteractionComponentArray( + definition.scale, + definition.interactionType, + [properties.LIKERT], + xapiValidationUtils.addPropToTrace(localTrace, properties.SCALE), + localErrors + ); + + validateInteractionComponentArray( + definition.source, + definition.interactionType, + [properties.MATCHING], + xapiValidationUtils.addPropToTrace(localTrace, properties.SOURCE), + localErrors + ); + + validateInteractionComponentArray( + definition.target, + definition.interactionType, + [properties.MATCHING], + xapiValidationUtils.addPropToTrace(localTrace, properties.TARGET), + localErrors + ); + + validateInteractionComponentArray( + definition.steps, + definition.interactionType, + [properties.PERFORMANCE], + xapiValidationUtils.addPropToTrace(localTrace, properties.STEPS), + localErrors + ); + + validateAbsenceOfNonWhitelistedProperties(definition, xapiWhiteListProperties.ACTIVITY_DEFINITION, localTrace, localErrors); + return localErrors; +} + +function validateActivity(activity, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || properties.ACTIVITY; + + if (!xapiValidationUtils.isNonNullMapObject(activity)) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace), + message: xapiValidationErrors.ACTIVITIES_MUST_NOT_BE_NULL, + level: xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + validatePropertyIsUri(activity, properties.ID, localTrace, localErrors, /*isRequired*/true); + + if (activity.definition !== undefined) { + validateActivityDefintion( + activity.definition, + xapiValidationUtils.addPropToTrace(localTrace, properties.DEFINITION), + localErrors + ); + } + + validateAbsenceOfNonWhitelistedProperties(activity, xapiWhiteListProperties.ACTIVITY, localTrace, localErrors); + + return localErrors; +} + +function validateStatementRef(statementRef, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || properties.STATEMENT_REF; + + if (!xapiValidationUtils.isNonNullMapObject(statementRef)) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace), + message: xapiValidationErrors.STATEMENT_REF_MUST_NOT_BE_NULL_MAP_OBJECTS, + level: xapiErrorLevels.MUST_VIOLATION + }); + return localErrors; + } + + + if (statementRef.objectType !== objectTypes.STATEMENT_REF) { + localErrors.push({ + trace: xapiValidationUtils.addPropToTrace(localTrace, properties.OBJECT_TYPE), + message: xapiValidationErrors.OBJECT_TYPE_MUST_BE_STATEMENT_REF, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + + if (!statementRef.id || !xapiValidationRegex.UUID.test(statementRef.id)) { + localErrors.push({ + trace: xapiValidationUtils.addPropToTrace(localTrace, properties.ID), + message: xapiValidationErrors.ID_MUST_BE_VALID_UUID_REF, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + + validateAbsenceOfNonWhitelistedProperties(statementRef, xapiWhiteListProperties.STATEMENT_REF, localTrace, localErrors); + + return localErrors; +} + +function validateScore(score, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || properties.SCORE; + + if (score === undefined) { + return localErrors; + } + + validatePropertyIsNumber(score, properties.SCALED, localTrace, localErrors, /*isRequired*/false); + + if (score.scaled !== undefined) { + if (score.scaled < xapiGeneral.MIN_SCALED_VALUE || score.scaled > xapiGeneral.MAX_SCALED_VALUE) { + localErrors.push({ + trace: xapiValidationUtils.addPropToTrace(localTrace, properties.SCALED), + message: xapiValidationErrors.SCALED_MUST_BE_BETWEEN_0_1, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + } + + if (score.min !== undefined) { + validatePropertyIsNumber(score, properties.MIN, localTrace, localErrors, /*isRequired*/false); + + if (score.raw !== undefined && score.raw < score.min) { + localErrors.push({ + trace: xapiValidationUtils.addPropToTrace(localTrace, properties.RAW), + message: xapiValidationErrors.RAW_MUST_BE_GREATER_THAN_MIN, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + + if (score.max !== undefined && score.max < score.min) { + localErrors.push({ + trace: xapiValidationUtils.addPropToTrace(localTrace, properties.MAX), + message: xapiValidationErrors.MAX_MUST_BE_GREATER_THAN_MIN, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + } + + if (score.max !== undefined) { + validatePropertyIsNumber(score, properties.MAX, localTrace, localErrors, /*isRequired*/false); + + if (score.raw !== undefined && score.raw > score.max) { + localErrors.push({ + trace: xapiValidationUtils.addPropToTrace(localTrace, properties.RAW), + message: xapiValidationErrors.RAW_MUST_BE_LESS_THAN_MAX, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + } + + validatePropertyIsNumber(score, properties.RAW, localTrace, localErrors, /*isRequired*/false); + validateAbsenceOfNonWhitelistedProperties(score, xapiWhiteListProperties.SCORE, localTrace, localErrors); + + return localErrors; +} + +function validateResult(result, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || properties.RESULT; + + if (result === undefined) {return localErrors;} + + if (!xapiValidationUtils.isNonNullMapObject(result)) { + localErrors.push({ + trace: xapiValidationUtils.addPropToTrace(localTrace), + message: xapiValidationErrors.RESULT_MUST_BE_MAP_OBJECT, + level: xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + validateScore(result.score, xapiValidationUtils.addPropToTrace(localTrace, properties.SCORE), localErrors); + validatePropertyIsBoolean(result, properties.SUCCESS, localTrace, localErrors, /*isRequired*/false); + validatePropertyIsBoolean(result, properties.COMPLETION, localTrace, localErrors, /*isRequired*/false); + validatePropertyIsString(result, properties.RESPONSE, localTrace, localErrors, /*isRequired*/false); + validateExtensions(result.extensions, xapiValidationUtils.addPropToTrace(localTrace, properties.EXTENSIONS), localErrors); + + if (result.duration !== undefined && (result.duration === null || !xapiValidationUtils.isString(result.duration) || !xapiValidationRegex.ISO_8601_DURATION.test(result.duration))) { + localErrors.push({ + trace: xapiValidationUtils.addPropToTrace(localTrace, properties.DURATION), + message: xapiValidationErrors.DURATION_MUST_BE_VALID, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + + validateAbsenceOfNonWhitelistedProperties(result, xapiWhiteListProperties.RESULT, localTrace, localErrors); + + return localErrors; +} + +function validatePropertyIsISO8601String(parent, propertyName, trace, errors) { + var localErrors, localTrace, matched, datetime; + + localErrors = errors || []; + localTrace = trace || properties.DATE_TIME; + datetime = parent[propertyName]; + + if (datetime === undefined) {return localErrors;} + + if (datetime === null || !xapiValidationUtils.isString(datetime)) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace, propertyName), + message: `${propertyName} ${xapiValidationErrors.MUST_BE_STRING}`, + level: xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + matched = xapiValidationRegex.ISO_8601_DATE_TIME.exec(datetime); + + if (matched) { + if (!dateIncludesZoneInformation(matched)) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace, propertyName), + message: xapiValidationErrors.DATE_SHOULD_INCLUDE_ZONE_INFORMATION, + level: xapiErrorLevels.SHOULD_VIOLATION + }); + } + } else { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace, propertyName), + message: xapiValidationErrors.DATE_MUST_BE_VALID, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + + return localErrors; +} + +function validateVersion(version, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || properties.VERSION; + + if (version === undefined) {return localErrors;} + + if (version === null || !xapiValidationUtils.isString(version) || !xapiValidationRegex.SEMVER_1_P_0_P_0.test(version)) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace), + message: xapiValidationErrors.VERSION_MUST_COMPLY_SEMANTIC_VERSIONING, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + + return localErrors; +} + +function validateAttachmentObject(attachment, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || properties.ATTACHMENT; + + if (!xapiValidationUtils.isNonNullMapObject(attachment)) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace), + message: xapiValidationErrors.ATTACHMENTS_MUST_NOT_BE_NULL_MAP_OBJECTS, + level: xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + if (attachment.display === undefined) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace, properties.DISPLAY), + message: xapiValidationErrors.DISPLAY_SHOULD_BE_PROVIDED, + level: xapiErrorLevels.MUST_VIOLATION + }); + + } else { + validateLanguageMap(attachment.display, xapiValidationUtils.addPropToTrace(localTrace, properties.DISPLAY), localErrors); + } + + validateLanguageMap(attachment.description, xapiValidationUtils.addPropToTrace(localTrace, properties.DESCRIPTION), localErrors); + validatePropertyIsUri(attachment, properties.USAGE_TYPE, localTrace, localErrors, /*isRequired*/true, xapiErrorLevels.MUST_VIOLATION); + validatePropertyIsUri(attachment, properties.FILE_URL, localTrace, localErrors, /*isRequired*/false, xapiErrorLevels.MUST_VIOLATION); + + // TODO - more complete validation for Internet Media Type via RFC 2046 + validatePropertyIsString(attachment, properties.CONTENT_TYPE, localTrace, localErrors, /*isRequired*/true, xapiErrorLevels.MUST_VIOLATION); + + if (attachment.length === undefined || attachment.length === null || !xapiValidationUtils.isNumber(attachment.length) || (attachment.length % 1 !== 0)) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace, properties.LENGTH), + message: xapiValidationErrors.LENGTH_MUST_BE_INTEGER, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + + if (attachment.sha2 === undefined) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace, properties.SHA2), + message: xapiValidationErrors.SHA2_MUST_BE_PROVIDED_ON_ATTACHMENT_OBJECTS, + level: xapiErrorLevels.MUST_VIOLATION + }); + } else if (attachment.sha2 === null || !xapiValidationUtils.isString(attachment.sha2) || !xapiValidationRegex.BASE_64.test(attachment.sha2)) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace, properties.SHA2), + message: xapiValidationErrors.SHA2_MUST_CONTAIN_BASE_64_STRING, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + + validateAbsenceOfNonWhitelistedProperties(attachment, xapiWhiteListProperties.ATTACHMENT, localTrace, localErrors); + return localErrors; +} + +function validateAttachments(attachments, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || properties.ATTACHMENTS; + + if (attachments === undefined) {return localErrors;} + + if (attachments === null || !xapiValidationUtils.isArray(attachments)) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace), + message: xapiValidationErrors.ATTACHMENTS_MUST_BE_NOT_NULL_ARRAY, + level: xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + attachments.forEach((attachment, i) => { + validateAttachmentObject(attachment, xapiValidationUtils.addLookupToTrace(localTrace, i), localErrors); + }); + + return localErrors; +} + +function validateAgent(agent, trace, errors) { + var localErrors, localTrace, ifiCount; + + localErrors = errors || []; + localTrace = trace || properties.AGENT; + + if (!xapiValidationUtils.isNonNullMapObject(agent)) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace), + message: xapiValidationErrors.AGENT_MUST_BE_NON_NULL_MAP_OBJECT, + level: xapiErrorLevels.MUST_VIOLATION + }); + return localErrors; + } + + ifiCount = getIFICount(agent); + + if (ifiCount !== xapiGeneral.NUMER_OF_SPECIFIED_IFI_PROPERTIES) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace), + message: xapiValidationErrors.AGENT_IFI_PROPERTIES_MUST_BE_SPECIFIED, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + + if (agent.objectType === objectTypes.GROUP) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace), + message: xapiValidationErrors.AGENT_MUST_NOT_HAVE_GROUP_CHARACTERISTICS, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + + validateIFIProperties(agent, localTrace, localErrors); + validatePropertyIsString(agent, properties.NAME, localTrace, localErrors, /*isRequired*/false); + + validateAbsenceOfNonWhitelistedProperties(agent, xapiWhiteListProperties.AGENT, localTrace, localErrors); + + return localErrors; +} + +function validateGroup(group, trace, errors) { + var localErrors, localTrace, memberTrace, ifiCount; + + localErrors = errors || []; + localTrace = trace || properties.GROUP; + memberTrace = xapiValidationUtils.addPropToTrace(localTrace, properties.MEMBER); + + if (!xapiValidationUtils.isNonNullMapObject(group)) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace), + message: xapiValidationErrors.GROUP_MUST_BE_NON_NULL_MAP_OBJECT, + level: xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + ifiCount = getIFICount(group); + + if (ifiCount === 0) { + if (group.member === null || group.member === undefined) { + localErrors.push({ + trace: memberTrace, + message: xapiValidationErrors.MEMBER_MUST_BE_PROVIDED_FOR_ANONYMOUS_GROUPS, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + } else if (ifiCount > xapiGeneral.NUMER_OF_SPECIFIED_IFI_PROPERTIES) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace), + message: xapiValidationErrors.GROUP_IFI_PROPERTIES_MUST_BE_SPECIFIED, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + + validateIFIProperties(group, localTrace, localErrors); + + validatePropertyIsString(group, properties.NAME, localTrace, localErrors, /*isRequired*/false); + + if (group.member !== undefined) { + if (group.member === null || !xapiValidationUtils.isArray(group.member)) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace, properties.MEMBER), + message: xapiValidationErrors.GROUP_MEMBER_MUST_BE_ARRAY, + level: xapiErrorLevels.MUST_VIOLATION + }); + } else { + group.member.forEach((member, i) => { + validateAgent(member, xapiValidationUtils.addLookupToTrace(memberTrace, i), localErrors); + }); + } + } + + validateAbsenceOfNonWhitelistedProperties(group, xapiWhiteListProperties.GROUP, localTrace, localErrors); + + return localErrors; +} + +function validateActor(actor, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || properties.ACTOR; + + if (actor === null || actor === undefined) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace), + message: xapiValidationErrors.ACTOR_MUST_BE_PROVIDED, + level: xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + if (xapiValidationUtils.isGroup(actor, objectTypes.GROUP)) { + validateGroup(actor, localTrace, localErrors); + } else { + validateAgent(actor, localTrace, localErrors); + } + + return localErrors; +} + +function validateAuthority(authority, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || properties.AUTHORITY; + + if (authority === undefined) { + return localErrors; + } + + if (!xapiValidationUtils.isNonNullMapObject(authority)) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace), + message: xapiValidationErrors.AUTHORITY_MUST_BE_NON_NULL_MAP_OBJECT, + level: xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + if (xapiValidationUtils.isGroup(authority, objectTypes.GROUP)) { + validateGroup(authority, localTrace, localErrors); + if (!authority.member || !authority.member.length || authority.member.length !== xapiGeneral.GROUP_AUTHORITY_AGENT_MEMBERS) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace, properties.MEMBER), + message: xapiValidationErrors.GROUP_AUTHORITY_AGENT_MEMBERS_MUST_BE_TWO, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + } else { + validateAgent(authority, localTrace, localErrors); + } + + return localErrors; +} + +function validateContextActivitySubContext(subContext, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || properties.SUB_CONTEXT; + + if (subContext === undefined) {return localErrors;} + + if (subContext === null) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace), + message: xapiValidationErrors.CONTEXT_ACTIVITIES_MUST_NOT_BE_NULL, + level: xapiErrorLevels.MUST_VIOLATION + }); + } else if (xapiValidationUtils.isArray(subContext)) { + subContext.forEach((activity, i) => { + validateActivity(activity, xapiValidationUtils.addLookupToTrace(localTrace, i), localErrors); + }); + } else if (xapiValidationUtils.isObject(subContext)) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace), + message: xapiValidationErrors.CONTEXT_ACTIVITIES_SHOULD_BE_AN_ARRAY, + level: xapiErrorLevels.SHOULD_VIOLATION + }); + + validateActivity(subContext, localTrace, localErrors); + } else { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace), + message: xapiValidationErrors.CONTEXT_ACTIVITIES_MUST_BE_ARRAY_OR_ACTIVITY_OBJ, + level: xapiErrorLevels.MUST_VIOLATION}); + } + return localErrors; +} + +function validateContextActivities(contextActivities, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || properties.CONTEXT_ACTIVITIES; + + if (contextActivities === undefined) { + return localErrors; + } + + if (!xapiValidationUtils.isNonNullMapObject(contextActivities)) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace), + message: xapiValidationErrors.CONTEXT_ACTIVITIES_MUST_BE_NON_NULL_MAP_OBJECT, + level: xapiErrorLevels.MUST_VIOLATION + }); + return localErrors; + } + + validateContextActivitySubContext(contextActivities.parent, xapiValidationUtils.addPropToTrace(localTrace, properties.PARENT), localErrors); + validateContextActivitySubContext(contextActivities.grouping, xapiValidationUtils.addPropToTrace(localTrace, properties.GROUPING), localErrors); + validateContextActivitySubContext(contextActivities.category, xapiValidationUtils.addPropToTrace(localTrace, properties.CATEGORY), localErrors); + validateContextActivitySubContext(contextActivities.other, xapiValidationUtils.addPropToTrace(localTrace, properties.OTHER), localErrors); + + validateAbsenceOfNonWhitelistedProperties(contextActivities, xapiWhiteListProperties.CONTEXT_ACTIVITIES, localTrace, localErrors); + + return localErrors; +} + +function validateContext(context, trace, errors, statementObjectObjectType) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || properties.CONTEXT; + + if (context === undefined) {return localErrors;} + + if (!xapiValidationUtils.isNonNullMapObject(context)) { + localErrors.push({ + trace: localTrace, + message: xapiValidationErrors.CONTEXT_MUST_BE_NON_NUL_MAP_OBJECT, + level: xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + if (context.registration !== undefined && (context.registration === null || !xapiValidationUtils.isString(context.registration) || !xapiValidationRegex.UUID.test(context.registration))) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace, properties.REGISTRATION), + message: xapiValidationErrors.REGISTRATION_MUST_BE_UUID_STRING, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + + if ([objectTypes.GROUP, objectTypes.AGENT].indexOf(statementObjectObjectType) !== xapiGeneral.NO_INDEX_FOUND) { + if (context.revision !== undefined) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace, properties.REVISION), + message: xapiValidationErrors.REVISION_MUST_BE_AGENT_OR_GROUP, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + + if (context.platform !== undefined) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace, properties.PLATFORM), + message: xapiValidationErrors.PLATFORM_MUST_NOT_BE_USED_WITH_REVISION_AGENT_OR_GROUP, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + } + + validatePropertyIsString(context, properties.REVISION, localTrace, localErrors, /*isRequired*/false, xapiErrorLevels.MUST_VIOLATION); + validatePropertyIsString(context, properties.PLATFORM, localTrace, localErrors, /*isRequired*/false, xapiErrorLevels.MUST_VIOLATION); + + if (context.team !== undefined) { + validateGroup(context.team, xapiValidationUtils.addPropToTrace(localTrace, properties.TEAM), localErrors); + } + + if (context.contextActivities !== undefined) { + validateContextActivities(context.contextActivities, xapiValidationUtils.addPropToTrace(localTrace, properties.CONTEXT_ACTIVITIES), localErrors); + } + + if (context.language !== undefined && !xapiValidationUtils.isValidLanguageTag(context.language, xapiValidationRegex.BCP_47)) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace, properties.LANGUAGE), + message: xapiValidationErrors.LANGUAGE_MUST_BE_STRING, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + + if (context.statement !== undefined) { + validateStatementRef(context.statement, xapiValidationUtils.addPropToTrace(localTrace, properties.STATEMENT), localErrors); + } + + if (context.instructor !== undefined) { + if (xapiValidationUtils.isGroup(context.instructor, objectTypes.GROUP)) { + validateGroup(context.instructor, xapiValidationUtils.addPropToTrace(localTrace, properties.INSTRUCTOR), localErrors); + } else { + validateAgent(context.instructor, xapiValidationUtils.addPropToTrace(localTrace, properties.INSTRUCTOR), localErrors); + } + } + + validateExtensions(context.extensions, xapiValidationUtils.addPropToTrace(localTrace, properties.EXTENSIONS), localErrors); + validateAbsenceOfNonWhitelistedProperties(context, xapiWhiteListProperties.EXTENSIONS,localTrace,localErrors); + + return localErrors; +} + +function validateObject(object, trace, errors, isWithinSubStatement) { + var localErrors, localTrace, objectType; + + localErrors = errors || []; + localTrace = trace || properties.OBJECT; + + if (object === undefined) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace), + message: xapiValidationErrors.OBJECT_MUST_BE_DEFINED, + level: xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + if (!xapiValidationUtils.isNonNullMapObject(object)) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace), + message: xapiValidationErrors.OBJECT_MUST_BE_NON_NULL_MAP_OBJECT, + level: xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + validatePropertyIsString(object, properties.OBJECT_TYPE, localTrace, localErrors, /*isRequired*/true, xapiErrorLevels.SHOULD_VIOLATION); + + objectType = object.objectType || objectTypes.ACTIVITY; + + switch (objectType) { + case objectTypes.ACTIVITY: + validateActivity(object, localTrace, localErrors); + break; + case objectTypes.AGENT: + validateAgent(object, localTrace, localErrors); + break; + case objectTypes.GROUP: + validateGroup(object, localTrace, localErrors); + break; + case objectTypes.STATEMENT_REF: + validateStatementRef(object, localTrace, localErrors); + break; + case objectTypes.SUB_STATEMENT: + if (isWithinSubStatement) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace, properties.OBJECT_TYPE), + message: xapiValidationErrors.SUB_STATEMENT_MUST_NOT_CONTAIN_SUB_STATEMENT, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + validate(object, localTrace, localErrors, /*isSubStatement*/true); + break; + default: + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace, properties.OBJECT_TYPE), + message: `${xapiValidationErrors.OBJECT_TYPE_MUST_BE_VALID_OPTION} ${xApiValidObjectTypes.toString()}`, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + + return localErrors; +} + +function validate(statement, trace, errors, isSubStatement) { + var localErrors, localTrace, statementObjectObjectType, whitelistedProperties; + + localErrors = errors || []; + localTrace = trace || properties.STATEMENT; + + whitelistedProperties = xapiWhiteListProperties.STATEMENT; + + if (!xapiValidationUtils.isNonNullMapObject(statement)) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace), + message: xapiValidationErrors.STATEMENT_REF_MUST_NOT_BE_NULL_MAP_OBJECTS, + level: xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + if (!isSubStatement) { + if (statement.id === null || statement.id === undefined || !xapiValidationUtils.isString(statement.id)) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace, properties.ID), + message: xapiValidationErrors.IDS_SHOULD_BE_GENERATED_BY_LRS, + level: xapiErrorLevels.SHOULD_VIOLATION + }); + } else if (!xapiValidationRegex.UUID.test(statement.id)) { + localErrors.push({ + trace: xapiValidationUtils.localTraceToString(localTrace, properties.ID), + message: xapiValidationErrors.ID_MUST_BE_VALID, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + } else { + whitelistedProperties = xapiWhiteListProperties.SUB_STATEMENT; + } + + validateActor(statement.actor, xapiValidationUtils.addPropToTrace(localTrace, properties.ACTOR), localErrors); + validateVerb(statement.verb, xapiValidationUtils.addPropToTrace(localTrace, properties.VERB), localErrors); + validateObject(statement.object, xapiValidationUtils.addPropToTrace(localTrace, properties.OBJECT), localErrors, isSubStatement); + validateResult(statement.result, xapiValidationUtils.addPropToTrace(localTrace, properties.RESULT), localErrors); + + statementObjectObjectType = statement.object && statement.object.objectType ? statement.object.objectType : objectTypes.ACTIVITY; + + validateContext(statement.context, xapiValidationUtils.addPropToTrace(localTrace, properties.CONTEXT), localErrors, statementObjectObjectType); + validatePropertyIsISO8601String(statement, properties.TIMESTAMP, localTrace, localErrors); + validatePropertyIsISO8601String(statement, properties.STORED, localTrace, localErrors); + + validateAuthority(statement.authority, xapiValidationUtils.addPropToTrace(localTrace, properties.AUTHORITY), localErrors); + validateVersion(statement.version, xapiValidationUtils.addPropToTrace(localTrace, properties.VERSION), localErrors); + validateAttachments(statement.attachments, xapiValidationUtils.addPropToTrace(localTrace, properties.ATTACHMENTS), localErrors); + + validateAbsenceOfNonWhitelistedProperties(statement, whitelistedProperties, localTrace, localErrors); + + return localErrors; +} + +function makeStatementReport(statement) { + var localErrors; + + localErrors = []; + validate(statement, properties.STATEMENT, localErrors, /*isRequired*/false); + + return makeV1Report(statement, localErrors); +} + +function validateAmbiguousTypeStatement(statement) { + var statementObject; + + if (statement === undefined) { + return makeV1SingleErrorReport(/*instance*/null, { + trace: properties.STATEMENT, + message: xapiValidationErrors.STATEMENT_ARGUMENT_MUST_BE_PROVIDED, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + + if (statement === null) { + return makeV1SingleErrorReport(/*instance*/null, { + trace: properties.STATEMENT, + message: xapiValidationErrors.STATEMENT_MUST_NOT_BE_NULL, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + + if (xapiValidationUtils.isString(statement)) { + try { + statementObject = JSON.parse(statement); + if (statementObject === null || !xapiValidationUtils.isObject(statementObject) || xapiValidationUtils.isArray(statementObject)) { + return makeV1SingleErrorReport(statementObject, { + trace: properties.STATEMENT, + message: xapiValidationErrors.STATEMENT_MUST_BE_PARSED_CORRECTLY, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + } catch (e) { + return makeV1SingleErrorReport(statementObject, { + trace: properties.STATEMENT, + message: `${xapiValidationErrors.INVALID_JSON}: ${e.message}`, + level: xapiErrorLevels.MUST_VIOLATION + }); + } + + return makeStatementReport(statementObject); + } + + if (xapiValidationUtils.isObject(statement) && !xapiValidationUtils.isArray(statement)) { + return makeStatementReport(statement); + } + + return makeV1SingleErrorReport(/*instance*/null, { + trace: properties.STATEMENT, + message: xapiValidationErrors.STATEMENT_ARGUMENT_IS_NOT_VALID, + level: xapiErrorLevels.MUST_VIOLATION + }); +} + +function dateIncludesZoneInformation(matched) { + return matched[dateFormatRegexPositions.ZONE] || + (matched[dateFormatRegexPositions.RELATIVE_TIME] && matched[dateFormatRegexPositions.TIME_ZONE_HOUR]); +} + +xapiValidation = { + validateStatement: validateAmbiguousTypeStatement +}; + +module.exports = xapiValidation; diff --git a/spec/xapiValidator_spec.js b/test/xapiValidator.test.js similarity index 98% rename from spec/xapiValidator_spec.js rename to test/xapiValidator.test.js index 265532e..cad8730 100644 --- a/spec/xapiValidator_spec.js +++ b/test/xapiValidator.test.js @@ -1,24 +1,28 @@ +import {_} from 'underscore'; +import {expect} from 'chai'; +import xapiValidator from '../src/xapiValidator'; + describe("xapiValidator", function() { describe("#validateStatement", function() { - + function reportHasErrorWithTracePrefix(report, prefix, targetLevel) { - if (report == null || report == undefined || report.errors == null || report.errors == undefined) { + if (report === null || report === undefined || report.errors === null || report.errors === undefined) { return false; } var hasTargetLevel = targetLevel !== null && targetLevel !== undefined; return _.any(report.errors, function(err) { - var foundPrefix = err.trace.indexOf(prefix) == 0; - return hasTargetLevel ? targetLevel == err.level && foundPrefix : foundPrefix; + var foundPrefix = err.trace.indexOf(prefix) === 0; + return hasTargetLevel ? targetLevel === err.level && foundPrefix : foundPrefix; }); } - + describe("when passed no arguments", function() { it("returns non-null report", function() { var result = xapiValidator.validateStatement(); expect(result).to.be.not.null; expect(result).to.be.a("Object"); }); - + it("includes one error", function() { var result = xapiValidator.validateStatement(); var errors = result.errors; @@ -30,14 +34,14 @@ describe("xapiValidator", function() { expect(errors[0]).to.have.property("level") .that.equals("MUST_VIOLATION"); }); - + it("has a null instance property in the report", function() { expect(xapiValidator.validateStatement()) .to.have.property("instance") .that.is.null; }); }); - + describe("when passed a null argument", function() { it("returns non-null report", function() { var result = xapiValidator.validateStatement(null); @@ -47,7 +51,7 @@ describe("xapiValidator", function() { .that.is.a("Array"); expect(result).to.have.property("instance"); }); - + it("includes one error", function() { var result = xapiValidator.validateStatement(null); var errors = result.errors; @@ -59,14 +63,14 @@ describe("xapiValidator", function() { expect(errors[0]).to.have.property("level") .that.equals("MUST_VIOLATION"); }); - + it("has a null instance property in the report", function() { expect(xapiValidator.validateStatement(null)) .to.have.property("instance") .that.is.null; }); }); - + describe("when passed a json string argument", function() { var minimalJsonString = "{\"id\":\"whatever\"}"; it("returns non-null report", function() { @@ -77,7 +81,7 @@ describe("xapiValidator", function() { .that.is.a("Array"); expect(result).to.have.property("instance"); }); - + it("has an instance property with the deserialized JSON in the report", function() { var result = xapiValidator.validateStatement(minimalJsonString); expect(result).to.have.property("instance") @@ -85,7 +89,7 @@ describe("xapiValidator", function() { .that.deep.equals({"id":"whatever"}); }); }); - + describe("when passed a json string argument encoding null", function() { var minimalJsonString = "null"; it("returns non-null report", function() { @@ -96,7 +100,7 @@ describe("xapiValidator", function() { .that.is.a("Array"); expect(result).to.have.property("instance"); }); - + it("includes one error", function() { var result = xapiValidator.validateStatement(minimalJsonString); var errors = result.errors; @@ -106,14 +110,14 @@ describe("xapiValidator", function() { expect(errors[0]).to.have.property("level") .that.equals("MUST_VIOLATION"); }); - + it("has an instance property with null value", function() { var result = xapiValidator.validateStatement(minimalJsonString); expect(result).to.have.property("instance") .that.is.null; }); }); - + describe("when passed an invalid json string argument", function() { var minimalJsonString = "derp"; it("returns non-null report", function() { @@ -124,25 +128,24 @@ describe("xapiValidator", function() { .that.is.a("Array"); expect(result).to.have.property("instance"); }); - + it("includes one error", function() { var result = xapiValidator.validateStatement(minimalJsonString); var errors = result.errors; expect(errors).to.be.instanceOf(Array); expect(errors).to.have.length(1); - expect(errors[0]).to.have.property("message") - .that.equals("Invalid JSON. The statement could not be parsed: Unexpected token d"); + expect(errors[0]).to.have.property("message"); expect(errors[0]).to.have.property("level") .that.equals("MUST_VIOLATION"); }); - + it("has an instance property with null value", function() { var result = xapiValidator.validateStatement(minimalJsonString); expect(result).to.have.property("instance") .that.is.null; }); }); - + describe("when passed a statement object", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , actor : {mbox:"mailto:agent@example.com"}, @@ -156,14 +159,14 @@ describe("xapiValidator", function() { .that.is.a("Array"); expect(result).to.have.property("instance"); }); - + it("has an instance property that matches the input object", function() { var result = xapiValidator.validateStatement(inputStatement); expect(result).to.have.property("instance") .that.deep.equals(inputStatement); }); }); - + describe("when given a null id property", function() { var inputStatement = {id : null , actor : {mbox:"mailto:agent@example.com"}, @@ -174,7 +177,7 @@ describe("xapiValidator", function() { expect(reportHasErrorWithTracePrefix(result, "statement.id")).to.be.true; }); }); - + describe("when given an invalid UUID id property", function() { var inputStatement = {id : "abc123", actor : {mbox:"mailto:agent@example.com"}, @@ -185,7 +188,7 @@ describe("xapiValidator", function() { expect(reportHasErrorWithTracePrefix(result, "statement.id")).to.be.true; }); }); - + describe("when given a valid UUID id property", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0", actor : {mbox:"mailto:agent@example.com"}, @@ -196,7 +199,7 @@ describe("xapiValidator", function() { expect(reportHasErrorWithTracePrefix(result, "statement.id")).to.be.false; }); }); - + describe("when given a null actor property", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , actor : null, @@ -207,7 +210,7 @@ describe("xapiValidator", function() { expect(reportHasErrorWithTracePrefix(result, "statement.actor")).to.be.true; }); }); - + describe("when given an empty non-null actor property", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , actor : {}, @@ -218,7 +221,7 @@ describe("xapiValidator", function() { expect(reportHasErrorWithTracePrefix(result, "statement.actor")).to.be.true; }); }); - + describe("when given an otherwise valid actor", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , actor : {mbox:"mailto:group@example.com"}, @@ -228,13 +231,13 @@ describe("xapiValidator", function() { var result = xapiValidator.validateStatement(inputStatement); expect(result.errors).to.have.property("length", 0); }); - + it("the name property produces no errors when a simple string", function() { inputStatement.actor.name = "hello"; var result = xapiValidator.validateStatement(inputStatement); expect(result.errors).to.have.property("length", 0); }); - + it("the name property produces no errors when a simple string", function() { inputStatement.actor.name = 1.23; var result = xapiValidator.validateStatement(inputStatement); @@ -242,7 +245,7 @@ describe("xapiValidator", function() { expect(result.errors).to.have.property("length", 1); }); }); - + describe("when given an actor with an objectType of 'Group'", function() { var moreValidStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , actor : {objectType:"Group", member:[]}, @@ -252,7 +255,7 @@ describe("xapiValidator", function() { var result = xapiValidator.validateStatement(moreValidStatement); expect(reportHasErrorWithTracePrefix(result, "statement.actor.member")).to.be.false; }); - + it("the member property is required to be present if the actor is unidentified, and produces an error when absent", function() { var inputInvalidStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , actor : {objectType:"Group"}, @@ -261,15 +264,15 @@ describe("xapiValidator", function() { var result = xapiValidator.validateStatement(inputInvalidStatement); expect(reportHasErrorWithTracePrefix(result, "statement.actor.member")).to.be.true; }); - + it("the member property is not required to be present if the actor is identified", function() { - var result = xapiValidator.validateStatement({id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , + var result = xapiValidator.validateStatement({id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , actor : {objectType:"Group", mbox:"mailto:group@example.com"}, verb: { "id":"http://adlnet.gov/expapi/verbs/created", "display":{"en-US":"created"}}, object : {id : "http://example.com/myUniqueId", objectType:"Activity"}}); expect(reportHasErrorWithTracePrefix(result, "statement.actor.member")).to.be.false; }); - + it("the member property is allowed to be present if the actor is identified", function() { var result = xapiValidator.validateStatement({id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0", actor : {objectType:"Group", mbox:"mailto:group@example.com", member:[]}, @@ -278,7 +281,7 @@ describe("xapiValidator", function() { expect(reportHasErrorWithTracePrefix(result, "statement.actor.member")).to.be.false; }); }); - + describe("when given an actor with a members property", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , actor : {member:[]}, @@ -287,28 +290,28 @@ describe("xapiValidator", function() { it("the member property has no errors about it when present but empty", function() { expect(xapiValidator.validateStatement(inputStatement).errors).to.be.empty; }); - + it("the member property has no errors when populated with a simple agent", function() { inputStatement.actor.member = [{mbox:"mailto:group@example.com"}]; expect(xapiValidator.validateStatement(inputStatement).errors).to.be.empty; }); - + it("the member property reports an error when populated with a Group object via objectType", function() { inputStatement.actor.member = [{mbox:"mailto:group@example.com", objectType:"Group"}]; expect(xapiValidator.validateStatement(inputStatement).errors) .to.have.property("length", 1); }); - + it("the member property's agent reports an error when given an account missing its homePage", function() { inputStatement.actor.member = [{account:{name:"bob"}}]; expect(reportHasErrorWithTracePrefix(xapiValidator.validateStatement(inputStatement), "statement.actor.member[0].account.homePage")).to.be.true; }); - + it("the member property's agent reports an error when given an account missing its name", function() { inputStatement.actor.member = [{account:{homePage:"http://example.com"}}]; expect(reportHasErrorWithTracePrefix(xapiValidator.validateStatement(inputStatement), "statement.actor.member[0].account.name")).to.be.true; }); - + it("the member property's agent reports an error when given an account with an all-lowercase homepage", function() { inputStatement.actor.member = [{account:{homepage:"http://example.com", name:"bob"}}]; var report = xapiValidator.validateStatement(inputStatement); @@ -322,28 +325,28 @@ describe("xapiValidator", function() { expect(xapiValidator.validateStatement(inputStatement).errors) .to.have.property("length", 0); }); - + it("the member property's agent reports no error when given a valid mbox", function() { inputStatement.actor.member = [{mbox:"mailto:bob@example.com"}]; expect(xapiValidator.validateStatement(inputStatement).errors) .to.have.property("length", 0); }); - + it("the member property's agent reports an error when given an invalid mbox", function() { inputStatement.actor.member = [{mbox:"SOMETHINGWRONG:bob@example.com"}]; var results = xapiValidator.validateStatement(inputStatement); expect(reportHasErrorWithTracePrefix(results, "statement.actor.member[0].mbox")).to.be.true; expect(results.errors).to.have.property("length", 1); }); - + it("the member property reports an error when populated with a Group object via member", function() { inputStatement.actor.member = [{mbox:"mailto:group@example.com", member:[]}]; expect(xapiValidator.validateStatement(inputStatement).errors) .to.have.property("length", 1); }); - + }); - + describe("when given a statement without a verb property", function() { it("reports an error", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , @@ -354,7 +357,7 @@ describe("xapiValidator", function() { expect(reportHasErrorWithTracePrefix(results, "statement.verb")).to.be.true; }); }); - + describe("when given a verb without an id property", function() { it("reports an error", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , @@ -366,7 +369,7 @@ describe("xapiValidator", function() { expect(reportHasErrorWithTracePrefix(results, "statement.verb.id", "MUST_VIOLATION")).to.be.true; }); }); - + describe("when given a verb with a non-string id property", function() { it("reports an error", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , @@ -378,7 +381,7 @@ describe("xapiValidator", function() { expect(reportHasErrorWithTracePrefix(results, "statement.verb.id", "MUST_VIOLATION")).to.be.true; }); }); - + describe("when given a verb with a relative URI id property", function() { it("reports an SHOULD_VIOLATION error", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , @@ -390,7 +393,7 @@ describe("xapiValidator", function() { expect(reportHasErrorWithTracePrefix(results, "statement.verb.id", "SHOULD_VIOLATION")).to.be.true; }); }); - + describe("when given a verb without a display property", function() { it("reports an error", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , @@ -402,7 +405,7 @@ describe("xapiValidator", function() { expect(reportHasErrorWithTracePrefix(results, "statement.verb.display", "SHOULD_VIOLATION")).to.be.true; }); }); - + describe("when given a verb with an empty display property", function() { it("reports no errors", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , @@ -412,7 +415,7 @@ describe("xapiValidator", function() { expect(xapiValidator.validateStatement(inputStatement).errors).to.have.property("length", 0); }); }); - + describe("when given a verb.display with RFC 5646 key and string value", function() { it("reports no errors", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , @@ -422,7 +425,7 @@ describe("xapiValidator", function() { expect(xapiValidator.validateStatement(inputStatement).errors).to.have.property("length", 0); }); }); - + describe("when given a verb.display with RFC 5646 key and non-string value", function() { it("reports an error", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , @@ -434,7 +437,7 @@ describe("xapiValidator", function() { expect(reportHasErrorWithTracePrefix(results, "statement.verb.display[\"en-US\"]", "MUST_VIOLATION")).to.be.true; }); }); - + describe("when given a verb.display with invalid key and string value", function() { it("reports an error", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , @@ -446,7 +449,7 @@ describe("xapiValidator", function() { expect(reportHasErrorWithTracePrefix(results, "statement.verb.display.123totallyWrong", "MUST_VIOLATION")).to.be.true; }); }); - + describe("when the object property is absent", function() { it("reports a MUST_VIOLATION error", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , @@ -457,7 +460,7 @@ describe("xapiValidator", function() { expect(reportHasErrorWithTracePrefix(results, "statement.object", "MUST_VIOLATION")).to.be.true; }); }); - + describe("when the object property is null", function() { it("reports a MUST_VIOLATION error", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , @@ -469,7 +472,7 @@ describe("xapiValidator", function() { expect(reportHasErrorWithTracePrefix(results, "statement.object", "MUST_VIOLATION")).to.be.true; }); }); - + describe("when the object lacks an objectType property", function() { it("reports a SHOULD_VIOLATION error", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , @@ -487,7 +490,7 @@ describe("xapiValidator", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , actor : {member:[]}, verb: { "id":"http://adlnet.gov/expapi/verbs/created", display : {"en-US":"created"}}, - object : {id : "http://example.com/myUniqueId", objectType:"Activity", + object : {id : "http://example.com/myUniqueId", objectType:"Activity", definition: null}}; var results = xapiValidator.validateStatement(inputStatement); expect(results.errors).to.have.property("length", 1); @@ -500,7 +503,7 @@ describe("xapiValidator", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , actor : {member:[]}, verb: { "id":"http://adlnet.gov/expapi/verbs/created", display : {"en-US":"created"}}, - object : {id : "http://example.com/myUniqueId", objectType:"Activity", + object : {id : "http://example.com/myUniqueId", objectType:"Activity", definition: []}}; var results = xapiValidator.validateStatement(inputStatement); expect(results.errors).to.have.property("length", 1); @@ -524,7 +527,7 @@ describe("xapiValidator", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , actor : {member:[]}, verb: { "id":"http://adlnet.gov/expapi/verbs/created", display : {"en-US":"created"}}, - object : {id : "http://example.com/myUniqueId", objectType:"Activity", + object : {id : "http://example.com/myUniqueId", objectType:"Activity", definition:{name:1.23}}}; var results = xapiValidator.validateStatement(inputStatement); expect(results.errors).to.have.property("length", 1); @@ -535,7 +538,7 @@ describe("xapiValidator", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , actor : {member:[]}, verb: { "id":"http://adlnet.gov/expapi/verbs/created", display : {"en-US":"created"}}, - object : {id : "http://example.com/myUniqueId", objectType:"Activity", + object : {id : "http://example.com/myUniqueId", objectType:"Activity", definition:{name:{"123 totally not a language code" : "created"}}}}; var results = xapiValidator.validateStatement(inputStatement); expect(results.errors).to.have.property("length", 1); @@ -546,20 +549,20 @@ describe("xapiValidator", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , actor : {member:[]}, verb: { "id":"http://adlnet.gov/expapi/verbs/created", display : {"en-US":"created"}}, - object : {id : "http://example.com/myUniqueId", objectType:"Activity", + object : {id : "http://example.com/myUniqueId", objectType:"Activity", definition:{type:"http://adlnet.gov/expapi/activities/cmi.interaction", interactionType:"true-false"}}}; var results = xapiValidator.validateStatement(inputStatement); expect(results.errors).to.have.property("length", 0); expect(reportHasErrorWithTracePrefix(results, "statement.object.definition.name", "MUST_VIOLATION")).to.be.false; }); - + it("a non-CMI interactionType value produces an error", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , actor : {member:[]}, verb: { "id":"http://adlnet.gov/expapi/verbs/created", display : {"en-US":"created"}}, - object : {id : "http://example.com/myUniqueId", objectType:"Activity", + object : {id : "http://example.com/myUniqueId", objectType:"Activity", definition:{type:"http://adlnet.gov/expapi/activities/cmi.interaction", interactionType:"graphicGapMatchInteraction"}}}; var results = xapiValidator.validateStatement(inputStatement); expect(results.errors).to.have.property("length", 1); @@ -570,7 +573,7 @@ describe("xapiValidator", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , actor : {member:[]}, verb: { "id":"http://adlnet.gov/expapi/verbs/created", display : {"en-US":"created"}}, - object : {id : "http://example.com/myUniqueId", objectType:"Activity", + object : {id : "http://example.com/myUniqueId", objectType:"Activity", definition:{correctResponsesPattern: 1.23}}}; var results = xapiValidator.validateStatement(inputStatement); expect(results.errors).to.have.property("length", 1); @@ -581,7 +584,7 @@ describe("xapiValidator", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , actor : {member:[]}, verb: { "id":"http://adlnet.gov/expapi/verbs/created", display : {"en-US":"created"}}, - object : {id : "http://example.com/myUniqueId", objectType:"Activity", + object : {id : "http://example.com/myUniqueId", objectType:"Activity", definition:{correctResponsesPattern: "1.23"}}}; var results = xapiValidator.validateStatement(inputStatement); expect(results.errors).to.have.property("length", 1); @@ -592,7 +595,7 @@ describe("xapiValidator", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , actor : {member:[]}, verb: { "id":"http://adlnet.gov/expapi/verbs/created", display : {"en-US":"created"}}, - object : {id : "http://example.com/myUniqueId", objectType:"Activity", + object : {id : "http://example.com/myUniqueId", objectType:"Activity", definition:{correctResponsesPattern: [1.23]}}}; var results = xapiValidator.validateStatement(inputStatement); expect(results.errors).to.have.property("length", 1); @@ -603,7 +606,7 @@ describe("xapiValidator", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , actor : {member:[]}, verb: { "id":"http://adlnet.gov/expapi/verbs/created", display : {"en-US":"created"}}, - object : {id : "http://example.com/myUniqueId", objectType:"Activity", + object : {id : "http://example.com/myUniqueId", objectType:"Activity", definition:{correctResponsesPattern: ["1.23"]}}}; var results = xapiValidator.validateStatement(inputStatement); expect(results.errors).to.have.property("length", 0); @@ -614,7 +617,7 @@ describe("xapiValidator", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , actor : {member:[]}, verb: { "id":"http://adlnet.gov/expapi/verbs/created", display : {"en-US":"created"}}, - object : {id : "http://example.com/myUniqueId", objectType:"Activity", + object : {id : "http://example.com/myUniqueId", objectType:"Activity", definition:{type:"http://example.com/somethingElse", interactionType:"choice", choices:[]}} }; var results = xapiValidator.validateStatement(inputStatement); @@ -626,7 +629,7 @@ describe("xapiValidator", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , actor : {member:[]}, verb: { "id":"http://adlnet.gov/expapi/verbs/created", display : {"en-US":"created"}}, - object : {id : "http://example.com/myUniqueId", objectType:"Activity", + object : {id : "http://example.com/myUniqueId", objectType:"Activity", definition:{type:"http://adlnet.gov/expapi/activities/cmi.interaction", interactionType:"choice", steps:[]}} }; var results = xapiValidator.validateStatement(inputStatement); @@ -638,8 +641,8 @@ describe("xapiValidator", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , actor : {member:[]}, verb: { "id":"http://adlnet.gov/expapi/verbs/created", display : {"en-US":"created"}}, - object : {id : "http://example.com/myUniqueId", objectType:"Activity", - definition:{type:"http://adlnet.gov/expapi/activities/cmi.interaction", interactionType:"choice", + object : {id : "http://example.com/myUniqueId", objectType:"Activity", + definition:{type:"http://adlnet.gov/expapi/activities/cmi.interaction", interactionType:"choice", choices:[{id:"hello invalid id", description:{}}]}} }; var results = xapiValidator.validateStatement(inputStatement); @@ -651,8 +654,8 @@ describe("xapiValidator", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , actor : {member:[]}, verb: { "id":"http://adlnet.gov/expapi/verbs/created", display : {"en-US":"created"}}, - object : {id : "http://example.com/myUniqueId", objectType:"Activity", - definition:{type:"http://adlnet.gov/expapi/activities/cmi.interaction", interactionType:"choice", + object : {id : "http://example.com/myUniqueId", objectType:"Activity", + definition:{type:"http://adlnet.gov/expapi/activities/cmi.interaction", interactionType:"choice", choices:[{id:"idA", description:{}}, {id:"idA", description:{}}]}} }; var results = xapiValidator.validateStatement(inputStatement); @@ -681,7 +684,7 @@ describe("xapiValidator", function() { expect(reportHasErrorWithTracePrefix(results, "statement.object.id", "MUST_VIOLATION")).to.be.true; }); }); - + describe("given a substatement type object", function() { it("should not report an error when valid", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0", @@ -695,7 +698,7 @@ describe("xapiValidator", function() { expect(results.errors).to.have.property("length", 0); }); - + it("reports a MUST error when the id property is present", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0", actor : {mbox:"mailto:agent@example.com"}, @@ -706,11 +709,11 @@ describe("xapiValidator", function() { verb: { "id":"http://adlnet.gov/expapi/verbs/created", "display":{"en-US":"created"}}, object: { id : "http://example.com/myUniqueId", objectType:"Activity"}}}; var results = xapiValidator.validateStatement(inputStatement); - + expect(results.errors).to.have.property("length", 1); expect(reportHasErrorWithTracePrefix(results, "statement.object.id", "MUST_VIOLATION")).to.be.true; }); - + it("reports a MUST error when the version property is present", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0", actor : {mbox:"mailto:agent@example.com"}, @@ -725,7 +728,7 @@ describe("xapiValidator", function() { expect(results.errors).to.have.property("length", 1); expect(reportHasErrorWithTracePrefix(results, "statement.object.version", "MUST_VIOLATION")).to.be.true; }); - + it("reports a MUST error when the stored property is present", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0", actor : {mbox:"mailto:agent@example.com"}, @@ -736,11 +739,11 @@ describe("xapiValidator", function() { verb: { "id":"http://adlnet.gov/expapi/verbs/created", "display":{"en-US":"created"}}, object: { id : "http://example.com/myUniqueId", objectType:"Activity"}}}; var results = xapiValidator.validateStatement(inputStatement); - + expect(results.errors).to.have.property("length", 1); expect(reportHasErrorWithTracePrefix(results, "statement.object.stored", "MUST_VIOLATION")).to.be.true; }); - + it("reports a MUST error when the authority property is present", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0", actor : {mbox:"mailto:agent@example.com"}, @@ -843,7 +846,7 @@ describe("xapiValidator", function() { result : {completion:false}}; var results = xapiValidator.validateStatement(inputStatement); expect(results.errors).to.have.property("length", 0); - + }); it("a non-String response property produces an error", function() { @@ -864,7 +867,7 @@ describe("xapiValidator", function() { object : {id : "http://example.com/myUniqueId", objectType:"Activity"}, result : {response:"idA"}}; var results = xapiValidator.validateStatement(inputStatement); - expect(results.errors).to.have.property("length", 0); + expect(results.errors).to.have.property("length", 0); }); it("a non-String duration property produces an error", function() { @@ -929,7 +932,7 @@ describe("xapiValidator", function() { object : {id : "http://example.com/myUniqueId", objectType:"Activity"}, result : {score:{raw:123}}}; var results = xapiValidator.validateStatement(inputStatement); - expect(results.errors).to.have.property("length", 0); + expect(results.errors).to.have.property("length", 0); }); it("a Number raw property below min produces an error", function() { @@ -961,7 +964,7 @@ describe("xapiValidator", function() { object : {id : "http://example.com/myUniqueId", objectType:"Activity"}, result : {score:{raw:123, min:120, max:125}}}; var results = xapiValidator.validateStatement(inputStatement); - expect(results.errors).to.have.property("length", 0); + expect(results.errors).to.have.property("length", 0); }); it("a non-Number scaled property produces an error", function() { @@ -982,7 +985,7 @@ describe("xapiValidator", function() { object : {id : "http://example.com/myUniqueId", objectType:"Activity"}, result : {score:{scaled:0.5}}}; var results = xapiValidator.validateStatement(inputStatement); - expect(results.errors).to.have.property("length", 0); + expect(results.errors).to.have.property("length", 0); }); it("a Number scaled property below 0 produces an error", function() { @@ -1025,7 +1028,7 @@ describe("xapiValidator", function() { object : {id : "http://example.com/myUniqueId", objectType:"Activity"}, result : {score:{max:123}}}; var results = xapiValidator.validateStatement(inputStatement); - expect(results.errors).to.have.property("length", 0); + expect(results.errors).to.have.property("length", 0); }); it("a Number max property below min produces an error", function() { @@ -1057,7 +1060,7 @@ describe("xapiValidator", function() { object : {id : "http://example.com/myUniqueId", objectType:"Activity"}, result : {score:{min:123}}}; var results = xapiValidator.validateStatement(inputStatement); - expect(results.errors).to.have.property("length", 0); + expect(results.errors).to.have.property("length", 0); }); it("a Number min property above max produces an error", function() { @@ -1080,7 +1083,7 @@ describe("xapiValidator", function() { object : {id : "http://example.com/myUniqueId", objectType:"Activity"}, context: {}}; var results = xapiValidator.validateStatement(inputStatement); - expect(results.errors).to.have.property("length", 0); + expect(results.errors).to.have.property("length", 0); }); it("an non-object context value produces an error", function() { @@ -1791,7 +1794,7 @@ describe("xapiValidator", function() { actor : {mbox:"mailto:agent@example.com"}, verb: { "id":"http://adlnet.gov/expapi/verbs/created", "display":{"en-US":"created"}}, object : {id : "http://example.com/myUniqueId", objectType:"Activity"}, - authority: {objectType:"Group", member:[{objectType:"Agent", mbox:"mailto:bob@example.com"}, + authority: {objectType:"Group", member:[{objectType:"Agent", mbox:"mailto:bob@example.com"}, {objectType:"Agent", mbox:"mailto:tom@example.com"}]}}; var results = xapiValidator.validateStatement(inputStatement); expect(results.errors).to.have.property("length", 0); @@ -1813,7 +1816,7 @@ describe("xapiValidator", function() { actor : {mbox:"mailto:agent@example.com"}, verb: { "id":"http://adlnet.gov/expapi/verbs/created", "display":{"en-US":"created"}}, object : {id : "http://example.com/myUniqueId", objectType:"Activity"}, - authority: {objectType:"Group", member:[{objectType:"Agent", mbox:"mailto:bob@example.com"}, + authority: {objectType:"Group", member:[{objectType:"Agent", mbox:"mailto:bob@example.com"}, {objectType:"Agent", mbox:"mailto:tom@example.com"}, {objectType:"Agent", mbox:"mailto:frank@example.com"}]}}; var results = xapiValidator.validateStatement(inputStatement); @@ -1826,7 +1829,7 @@ describe("xapiValidator", function() { actor : {mbox:"mailto:agent@example.com"}, verb: { "id":"http://adlnet.gov/expapi/verbs/created", "display":{"en-US":"created"}}, object : {id : "http://example.com/myUniqueId", objectType:"Activity"}, - authority: {objectType:"Group", member:[{objectType:"Agent", mbox:"mailto:bob@example.com"}, + authority: {objectType:"Group", member:[{objectType:"Agent", mbox:"mailto:bob@example.com"}, {objectType:"Agent"}]}}; var results = xapiValidator.validateStatement(inputStatement); expect(results.errors).to.have.property("length", 1); @@ -1855,7 +1858,7 @@ describe("xapiValidator", function() { var results = xapiValidator.validateStatement(inputStatement); expect(results.errors).to.have.property("length", 1); expect(reportHasErrorWithTracePrefix(results, "statement.version", "MUST_VIOLATION")).to.be.true; - }); + }); }); describe("for an version property with a string value", function() { @@ -1911,7 +1914,7 @@ describe("xapiValidator", function() { expect(results.errors).to.have.property("length", 1); expect(reportHasErrorWithTracePrefix(results, "statement.version", "MUST_VIOLATION")).to.be.true; }); - + it("a semantic version with SemVer 2.0.0 build release metadata not in SemVer 1.0.0 produces an error", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , actor : {mbox:"mailto:agent@example.com"}, @@ -1921,7 +1924,7 @@ describe("xapiValidator", function() { var results = xapiValidator.validateStatement(inputStatement); expect(results.errors).to.have.property("length", 1); expect(reportHasErrorWithTracePrefix(results, "statement.version", "MUST_VIOLATION")).to.be.true; - }); + }); }); describe("for an attachments property on the statement with a non-Array value", function() { @@ -1946,7 +1949,7 @@ describe("xapiValidator", function() { expect(results.errors).to.have.property("length", 1); expect(reportHasErrorWithTracePrefix(results, "statement.attachments", "MUST_VIOLATION")).to.be.true; }); - + it("an object map value produces an error", function() { var inputStatement = {id : "fd41c918-b88b-4b20-a0a5-a4c32391aaa0" , actor : {mbox:"mailto:agent@example.com"}, @@ -1956,7 +1959,7 @@ describe("xapiValidator", function() { var results = xapiValidator.validateStatement(inputStatement); expect(results.errors).to.have.property("length", 1); expect(reportHasErrorWithTracePrefix(results, "statement.attachments", "MUST_VIOLATION")).to.be.true; - }); + }); }); describe("for an attachments property on the statement with an Array value", function() { @@ -1968,7 +1971,7 @@ describe("xapiValidator", function() { attachments: []}; var results = xapiValidator.validateStatement(inputStatement); expect(results.errors).to.have.property("length", 0); - }); + }); }); describe("for an attachment object within the attachments property's Array on the statement", function() { @@ -2160,4 +2163,4 @@ describe("xapiValidator", function() { }); }); }); -}); \ No newline at end of file +}); diff --git a/xapiValidator.js b/xapiValidator.js index b25fe8e..9a44e08 100644 --- a/xapiValidator.js +++ b/xapiValidator.js @@ -1,874 +1,1620 @@ -// UMD flavor "commonjsStrictGlobal.js" from https://github.com/umdjs/umd -(function (root, factory) { - "use strict"; - if (typeof exports === 'object') { - // CommonJS - factory(exports); - } else if (typeof define === 'function' && define.amd) { - // AMD. Register as an anonymous module. - define(['exports'], function (exports) { - root.xapiValidator = exports; - factory(exports); - }); - } else { - // Browser globals - root.xapiValidator = {}; - factory(root.xapiValidator); - } -} (this, function (exports) { - "use strict"; - var MUST_VIOLATION = "MUST_VIOLATION", - SHOULD_VIOLATION = "SHOULD_VIOLATION", - MAY_VIOLATION = "MAY_VIOLATION", - toString = Object.prototype.toString, - uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i, - iso8601DurationRegex = /^P((\d+([\.,]\d+)?Y)?(\d+([\.,]\d+)?M)?(\d+([\.,]\d+)?W)?(\d+([\.,]\d+)?D)?)?(T(\d+([\.,]\d+)?H)?(\d+([\.,]\d+)?M)?(\d+([\.,]\d+)?S)?)?$/, - iso8601DateTimeRegex, - mailtoUriRegex = /^mailto:/, - semVer1p0p0Regex = /^((\d+)\.(\d+)\.(\d+))(?:-([\dA-Za-z\-]+))?$/, - base64Regex = /^(?:[A-Za-z0-9\+\/]{4})*(?:[A-Za-z0-9\+\/]{2}==|[A-Za-z0-9\+\/]{3}=|[A-Za-z0-9\+\/]{4})$/, - iriRegex, - bcp47Regex, - isArray, - ifiPropertyNames = ["mbox", "mbox_sha1sum", "openID", "account"], - cmiInteractionTypes = ["true-false", "choice", "fill-in", - "long-fill-in", "matching", "performance", - "sequencing", "likert", "numeric", - "other"]; - iriRegex = /^[a-z](?:[\-a-z0-9\+\.])*:(?:\/\/(?:(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:])*@)?(?:\[(?:(?:(?:[0-9a-f]{1,4}:){6}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|::(?:[0-9a-f]{1,4}:){5}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:[0-9a-f]{1,4}:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3})|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+[\-a-z0-9\._~!\$&'\(\)\*\+,;=:]+)\]|(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}|(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=@])*)(?::[0-9]*)?(?:\/(?:(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@]))*)*|\/(?:(?:(?:(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@]))+)(?:\/(?:(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@]))*)*)?|(?:(?:(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@]))+)(?:\/(?:(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@]))*)*|(?!(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@])))(?:\?(?:(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@])|[\uE000-\uF8FF\uF0000-\uFFFFD|\u100000-\u10FFFD\/\?])*)?(?:\#(?:(?:%[0-9a-f][0-9a-f]|[\-a-z0-9\._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\u10000-\u1FFFD\u20000-\u2FFFD\u30000-\u3FFFD\u40000-\u4FFFD\u50000-\u5FFFD\u60000-\u6FFFD\u70000-\u7FFFD\u80000-\u8FFFD\u90000-\u9FFFD\uA0000-\uAFFFD\uB0000-\uBFFFD\uC0000-\uCFFFD\uD0000-\uDFFFD\uE1000-\uEFFFD!\$&'\(\)\*\+,;=:@])|[\/\?])*)?$/i; - - // 1 YYYY 2 MM 3 DD 4 HH 5 mm 6 ss 7 msec 8 Z 9 ± 10 tzHH 11 tzmm - iso8601DateTimeRegex = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/; - - bcp47Regex = /^(?:(en-GB-oed|i-(?:ami|bnn|default|enochian|hak|klingon|lux|mingo|navajo|pwn|tao|tay|tsu)|sgn-(?:BE-FR|BE-NL|CH-DE))|(art-lojban|cel-gaulish|no-(?:bok|nyn)|zh-(?:guoyu|hakka|min|min-nan|xiang)))$|^(x(?:-[0-9a-z]{1,8})+)$|^(?:((?:[a-z]{2,3}(?:(?:-[a-z]{3}){1,3})?)|[a-z]{4}|[a-z]{5,8})(?:-([a-z]{4}))?(?:-([a-z]{2}|[0-9]{3}))?((?:-(?:[a-z0-9]{5,8}|[0-9][a-z0-9]{3}))*)?((?:-[0-9a-wy-z](?:-[a-z0-9]{2,8}){1,})*)?(-x(?:-[0-9a-z]{1,8})+)?)$/i; - - function isString(obj) { - return toString.call(obj) === '[object String]'; +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.xapiValidator = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 1) { - localErrors.push(new ValidationError(addPropToTrace(localTrace, "scaled"), "If present, the scaled property value must be between 0 and 1", MUST_VIOLATION)); - } - } - if (score.min !== undefined) { - validatePropertyIsNumber(score, "min", localTrace, localErrors, false); - if (score.raw !== undefined && score.raw < score.min) { - localErrors.push(new ValidationError(addPropToTrace(localTrace, "raw"), "If both 'raw' and 'min' are present, the raw property value should be greater than min", MUST_VIOLATION)); - } - if (score.max !== undefined && score.max < score.min) { - localErrors.push(new ValidationError(addPropToTrace(localTrace, "max"), "If both 'max' and 'min' are present, the max property value should be greater than min", MUST_VIOLATION)); - } - } - if (score.max !== undefined) { - validatePropertyIsNumber(score, "max", localTrace, localErrors, false); - if (score.raw !== undefined && score.raw > score.max) { - localErrors.push(new ValidationError(addPropToTrace(localTrace, "raw"), "If both 'raw' and 'max' are present, the raw property value should be less than max", MUST_VIOLATION)); - } - } - validatePropertyIsNumber(score, "raw", localTrace, localErrors, false); - validateAbsenceOfNonWhitelistedProperties(score, ["scaled", "raw", "min", "max"], localTrace, localErrors); - return localErrors; - } +function validateStatementRef(statementRef, trace, errors) { + var localErrors, localTrace; - function validateResult(result, trace, errors) { - var localErrors = errors || [], - localTrace = trace || "result"; - if (result === undefined) { - return localErrors; - } - if (!isNonNullMapObject(result)) { - localErrors.push(new ValidationError(addPropToTrace(localTrace), "If present, the result must be a map object", MUST_VIOLATION)); - return localErrors; - } - validateScore(result.score, addPropToTrace(localTrace, "score"), localErrors); - validatePropertyIsBoolean(result, "success", localTrace, localErrors, false); - validatePropertyIsBoolean(result, "completion", localTrace, localErrors, false); - validatePropertyIsString(result, "response", localTrace, localErrors, false); - validateExtensions(result.extensions, addPropToTrace(localTrace, "extensions"), localErrors); - if (result.duration !== undefined && (result.duration === null || !isString(result.duration) || !iso8601DurationRegex.test(result.duration))) { - localErrors.push(new ValidationError(addPropToTrace(localTrace, "duration"), "If present, the duration property value must be an ISO 8601 duration", MUST_VIOLATION)); - } - validateAbsenceOfNonWhitelistedProperties(result, ["score", "success", "completion", "response", "duration", "extensions"], localTrace, localErrors); + localErrors = errors || []; + localTrace = trace || _properties.properties.STATEMENT_REF; - return localErrors; - } + if (!_utils.xapiValidationUtils.isNonNullMapObject(statementRef)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.STATEMENT_REF_MUST_NOT_BE_NULL_MAP_OBJECTS, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + return localErrors; + } - - function validatePropertyIsISO8601String(parent, propertyName, trace, errors) { - var localErrors = errors || [], - localTrace = trace || "datetime", - matched, - datetime = parent[propertyName]; - if (datetime === undefined) { - return localErrors; - } - if (datetime === null || !isString(datetime)) { - localErrors.push(new ValidationError(localTraceToString(localTrace, propertyName), "This property must be a string value, but was null or another value type.", MUST_VIOLATION)); - return localErrors; - } - matched = iso8601DateTimeRegex.exec(datetime); - if (matched) { - if (!(matched[8] || (matched[9] && matched[10]))) { - localErrors.push(new ValidationError(localTraceToString(localTrace, propertyName), "ISO 8601 date time strings used in the xAPI should include time zone information.", SHOULD_VIOLATION)); - } - } else { - localErrors.push(new ValidationError(localTraceToString(localTrace, propertyName), "This property's string value must be conformant to ISO 8601 for Date Times.", MUST_VIOLATION)); - } + if (statementRef.objectType !== _properties.objectTypes.STATEMENT_REF) { + localErrors.push({ + trace: _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.OBJECT_TYPE), + message: _errors.xapiValidationErrors.OBJECT_TYPE_MUST_BE_STATEMENT_REF, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } - return localErrors; - } + if (!statementRef.id || !_regex.xapiValidationRegex.UUID.test(statementRef.id)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.ID), + message: _errors.xapiValidationErrors.ID_MUST_BE_VALID_UUID_REF, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } - + validateAbsenceOfNonWhitelistedProperties(statementRef, _properties.xapiWhiteListProperties.STATEMENT_REF, localTrace, localErrors); - function validateVersion(version, trace, errors) { - var localErrors = errors || [], - localTrace = trace || "version"; - if (version === undefined) { - return localErrors; - } - if (version === null || !isString(version) || !semVer1p0p0Regex.test(version)) { - localErrors.push(new ValidationError(localTraceToString(localTrace), "version must be a non-null string that complies with Semantic Versioning 1.0.0", MUST_VIOLATION)); - } - return localErrors; - } + return localErrors; +} - function validateAttachmentObject(attachment, trace, errors) { - var localErrors = errors || [], - localTrace = trace || "attachment"; - if (!isNonNullMapObject(attachment)) { - localErrors.push(new ValidationError(localTraceToString(localTrace), "attachment instances must be non-null map objects.", MUST_VIOLATION)); - return localErrors; - } - if (attachment.display === undefined) { - localErrors.push(new ValidationError(localTraceToString(localTrace, "display"), "display property must be provided.", MUST_VIOLATION)); - } else { - validateLanguageMap(attachment.display, addPropToTrace(localTrace, "display"), localErrors); - } - validateLanguageMap(attachment.description, addPropToTrace(localTrace, "description"), localErrors); +function validateScore(score, trace, errors) { + var localErrors, localTrace; - validatePropertyIsUri(attachment, "usageType", localTrace, localErrors, true, MUST_VIOLATION); - validatePropertyIsUri(attachment, "fileUrl", localTrace, localErrors, false, MUST_VIOLATION); + localErrors = errors || []; + localTrace = trace || _properties.properties.SCORE; - // TODO - more complete validation for Internet Media Type via RFC 2046 - validatePropertyIsString(attachment, "contentType", localTrace, localErrors, true, MUST_VIOLATION); - if (attachment.length === undefined || attachment.length === null || !isNumber(attachment.length) || !(attachment.length % 1 === 0)) { - localErrors.push(new ValidationError(localTraceToString(localTrace, "length"), "length property must be provided with an integer value", MUST_VIOLATION)); - } + if (score === undefined) { + return localErrors; + } - if (attachment.sha2 === undefined) { - localErrors.push(new ValidationError(localTraceToString(localTrace, "sha2"), "sha2 property must be provided on attachment objects", MUST_VIOLATION)); - } else if (attachment.sha2 === null || !isString(attachment.sha2) || !base64Regex.test(attachment.sha2)) { - localErrors.push(new ValidationError(localTraceToString(localTrace, "sha2"), "sha2 property must contain a string with bas64 contents", MUST_VIOLATION)); - } + validatePropertyIsNumber(score, _properties.properties.SCALED, localTrace, localErrors, /*isRequired*/false); - validateAbsenceOfNonWhitelistedProperties(attachment, ["usageType", "display", "description", "contentType", "length", "sha2", "fileUrl"], localTrace, localErrors); - return localErrors; + if (score.scaled !== undefined) { + if (score.scaled < _general.xapiGeneral.MIN_SCALED_VALUE || score.scaled > _general.xapiGeneral.MAX_SCALED_VALUE) { + localErrors.push({ + trace: _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.SCALED), + message: _errors.xapiValidationErrors.SCALED_MUST_BE_BETWEEN_0_1, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); } + } - function validateAttachments(attachments, trace, errors) { - var localErrors = errors || [], - localTrace = trace || "attachments", - numAttachments, - i; - if (attachments === undefined) { - return localErrors; - } - if (attachments === null || !isArray(attachments)) { - localErrors.push(new ValidationError(localTraceToString(localTrace), "attachments must be a non-null Array.", MUST_VIOLATION)); - return localErrors; - } - numAttachments = attachments.length; - for (i = 0; i < numAttachments; i+=1) { - validateAttachmentObject(attachments[i], addLookupToTrace(localTrace, i), localErrors); - } - return localErrors; - } + if (score.min !== undefined) { + validatePropertyIsNumber(score, _properties.properties.MIN, localTrace, localErrors, /*isRequired*/false); - function isGroup(actorOrGroup) { - return (actorOrGroup.member !== null && actorOrGroup.member !== undefined) || actorOrGroup.objectType === "Group"; + if (score.raw !== undefined && score.raw < score.min) { + localErrors.push({ + trace: _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.RAW), + message: _errors.xapiValidationErrors.RAW_MUST_BE_GREATER_THAN_MIN, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); } - function validateAgent(agent, trace, errors) { - var localErrors = errors || [], - localTrace = trace || "agent", - ifiCount; - if (!isNonNullMapObject(agent)) { - localErrors.push(new ValidationError(localTraceToString(localTrace), "Agent must be a non-null map object", MUST_VIOLATION)); - return localErrors; - } - - ifiCount = getIFICount(agent); - if (ifiCount !== 1) { - localErrors.push(new ValidationError(localTraceToString(localTrace), "Exactly one Inverse Functional Identifier property must be specified.", MUST_VIOLATION)); - } - if (agent.objectType === "Group") { - localErrors.push(new ValidationError(localTraceToString(localTrace), "Invalid object with characteristics of a Group when an Agent was expected.", MUST_VIOLATION)); - } - validateIFIProperties(agent, localTrace, localErrors); - validatePropertyIsString(agent, "name", localTrace, localErrors, false); - - validateAbsenceOfNonWhitelistedProperties(agent, ["objectType", "name"].concat(ifiPropertyNames), localTrace, localErrors); - - return localErrors; + if (score.max !== undefined && score.max < score.min) { + localErrors.push({ + trace: _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.MAX), + message: _errors.xapiValidationErrors.MAX_MUST_BE_GREATER_THAN_MIN, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); } + } - function validateGroup(group, trace, errors) { - var localErrors = errors || [], - localTrace = trace || "group", - memberTrace = addPropToTrace(localTrace, "member"), - ifiCount, - numMembers, - i; - if (!isNonNullMapObject(group)) { - localErrors.push(new ValidationError(localTraceToString(localTrace), "Group must be a non-null map object", MUST_VIOLATION)); - return localErrors; - } - - ifiCount = getIFICount(group); - if (ifiCount === 0) { - if (group.member === null || group.member === undefined) { - localErrors.push(new ValidationError(memberTrace, "member property must be provided for Anonymous Groups.", MUST_VIOLATION)); - } - } else if (ifiCount > 1) { - localErrors.push(new ValidationError(localTraceToString(localTrace), "Only one Inverse Functional Identifier property must be specified.", MUST_VIOLATION)); - } - validateIFIProperties(group, localTrace, localErrors); - validatePropertyIsString(group, "name", localTrace, localErrors, false); - - if (group.member !== undefined) { - if (group.member === null || !isArray(group.member)) { - localErrors.push(new ValidationError(localTraceToString(localTrace, "member"), "If present, the member property of a Group must be an Array", MUST_VIOLATION)); - } else { - numMembers = group.member.length; - for (i = 0; i < numMembers; i+=1) { - validateAgent(group.member[i], addLookupToTrace(memberTrace, i), localErrors); - } - } - } - - validateAbsenceOfNonWhitelistedProperties(group, ["objectType", "name", "member"].concat(ifiPropertyNames), localTrace, localErrors); + if (score.max !== undefined) { + validatePropertyIsNumber(score, _properties.properties.MAX, localTrace, localErrors, /*isRequired*/false); - return localErrors; + if (score.raw !== undefined && score.raw > score.max) { + localErrors.push({ + trace: _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.RAW), + message: _errors.xapiValidationErrors.RAW_MUST_BE_LESS_THAN_MAX, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); } - - function validateActor(actor, trace, errors) { - var localErrors = errors || [], - localTrace = trace || "actor"; - if (actor === null || actor === undefined) { - localErrors.push(new ValidationError(localTraceToString(localTrace), "Actor must be provided.", MUST_VIOLATION)); - return localErrors; - } - if (isGroup(actor)) { - validateGroup(actor, localTrace, localErrors); - } else { - validateAgent(actor, localTrace, localErrors); - } - return localErrors; + } + + validatePropertyIsNumber(score, _properties.properties.RAW, localTrace, localErrors, /*isRequired*/false); + validateAbsenceOfNonWhitelistedProperties(score, _properties.xapiWhiteListProperties.SCORE, localTrace, localErrors); + + return localErrors; +} + +function validateResult(result, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || _properties.properties.RESULT; + + if (result === undefined) { + return localErrors; + } + + if (!_utils.xapiValidationUtils.isNonNullMapObject(result)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.addPropToTrace(localTrace), + message: _errors.xapiValidationErrors.RESULT_MUST_BE_MAP_OBJECT, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + validateScore(result.score, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.SCORE), localErrors); + validatePropertyIsBoolean(result, _properties.properties.SUCCESS, localTrace, localErrors, /*isRequired*/false); + validatePropertyIsBoolean(result, _properties.properties.COMPLETION, localTrace, localErrors, /*isRequired*/false); + validatePropertyIsString(result, _properties.properties.RESPONSE, localTrace, localErrors, /*isRequired*/false); + validateExtensions(result.extensions, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.EXTENSIONS), localErrors); + + if (result.duration !== undefined && (result.duration === null || !_utils.xapiValidationUtils.isString(result.duration) || !_regex.xapiValidationRegex.ISO_8601_DURATION.test(result.duration))) { + localErrors.push({ + trace: _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.DURATION), + message: _errors.xapiValidationErrors.DURATION_MUST_BE_VALID, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + + validateAbsenceOfNonWhitelistedProperties(result, _properties.xapiWhiteListProperties.RESULT, localTrace, localErrors); + + return localErrors; +} + +function validatePropertyIsISO8601String(parent, propertyName, trace, errors) { + var localErrors, localTrace, matched, datetime; + + localErrors = errors || []; + localTrace = trace || _properties.properties.DATE_TIME; + datetime = parent[propertyName]; + + if (datetime === undefined) { + return localErrors; + } + + if (datetime === null || !_utils.xapiValidationUtils.isString(datetime)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, propertyName), + message: propertyName + ' ' + _errors.xapiValidationErrors.MUST_BE_STRING, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + matched = _regex.xapiValidationRegex.ISO_8601_DATE_TIME.exec(datetime); + + if (matched) { + if (!dateIncludesZoneInformation(matched)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, propertyName), + message: _errors.xapiValidationErrors.DATE_SHOULD_INCLUDE_ZONE_INFORMATION, + level: _errors.xapiErrorLevels.SHOULD_VIOLATION + }); } - - function validateAuthority(authority, trace, errors) { - var localErrors = errors || [], - localTrace = trace || "authority"; - if (authority === undefined) { - return localErrors; - } - if (!isNonNullMapObject(authority)) { - localErrors.push(new ValidationError(localTraceToString(localTrace), "If present, the authority property must be a non-null map object.", MUST_VIOLATION)); - return localErrors; - } - if (isGroup(authority)) { - validateGroup(authority, localTrace, localErrors); - if (!authority.member || !authority.member.length || authority.member.length !== 2) { - localErrors.push(new ValidationError(localTraceToString(localTrace, "member"), "If used as a Group, the authority property must contain a member property that is an array containing exactly two Agent objects.", MUST_VIOLATION)); - } - } else { - validateAgent(authority, localTrace, localErrors); - } - return localErrors; + } else { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, propertyName), + message: _errors.xapiValidationErrors.DATE_MUST_BE_VALID, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + + return localErrors; +} + +function validateVersion(version, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || _properties.properties.VERSION; + + if (version === undefined) { + return localErrors; + } + + if (version === null || !_utils.xapiValidationUtils.isString(version) || !_regex.xapiValidationRegex.SEMVER_1_P_0_P_0.test(version)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.VERSION_MUST_COMPLY_SEMANTIC_VERSIONING, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + + return localErrors; +} + +function validateAttachmentObject(attachment, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || _properties.properties.ATTACHMENT; + + if (!_utils.xapiValidationUtils.isNonNullMapObject(attachment)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.ATTACHMENTS_MUST_NOT_BE_NULL_MAP_OBJECTS, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + if (attachment.display === undefined) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, _properties.properties.DISPLAY), + message: _errors.xapiValidationErrors.DISPLAY_SHOULD_BE_PROVIDED, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } else { + validateLanguageMap(attachment.display, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.DISPLAY), localErrors); + } + + validateLanguageMap(attachment.description, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.DESCRIPTION), localErrors); + validatePropertyIsUri(attachment, _properties.properties.USAGE_TYPE, localTrace, localErrors, /*isRequired*/true, _errors.xapiErrorLevels.MUST_VIOLATION); + validatePropertyIsUri(attachment, _properties.properties.FILE_URL, localTrace, localErrors, /*isRequired*/false, _errors.xapiErrorLevels.MUST_VIOLATION); + + // TODO - more complete validation for Internet Media Type via RFC 2046 + validatePropertyIsString(attachment, _properties.properties.CONTENT_TYPE, localTrace, localErrors, /*isRequired*/true, _errors.xapiErrorLevels.MUST_VIOLATION); + + if (attachment.length === undefined || attachment.length === null || !_utils.xapiValidationUtils.isNumber(attachment.length) || attachment.length % 1 !== 0) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, _properties.properties.LENGTH), + message: _errors.xapiValidationErrors.LENGTH_MUST_BE_INTEGER, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + + if (attachment.sha2 === undefined) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, _properties.properties.SHA2), + message: _errors.xapiValidationErrors.SHA2_MUST_BE_PROVIDED_ON_ATTACHMENT_OBJECTS, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } else if (attachment.sha2 === null || !_utils.xapiValidationUtils.isString(attachment.sha2) || !_regex.xapiValidationRegex.BASE_64.test(attachment.sha2)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, _properties.properties.SHA2), + message: _errors.xapiValidationErrors.SHA2_MUST_CONTAIN_BASE_64_STRING, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + + validateAbsenceOfNonWhitelistedProperties(attachment, _properties.xapiWhiteListProperties.ATTACHMENT, localTrace, localErrors); + return localErrors; +} + +function validateAttachments(attachments, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || _properties.properties.ATTACHMENTS; + + if (attachments === undefined) { + return localErrors; + } + + if (attachments === null || !_utils.xapiValidationUtils.isArray(attachments)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.ATTACHMENTS_MUST_BE_NOT_NULL_ARRAY, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + attachments.forEach(function (attachment, i) { + validateAttachmentObject(attachment, _utils.xapiValidationUtils.addLookupToTrace(localTrace, i), localErrors); + }); + + return localErrors; +} + +function validateAgent(agent, trace, errors) { + var localErrors, localTrace, ifiCount; + + localErrors = errors || []; + localTrace = trace || _properties.properties.AGENT; + + if (!_utils.xapiValidationUtils.isNonNullMapObject(agent)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.AGENT_MUST_BE_NON_NULL_MAP_OBJECT, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + return localErrors; + } + + ifiCount = getIFICount(agent); + + if (ifiCount !== _general.xapiGeneral.NUMER_OF_SPECIFIED_IFI_PROPERTIES) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.AGENT_IFI_PROPERTIES_MUST_BE_SPECIFIED, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + + if (agent.objectType === _properties.objectTypes.GROUP) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.AGENT_MUST_NOT_HAVE_GROUP_CHARACTERISTICS, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + + validateIFIProperties(agent, localTrace, localErrors); + validatePropertyIsString(agent, _properties.properties.NAME, localTrace, localErrors, /*isRequired*/false); + + validateAbsenceOfNonWhitelistedProperties(agent, _properties.xapiWhiteListProperties.AGENT, localTrace, localErrors); + + return localErrors; +} + +function validateGroup(group, trace, errors) { + var localErrors, localTrace, memberTrace, ifiCount; + + localErrors = errors || []; + localTrace = trace || _properties.properties.GROUP; + memberTrace = _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.MEMBER); + + if (!_utils.xapiValidationUtils.isNonNullMapObject(group)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.GROUP_MUST_BE_NON_NULL_MAP_OBJECT, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + ifiCount = getIFICount(group); + + if (ifiCount === 0) { + if (group.member === null || group.member === undefined) { + localErrors.push({ + trace: memberTrace, + message: _errors.xapiValidationErrors.MEMBER_MUST_BE_PROVIDED_FOR_ANONYMOUS_GROUPS, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); } - - function validateContextActivitySubContext(subContext, trace, errors) { - var localErrors = errors || [], - localTrace = trace || "subContext", - numActivities, - i; - if (subContext === undefined) { - return localErrors; - } - if (subContext === null) { - localErrors.push(new ValidationError(localTraceToString(localTrace), "Context Activities property values must not be null.", MUST_VIOLATION)); - } else if (isArray(subContext)) { - numActivities = subContext.length; - for (i = 0; i < numActivities; i+=1) { - validateActivity(subContext[i], addLookupToTrace(localTrace, i), localErrors); - } - } else if (isObject(subContext)) { - localErrors.push(new ValidationError(localTraceToString(localTrace), "Context Activities property values should prefer to be an array of Activities rather than a single Activity object.", SHOULD_VIOLATION)); - validateActivity(subContext, localTrace, localErrors); - } else { - localErrors.push(new ValidationError(localTraceToString(localTrace), "Context Activities property values must be an array of Activity Objects or a single Activity Object.", MUST_VIOLATION)); - } - return localErrors; + } else if (ifiCount > _general.xapiGeneral.NUMER_OF_SPECIFIED_IFI_PROPERTIES) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.GROUP_IFI_PROPERTIES_MUST_BE_SPECIFIED, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + + validateIFIProperties(group, localTrace, localErrors); + + validatePropertyIsString(group, _properties.properties.NAME, localTrace, localErrors, /*isRequired*/false); + + if (group.member !== undefined) { + if (group.member === null || !_utils.xapiValidationUtils.isArray(group.member)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, _properties.properties.MEMBER), + message: _errors.xapiValidationErrors.GROUP_MEMBER_MUST_BE_ARRAY, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } else { + group.member.forEach(function (member, i) { + validateAgent(member, _utils.xapiValidationUtils.addLookupToTrace(memberTrace, i), localErrors); + }); } - - function validateContextActivities(contextActivities, trace, errors) { - var localErrors = errors || [], - localTrace = trace || "contextActivities"; - if (contextActivities === undefined) { - return localErrors; - } - if (!isNonNullMapObject(contextActivities)) { - localErrors.push(new ValidationError(localTraceToString(localTrace), "The Context Activities instances must be a non-null map object.", MUST_VIOLATION)); - return localErrors; - } - validateContextActivitySubContext(contextActivities.parent, addPropToTrace(localTrace, "parent"), localErrors); - validateContextActivitySubContext(contextActivities.grouping, addPropToTrace(localTrace, "grouping"), localErrors); - validateContextActivitySubContext(contextActivities.category, addPropToTrace(localTrace, "category"), localErrors); - validateContextActivitySubContext(contextActivities.other, addPropToTrace(localTrace, "other"), localErrors); - - validateAbsenceOfNonWhitelistedProperties(contextActivities, ["parent", "grouping", "category", "other"], localTrace, localErrors); - return localErrors; + } + + validateAbsenceOfNonWhitelistedProperties(group, _properties.xapiWhiteListProperties.GROUP, localTrace, localErrors); + + return localErrors; +} + +function validateActor(actor, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || _properties.properties.ACTOR; + + if (actor === null || actor === undefined) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.ACTOR_MUST_BE_PROVIDED, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + if (_utils.xapiValidationUtils.isGroup(actor, _properties.objectTypes.GROUP)) { + validateGroup(actor, localTrace, localErrors); + } else { + validateAgent(actor, localTrace, localErrors); + } + + return localErrors; +} + +function validateAuthority(authority, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || _properties.properties.AUTHORITY; + + if (authority === undefined) { + return localErrors; + } + + if (!_utils.xapiValidationUtils.isNonNullMapObject(authority)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.AUTHORITY_MUST_BE_NON_NULL_MAP_OBJECT, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + if (_utils.xapiValidationUtils.isGroup(authority, _properties.objectTypes.GROUP)) { + validateGroup(authority, localTrace, localErrors); + if (!authority.member || !authority.member.length || authority.member.length !== _general.xapiGeneral.GROUP_AUTHORITY_AGENT_MEMBERS) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, _properties.properties.MEMBER), + message: _errors.xapiValidationErrors.GROUP_AUTHORITY_AGENT_MEMBERS_MUST_BE_TWO, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); } - - function validateContext(context, trace, errors, statementObjectObjectType) { - var localErrors = errors || [], - localTrace = trace || "context"; - if (context === undefined) { - return localErrors; - } - if (!isNonNullMapObject(context)) { - localErrors.push(new ValidationError(localTrace, "If present, the context must be a non-null map object.", MUST_VIOLATION)); - return localErrors; - } - if (context.registration !== undefined && (context.registration === null || !isString(context.registration) || !uuidRegex.test(context.registration))) { - localErrors.push(new ValidationError(localTraceToString(localTrace, "registration"), "If present, the registration property must be a UUID string.", MUST_VIOLATION)); - } - if (["Group", "Agent"].indexOf(statementObjectObjectType) !== -1) { - if (context.revision !== undefined) { - localErrors.push(new ValidationError(localTraceToString(localTrace, "revision"), "The revision property must not be used if the Statement's Object is an Agent or Group.", MUST_VIOLATION)); - } - if (context.platform !== undefined) { - localErrors.push(new ValidationError(localTraceToString(localTrace, "platform"), "The platform property must not be used if the Statement's Object is an Agent or Group.", MUST_VIOLATION)); - } - } - - validatePropertyIsString(context, "revision", localTrace, localErrors, false, MUST_VIOLATION); - validatePropertyIsString(context, "platform", localTrace, localErrors, false, MUST_VIOLATION); - if (context.team !== undefined) { - validateGroup(context.team, addPropToTrace(localTrace, "team"), localErrors); - } - if (context.contextActivities !== undefined) { - validateContextActivities(context.contextActivities, addPropToTrace(localTrace, "contextActivities"), localErrors); - } - if (context.language !== undefined && !isValidLanguageTag(context.language)) { - localErrors.push(new ValidationError(localTraceToString(localTrace, "language"), "The language property must be encoded as an RFC 5646 compliant string, but was not.", MUST_VIOLATION)); - } - if (context.statement !== undefined) { - validateStatementRef(context.statement, addPropToTrace(localTrace, "statement"), localErrors); - } - - if (context.instructor !== undefined) { - if (isGroup(context.instructor)) { - validateGroup(context.instructor, addPropToTrace(localTrace, "instructor"), localErrors); - } else { - validateAgent(context.instructor, addPropToTrace(localTrace, "instructor"), localErrors); - } - } - validateExtensions(context.extensions, addPropToTrace(localTrace, "extensions"), localErrors); - validateAbsenceOfNonWhitelistedProperties(context, - ["registration", "instructor", "team", "contextActivities", "revision", "platform", "language", "statement", "extensions"], - localTrace, localErrors); - return localErrors; + } else { + validateAgent(authority, localTrace, localErrors); + } + + return localErrors; +} + +function validateContextActivitySubContext(subContext, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || _properties.properties.SUB_CONTEXT; + + if (subContext === undefined) { + return localErrors; + } + + if (subContext === null) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.CONTEXT_ACTIVITIES_MUST_NOT_BE_NULL, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } else if (_utils.xapiValidationUtils.isArray(subContext)) { + subContext.forEach(function (activity, i) { + validateActivity(activity, _utils.xapiValidationUtils.addLookupToTrace(localTrace, i), localErrors); + }); + } else if (_utils.xapiValidationUtils.isObject(subContext)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.CONTEXT_ACTIVITIES_SHOULD_BE_AN_ARRAY, + level: _errors.xapiErrorLevels.SHOULD_VIOLATION + }); + + validateActivity(subContext, localTrace, localErrors); + } else { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.CONTEXT_ACTIVITIES_MUST_BE_ARRAY_OR_ACTIVITY_OBJ, + level: _errors.xapiErrorLevels.MUST_VIOLATION }); + } + return localErrors; +} + +function validateContextActivities(contextActivities, trace, errors) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || _properties.properties.CONTEXT_ACTIVITIES; + + if (contextActivities === undefined) { + return localErrors; + } + + if (!_utils.xapiValidationUtils.isNonNullMapObject(contextActivities)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.CONTEXT_ACTIVITIES_MUST_BE_NON_NULL_MAP_OBJECT, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + return localErrors; + } + + validateContextActivitySubContext(contextActivities.parent, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.PARENT), localErrors); + validateContextActivitySubContext(contextActivities.grouping, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.GROUPING), localErrors); + validateContextActivitySubContext(contextActivities.category, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.CATEGORY), localErrors); + validateContextActivitySubContext(contextActivities.other, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.OTHER), localErrors); + + validateAbsenceOfNonWhitelistedProperties(contextActivities, _properties.xapiWhiteListProperties.CONTEXT_ACTIVITIES, localTrace, localErrors); + + return localErrors; +} + +function validateContext(context, trace, errors, statementObjectObjectType) { + var localErrors, localTrace; + + localErrors = errors || []; + localTrace = trace || _properties.properties.CONTEXT; + + if (context === undefined) { + return localErrors; + } + + if (!_utils.xapiValidationUtils.isNonNullMapObject(context)) { + localErrors.push({ + trace: localTrace, + message: _errors.xapiValidationErrors.CONTEXT_MUST_BE_NON_NUL_MAP_OBJECT, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + if (context.registration !== undefined && (context.registration === null || !_utils.xapiValidationUtils.isString(context.registration) || !_regex.xapiValidationRegex.UUID.test(context.registration))) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, _properties.properties.REGISTRATION), + message: _errors.xapiValidationErrors.REGISTRATION_MUST_BE_UUID_STRING, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + + if ([_properties.objectTypes.GROUP, _properties.objectTypes.AGENT].indexOf(statementObjectObjectType) !== _general.xapiGeneral.NO_INDEX_FOUND) { + if (context.revision !== undefined) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, _properties.properties.REVISION), + message: _errors.xapiValidationErrors.REVISION_MUST_BE_AGENT_OR_GROUP, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); } - function validateObject(object, trace, errors, isWithinSubStatement) { - var localErrors = errors || [], - localTrace = trace || "object", - objectType; - if (object === undefined) { - localErrors.push(new ValidationError(localTraceToString(localTrace), "object property must be provided.", MUST_VIOLATION)); - return localErrors; - } - if (!isNonNullMapObject(object)) { - localErrors.push(new ValidationError(localTraceToString(localTrace), "object property must be a non-null map object.", MUST_VIOLATION)); - return localErrors; - } - validatePropertyIsString(object, "objectType", localTrace, localErrors, true, SHOULD_VIOLATION); - objectType = object.objectType || "Activity"; - if (objectType === "Activity") { - validateActivity(object, localTrace, localErrors); - } else if (objectType === "Agent") { - validateAgent(object, localTrace, localErrors); - } else if (objectType === "Group") { - validateGroup(object, localTrace, localErrors); - } else if (objectType === "StatementRef") { - validateStatementRef(object, localTrace, localErrors); - } else if (objectType === "SubStatement") { - if (isWithinSubStatement) { - localErrors.push(new ValidationError(localTraceToString(localTrace, "objectType"), "A SubStatement must not contain a SubStatement", MUST_VIOLATION)); - } - validateStatement(object, localTrace, localErrors, true); - } else { - localErrors.push(new ValidationError(localTraceToString(localTrace, "objectType"), "object's objectType did not match a valid option ['Activity', 'Agent', 'Group', 'StatementRef', 'SubStatement']", MUST_VIOLATION)); - } - return localErrors; + if (context.platform !== undefined) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, _properties.properties.PLATFORM), + message: _errors.xapiValidationErrors.PLATFORM_MUST_NOT_BE_USED_WITH_REVISION_AGENT_OR_GROUP, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + } + + validatePropertyIsString(context, _properties.properties.REVISION, localTrace, localErrors, /*isRequired*/false, _errors.xapiErrorLevels.MUST_VIOLATION); + validatePropertyIsString(context, _properties.properties.PLATFORM, localTrace, localErrors, /*isRequired*/false, _errors.xapiErrorLevels.MUST_VIOLATION); + + if (context.team !== undefined) { + validateGroup(context.team, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.TEAM), localErrors); + } + + if (context.contextActivities !== undefined) { + validateContextActivities(context.contextActivities, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.CONTEXT_ACTIVITIES), localErrors); + } + + if (context.language !== undefined && !_utils.xapiValidationUtils.isValidLanguageTag(context.language, _regex.xapiValidationRegex.BCP_47)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, _properties.properties.LANGUAGE), + message: _errors.xapiValidationErrors.LANGUAGE_MUST_BE_STRING, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + + if (context.statement !== undefined) { + validateStatementRef(context.statement, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.STATEMENT), localErrors); + } + + if (context.instructor !== undefined) { + if (_utils.xapiValidationUtils.isGroup(context.instructor, _properties.objectTypes.GROUP)) { + validateGroup(context.instructor, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.INSTRUCTOR), localErrors); + } else { + validateAgent(context.instructor, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.INSTRUCTOR), localErrors); + } + } + + validateExtensions(context.extensions, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.EXTENSIONS), localErrors); + validateAbsenceOfNonWhitelistedProperties(context, _properties.xapiWhiteListProperties.EXTENSIONS, localTrace, localErrors); + + return localErrors; +} + +function validateObject(object, trace, errors, isWithinSubStatement) { + var localErrors, localTrace, objectType; + + localErrors = errors || []; + localTrace = trace || _properties.properties.OBJECT; + + if (object === undefined) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.OBJECT_MUST_BE_DEFINED, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + if (!_utils.xapiValidationUtils.isNonNullMapObject(object)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.OBJECT_MUST_BE_NON_NULL_MAP_OBJECT, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + validatePropertyIsString(object, _properties.properties.OBJECT_TYPE, localTrace, localErrors, /*isRequired*/true, _errors.xapiErrorLevels.SHOULD_VIOLATION); + + objectType = object.objectType || _properties.objectTypes.ACTIVITY; + + switch (objectType) { + case _properties.objectTypes.ACTIVITY: + validateActivity(object, localTrace, localErrors); + break; + case _properties.objectTypes.AGENT: + validateAgent(object, localTrace, localErrors); + break; + case _properties.objectTypes.GROUP: + validateGroup(object, localTrace, localErrors); + break; + case _properties.objectTypes.STATEMENT_REF: + validateStatementRef(object, localTrace, localErrors); + break; + case _properties.objectTypes.SUB_STATEMENT: + if (isWithinSubStatement) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, _properties.properties.OBJECT_TYPE), + message: _errors.xapiValidationErrors.SUB_STATEMENT_MUST_NOT_CONTAIN_SUB_STATEMENT, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + validate(object, localTrace, localErrors, /*isSubStatement*/true); + break; + default: + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, _properties.properties.OBJECT_TYPE), + message: _errors.xapiValidationErrors.OBJECT_TYPE_MUST_BE_VALID_OPTION + ' ' + _properties.xApiValidObjectTypes.toString(), + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + + return localErrors; +} + +function validate(statement, trace, errors, isSubStatement) { + var localErrors, localTrace, statementObjectObjectType, whitelistedProperties; + + localErrors = errors || []; + localTrace = trace || _properties.properties.STATEMENT; + + whitelistedProperties = _properties.xapiWhiteListProperties.STATEMENT; + + if (!_utils.xapiValidationUtils.isNonNullMapObject(statement)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace), + message: _errors.xapiValidationErrors.STATEMENT_REF_MUST_NOT_BE_NULL_MAP_OBJECTS, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + + return localErrors; + } + + if (!isSubStatement) { + if (statement.id === null || statement.id === undefined || !_utils.xapiValidationUtils.isString(statement.id)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, _properties.properties.ID), + message: _errors.xapiValidationErrors.IDS_SHOULD_BE_GENERATED_BY_LRS, + level: _errors.xapiErrorLevels.SHOULD_VIOLATION + }); + } else if (!_regex.xapiValidationRegex.UUID.test(statement.id)) { + localErrors.push({ + trace: _utils.xapiValidationUtils.localTraceToString(localTrace, _properties.properties.ID), + message: _errors.xapiValidationErrors.ID_MUST_BE_VALID, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + } else { + whitelistedProperties = _properties.xapiWhiteListProperties.SUB_STATEMENT; + } + + validateActor(statement.actor, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.ACTOR), localErrors); + validateVerb(statement.verb, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.VERB), localErrors); + validateObject(statement.object, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.OBJECT), localErrors, isSubStatement); + validateResult(statement.result, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.RESULT), localErrors); + + statementObjectObjectType = statement.object && statement.object.objectType ? statement.object.objectType : _properties.objectTypes.ACTIVITY; + + validateContext(statement.context, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.CONTEXT), localErrors, statementObjectObjectType); + validatePropertyIsISO8601String(statement, _properties.properties.TIMESTAMP, localTrace, localErrors); + validatePropertyIsISO8601String(statement, _properties.properties.STORED, localTrace, localErrors); + + validateAuthority(statement.authority, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.AUTHORITY), localErrors); + validateVersion(statement.version, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.VERSION), localErrors); + validateAttachments(statement.attachments, _utils.xapiValidationUtils.addPropToTrace(localTrace, _properties.properties.ATTACHMENTS), localErrors); + + validateAbsenceOfNonWhitelistedProperties(statement, whitelistedProperties, localTrace, localErrors); + + return localErrors; +} + +function makeStatementReport(statement) { + var localErrors; + + localErrors = []; + validate(statement, _properties.properties.STATEMENT, localErrors, /*isRequired*/false); + + return makeV1Report(statement, localErrors); +} + +function validateAmbiguousTypeStatement(statement) { + var statementObject; + + if (statement === undefined) { + return makeV1SingleErrorReport( /*instance*/null, { + trace: _properties.properties.STATEMENT, + message: _errors.xapiValidationErrors.STATEMENT_ARGUMENT_MUST_BE_PROVIDED, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + + if (statement === null) { + return makeV1SingleErrorReport( /*instance*/null, { + trace: _properties.properties.STATEMENT, + message: _errors.xapiValidationErrors.STATEMENT_MUST_NOT_BE_NULL, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + + if (_utils.xapiValidationUtils.isString(statement)) { + try { + statementObject = JSON.parse(statement); + if (statementObject === null || !_utils.xapiValidationUtils.isObject(statementObject) || _utils.xapiValidationUtils.isArray(statementObject)) { + return makeV1SingleErrorReport(statementObject, { + trace: _properties.properties.STATEMENT, + message: _errors.xapiValidationErrors.STATEMENT_MUST_BE_PARSED_CORRECTLY, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); + } + } catch (e) { + return makeV1SingleErrorReport(statementObject, { + trace: _properties.properties.STATEMENT, + message: _errors.xapiValidationErrors.INVALID_JSON + ': ' + e.message, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); } - function validateStatement(statement, trace, errors, isSubStatement) { - var localErrors = errors || [], - localTrace = trace || "statement", - statementObjectObjectType, - whitelistedProperties = ["id", "actor", "verb", "object", "result", "context", "timestamp", "stored", "authority", "version", "attachments"]; - - if (!isNonNullMapObject(statement)) { - localErrors.push(new ValidationError(localTraceToString(localTrace), "Statements must be non-null map objects", MUST_VIOLATION)); - return localErrors; - } - - if (!isSubStatement) { - if (statement.id === null || statement.id === undefined || !isString(statement.id)) { - localErrors.push(new ValidationError(localTraceToString(localTrace, "id"), "Ids should be generated by the Activity Provider, and must be generated by the LRS", SHOULD_VIOLATION)); - } else if (!uuidRegex.test(statement.id)) { - localErrors.push(new ValidationError(localTraceToString(localTrace, "id"), "Id was not a valid UUID", MUST_VIOLATION)); - } - } else { - whitelistedProperties = ["actor", "verb", "object", "result", "context", "timestamp", "attachments", "objectType"]; - } - - validateActor(statement.actor, addPropToTrace(localTrace, "actor"), localErrors); - validateVerb(statement.verb, addPropToTrace(localTrace, "verb"), localErrors); - validateObject(statement.object, addPropToTrace(localTrace, "object"), localErrors, isSubStatement); - validateResult(statement.result, addPropToTrace(localTrace, "result"), localErrors); - - statementObjectObjectType = statement.object && statement.object.objectType ? statement.object.objectType : "Activity"; - validateContext(statement.context, addPropToTrace(localTrace, "context"), localErrors, statementObjectObjectType); - validatePropertyIsISO8601String(statement, "timestamp", localTrace, localErrors); - validatePropertyIsISO8601String(statement, "stored", localTrace, localErrors); + return makeStatementReport(statementObject); + } - validateAuthority(statement.authority, addPropToTrace(localTrace, "authority"), localErrors); - validateVersion(statement.version, addPropToTrace(localTrace, "version"), localErrors); - validateAttachments(statement.attachments, addPropToTrace(localTrace, "attachments"), localErrors); + if (_utils.xapiValidationUtils.isObject(statement) && !_utils.xapiValidationUtils.isArray(statement)) { + return makeStatementReport(statement); + } - validateAbsenceOfNonWhitelistedProperties(statement, whitelistedProperties, localTrace, localErrors); + return makeV1SingleErrorReport( /*instance*/null, { + trace: _properties.properties.STATEMENT, + message: _errors.xapiValidationErrors.STATEMENT_ARGUMENT_IS_NOT_VALID, + level: _errors.xapiErrorLevels.MUST_VIOLATION + }); +} - return localErrors; - } +function dateIncludesZoneInformation(matched) { + return matched[_regex.dateFormatRegexPositions.ZONE] || matched[_regex.dateFormatRegexPositions.RELATIVE_TIME] && matched[_regex.dateFormatRegexPositions.TIME_ZONE_HOUR]; +} - function makeStatementReport(statement) { - var localErrors = []; - validateStatement(statement, "statement", localErrors, false); - return makeV1Report(statement, localErrors); - } +xapiValidation = { + validateStatement: validateAmbiguousTypeStatement +}; - function validateAmbiguousTypeStatement(statement) { - var statementObject; - if (statement === undefined) { - return makeV1SingleErrorReport(null, new ValidationError("statement", "No statement argument provided.", MUST_VIOLATION)); - } - if (statement === null) { - return makeV1SingleErrorReport(null, new ValidationError("statement", "Null statement argument provided.", MUST_VIOLATION)); - } - if (isString(statement)) { - try { - statementObject = JSON.parse(statement); - if (statementObject === null || !isObject(statementObject) || isArray(statementObject)) { - return makeV1SingleErrorReport(statementObject, new ValidationError("statement", "Null or non-object statement value parsed from provided statment JSON.", MUST_VIOLATION)); - } - } catch (e) { - return makeV1SingleErrorReport(statementObject, new ValidationError("statement", "Invalid JSON. The statement could not be parsed: " + e.message, MUST_VIOLATION)); - } - return makeStatementReport(statementObject); - } - if (isObject(statement) && !isArray(statement)) { - return makeStatementReport(statement); - } - return makeV1SingleErrorReport(null, new ValidationError("statement", "Statement argument provided was not a valid object or a valid JSON string.", MUST_VIOLATION)); - } +module.exports = xapiValidation; - exports.validateStatement = validateAmbiguousTypeStatement; -})); \ No newline at end of file +},{"./constants/errors":1,"./constants/general":2,"./constants/interaction-types":3,"./constants/properties":4,"./constants/regex":5,"./utils/utils":6}]},{},[7])(7) +}); +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJzcmMvY29uc3RhbnRzL2Vycm9ycy5qcyIsInNyYy9jb25zdGFudHMvZ2VuZXJhbC5qcyIsInNyYy9jb25zdGFudHMvaW50ZXJhY3Rpb24tdHlwZXMuanMiLCJzcmMvY29uc3RhbnRzL3Byb3BlcnRpZXMuanMiLCJzcmMvY29uc3RhbnRzL3JlZ2V4LmpzIiwic3JjL3V0aWxzL3V0aWxzLmpzIiwic3JjL3hhcGlWYWxpZGF0b3IuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTs7Ozs7QUFFQSxJQUFNLGtCQUFrQixPQUFPLE1BQVAsQ0FBYztBQUNwQyxpQkFBa0IsZUFEa0I7QUFFcEMsa0JBQWtCLGdCQUZrQjtBQUdwQyxvQkFBa0I7QUFIa0IsQ0FBZCxDQUF4Qjs7QUFNQSxJQUFNLHVCQUF1QixPQUFPLE1BQVAsQ0FBYztBQUN6QywyQ0FBa0QseUNBRFQ7QUFFekMsMEJBQWtELHlCQUZUO0FBR3pDLDBDQUFrRCxzRkFIVDtBQUl6QyxxQ0FBa0QsdUNBSlQ7QUFLekMsNkNBQWtELDRFQUxUO0FBTXpDLHNDQUFrRCx5Q0FOVDtBQU96Qyw0Q0FBa0Qsc0RBUFQ7QUFRekMseUNBQWtELHFFQVJUO0FBU3pDLG9EQUFrRCxzR0FUVDtBQVV6QyxrREFBa0QsaUVBVlQ7QUFXekMsdUNBQWtELHdEQVhUO0FBWXpDLHlDQUFrRCxxSEFaVDtBQWF6QyxzQ0FBa0QsbUVBYlQ7QUFjekMsMkNBQWtELDhFQWRUO0FBZXpDLDZDQUFrRCxrREFmVDtBQWdCekMsc0JBQWtELDRFQWhCVDtBQWlCekMsd0NBQWtELG1GQWpCVDtBQWtCekMsK0JBQWtELGtEQWxCVDtBQW1CekMsOEJBQWtELHdDQW5CVDtBQW9CekMsMEJBQWtELHdFQXBCVDtBQXFCekMsK0JBQWtELG9FQXJCVDtBQXNCekMsNkNBQWtELHNJQXRCVDtBQXVCekMsMENBQWtELHFGQXZCVDtBQXdCekMsOEJBQWtELDZEQXhCVDtBQXlCekMscUNBQWtELHVDQXpCVDtBQTBCekMscUJBQWtELHdFQTFCVDtBQTJCekMsNkJBQWtELGtGQTNCVDtBQTRCekMsb0JBQWtELHlCQTVCVDtBQTZCekMscUNBQWtELHlFQTdCVDtBQThCekMsa0NBQWtELG9GQTlCVDtBQStCekMsd0JBQWtELHFGQS9CVDtBQWdDekMsaUNBQWtELDZGQWhDVDtBQWlDekMsb0NBQWtELGlFQWpDVDtBQWtDekMsMENBQWtELDRFQWxDVDtBQW1DekMseUNBQWtELG9FQW5DVDtBQW9DekMsZ0NBQWtELGdGQXBDVDtBQXFDekMsa0NBQWtELHdHQXJDVDtBQXNDekMsZ0JBQWtELGtEQXRDVDtBQXVDekMsNEJBQWtELDRDQXZDVDtBQXdDekMsbUNBQWtELHlEQXhDVDtBQXlDekMsa0NBQWtELDJEQXpDVDtBQTBDekMsMkJBQWtELHFGQTFDVDtBQTJDekMsMEJBQWtELDBEQTNDVDtBQTRDekMsZ0NBQWtELHdGQTVDVDtBQTZDekMsZ0RBQWtELDBEQTdDVDtBQThDekMsMkJBQWtELHVEQTlDVDtBQStDekMsbUJBQWtELDBDQS9DVDtBQWdEekMsc0JBQWtELHVFQWhEVDtBQWlEekMsMEJBQWtELHNEQWpEVDtBQWtEekMsa0JBQWtELHlDQWxEVDtBQW1EekMsbUJBQWtELHNEQW5EVDtBQW9EekMsa0JBQWtELHlDQXBEVDtBQXFEekMsdUJBQWtELDBEQXJEVDtBQXNEekMsc0JBQWtELDZDQXREVDtBQXVEekMsMEJBQWtELHFDQXZEVDtBQXdEekMsc0NBQWtELGtEQXhEVDtBQXlEekMscUNBQWtELHFGQXpEVDtBQTBEekMsb0NBQWtELHFEQTFEVDtBQTJEekMsZ0NBQWtELHdGQTNEVDtBQTREekMsNkJBQWtELHFGQTVEVDtBQTZEekMsb0NBQWtELDhEQTdEVDtBQThEekMsNkJBQWtELDZDQTlEVDtBQStEekMsbUNBQWtELHlGQS9EVDtBQWdFekMsOEJBQWtELCtEQWhFVDtBQWlFekMsK0NBQWtELHdEQWpFVDtBQWtFekMsb0NBQWtELDREQWxFVDtBQW1FekMsbUNBQWtELDRFQW5F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QyxLQUNFLFFBQVEsZ0NBQXlCLGFBQWpDLEtBQW1ELFFBQVEsZ0NBQXlCLGNBQWpDLENBRDVEO0FBRUQ7O0FBRUQsaUJBQWlCO0FBQ2YscUJBQW1CO0FBREosQ0FBakI7O0FBSUEsT0FBTyxPQUFQLEdBQWlCLGNBQWpCIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsIid1c2Ugc3RyaWN0JztcblxuY29uc3QgeGFwaUVycm9yTGV2ZWxzID0gT2JqZWN0LmZyZWV6ZSh7XG4gIE1BWV9WSU9MQVRJT046ICAgICdNQVlfVklPTEFUSU9OJyxcbiAgTVVTVF9WSU9MQVRJT046ICAgJ01VU1RfVklPTEFUSU9OJyxcbiAgU0hPVUxEX1ZJT0xBVElPTjogJ1NIT1VMRF9WSU9MQVRJT04nXG59KTtcblxuY29uc3QgeGFwaVZhbGlkYXRpb25FcnJvcnMgPSBPYmplY3QuZnJlZXplKHtcbiAgQUNUSVZJVElFU19NVVNUX05PVF9CRV9OVUxMX01BUF9PQkpFQ1RTOiAgICAgICAgICAnQWN0aXZpdGllcyBtdXN0IGJlIG5vbi1udWxsIG1hcCBvYmplY3RzJyxcbiAgQUNUT1JfTVVTVF9CRV9QUk9WSURFRDogICAgICAgICAgICAgICAgICAgICAgICAgICAnQWN0b3IgbXVzdCBiZSBwcm92aWRlZC4nLFxuICBBR0VOVF9JRklfUFJPUEVSVElFU19NVVNUX0JFX1NQRUNJRklFRDogICAgICAgICAgICdFeGFjdGx5IG9uZSBJbnZlcnNlIEZ1bmN0aW9uYWwgSWRlbnRpZmllciBwcm9wZXJ0eSBtdXN0IGJlIHNwZWNpZmllZCBmb3IgYW4gXCJhZ2VudFwiLicsXG4gIEFHRU5UX01VU1RfQkVfTk9OX05VTExfTUFQX09CSkVDVDogICAgICAgICAgICAgICAgJ1wiYWdlbnRcIiBtdXN0IGJlIGEgbm9uLW51bGwgbWFwIG9iamVjdCcsXG4gIEFHRU5UX01VU1RfTk9UX0hBVkVfR1JPVVBfQ0hBUkFDVEVSSVNUSUNTOiAgICAgICAgJ0ludmFsaWQgb2JqZWN0IHdpdGggY2hhcmFjdGVyaXN0aWNzIG9mIGEgR3JvdXAgd2hlbiBhbiBBZ2VudCB3YXMgZXhwZWN0ZWQuJyxcbiAgQVRUQUNITUVOVFNfTVVTVF9CRV9OT1RfTlVMTF9BUlJBWTogICAgICAgICAgICAgICAnXCJhdHRhY2htZW50c1wiIG11c3QgYmUgYSBub24tbnVsbCBBcnJheS4nLFxuICBBVFRBQ0hNRU5UU19NVVNUX05PVF9CRV9OVUxMX01BUF9PQkpFQ1RTOiAgICAgICAgICdcImF0dGFjaG1lbnRcIiBpbnN0YW5jZXMgbXVzdCBiZSBub24tbnVsbCBtYXAgb2JqZWN0cy4nLFxuICBBVVRIT1JJVFlfTVVTVF9CRV9OT05fTlVMTF9NQVBfT0JKRUNUOiAgICAgICAgICAgICdJZiBwcmVzZW50LCB0aGUgXCJhdXRob3JpdHlcIiBwcm9wZXJ0eSBtdXN0IGJlIGEgbm9uLW51bGwgbWFwIG9iamVjdC4nLFxuICBDT05URVhUX0FDVElWSVRJRVNfTVVTVF9CRV9BUlJBWV9PUl9BQ1RJVklUWV9PQko6ICdDb250ZXh0IEFjdGl2aXRpZXMgcHJvcGVydHkgdmFsdWVzIG11c3QgYmUgYW4gYXJyYXkgb2YgQWN0aXZpdHkgT2JqZWN0cyBvciBhIHNpbmdsZSBBY3Rpdml0eSBPYmplY3QuJyxcbiAgQ09OVEVYVF9BQ1RJVklUSUVTX01VU1RfQkVfTk9OX05VTExfTUFQX09CSkVDVDogICAnVGhlIENvbnRleHQgQWN0aXZpdGllcyBpbnN0YW5jZXMgbXVzdCBiZSBhIG5vbi1udWxsIG1hcCBvYmplY3QuJyxcbiAgQ09OVEVYVF9BQ1RJVklUSUVTX01VU1RfTk9UX0JFX05VTEw6ICAgICAgICAgICAgICAnXCJDb250ZXh0IEFjdGl2aXRpZXNcIiBwcm9wZXJ0eSB2YWx1ZXMgbXVzdCBub3QgYmUgbnVsbC4nLFxuICBDT05URVhUX0FDVElWSVRJRVNfU0hPVUxEX0JFX0FOX0FSUkFZOiAgICAgICAgICAgICdDb250ZXh0IEFjdGl2aXRpZXMgcHJvcGVydHkgdmFsdWVzIHNob3VsZCBwcmVmZXIgdG8gYmUgYW4gYXJyYXkgb2YgQWN0aXZpdGllcyByYXRoZXIgdGhhbiBhIHNpbmdsZSBBY3Rpdml0eSBvYmplY3QuJyxcbiAgQ09OVEVYVF9NVVNUX0JFX05PTl9OVUxfTUFQX09CSkVDVDogICAgICAgICAgICAgICAnSWYgcHJlc2VudCwgdGhlIFwiY29udGV4dFwiIHByb3BlcnR5IG11c3QgYmUgYSBub24tbnVsbCBtYXAgb2JqZWN0LicsXG4gIENPUlJFQ1RfUkVTUE9OU0VTX1BBVFRFUk5fTVVTVF9CRV9BUlJBWTogICAgICAgICAgJ0lmIHByZXNlbnQsIHRoZSBcImNvcnJlY3RSZXNwb25zZXNQYXR0ZXJuXCIgdmFsdWUgbXVzdCBiZSBhbiBBcnJheSBvZiBzdHJpbmdzLicsXG4gIENPUlJFQ1RfUkVTUE9OU0VTX1BBVFRFUk5fTVVTVF9CRV9TVFJJTkdTOiAgICAgICAgJ1wiY29ycmVjdFJlc3BvbnNlc1BhdHRlcm5cIiBpdGVtcyBtdXN0IGJlIHN0cmluZ3MuJyxcbiAgREFURV9NVVNUX0JFX1ZBTElEOiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnVGhpcyBwcm9wZXJ0eXMgc3RyaW5nIHZhbHVlIG11c3QgYmUgY29uZm9ybWFudCB0byBJU08gODYwMSBmb3IgRGF0ZSBUaW1lcy4nLFxuICBEQVRFX1NIT1VMRF9JTkNMVURFX1pPTkVfSU5GT1JNQVRJT046ICAgICAgICAgICAgICdJU08gODYwMSBkYXRlIHRpbWUgc3RyaW5ncyB1c2VkIGluIHRoZSB4QVBJIHNob3VsZCBpbmNsdWRlIHRpbWUgem9uZSBpbmZvcm1hdGlvbi4nLFxuICBERUZJTklUSU9OU19NVVNUX0JFX09CSkVDVFM6ICAgICAgICAgICAgICAgICAgICAgICdcImRlZmluaXRpb25zXCIsIHdoZW4gcHJlc2VudCwgbXVzdCBiZSBtYXAgb2JqZWN0cycsXG4gIERJU1BMQVlfU0hPVUxEX0JFX1BST1ZJREVEOiAgICAgICAgICAgICAgICAgICAgICAgJ1wiZGlzcGxheVwiIHByb3BlcnR5IHNob3VsZCBiZSBwcm92aWRlZC4nLFxuICBEVVJBVElPTl9NVVNUX0JFX1ZBTElEOiAgICAgICAgICAgICAgICAgICAgICAgICAgICdJZiBwcmVzZW50LCB0aGUgXCJkdXJhdGlvblwiIHByb3BlcnR5IHZhbHVlIG11c3QgYmUgYW4gSVNPIDg2MDEgZHVyYXRpb24nLFxuICBFWFRFTlNJT05TX01VU1RfTk9UX0JFX05VTEw6ICAgICAgICAgICAgICAgICAgICAgICdJZiBwcmVzZW50LCB0aGUgZXh0ZW5zaW9ucyBwcm9wZXJ0eSBtdXN0IGJlIGEgbm9uLW51bGwgbWFwIG9iamVjdC4nLFxuICBHUk9VUF9BVVRIT1JJVFlfQUdFTlRfTUVNQkVSU19NVVNUX0JFX1RXTzogICAgICAgICdJZiB1c2VkIGFzIGEgR3JvdXAsIHRoZSBcImF1dGhvcml0eVwiIHByb3BlcnR5IG11c3QgY29udGFpbiBhIFwibWVtYmVyXCIgcHJvcGVydHkgdGhhdCBpcyBhbiBhcnJheSBjb250YWluaW5nIGV4YWN0bHkgdHdvIEFnZW50IG9iamVjdHMuJyxcbiAgR1JPVVBfSUZJX1BST1BFUlRJRVNfTVVTVF9CRV9TUEVDSUZJRUQ6ICAgICAgICAgICAnRXhhY3RseSBvbmUgSW52ZXJzZSBGdW5jdGlvbmFsIElkZW50aWZpZXIgcHJvcGVydHkgbXVzdCBiZSBzcGVjaWZpZWQgZm9yIGEgXCJncm91cFwiLicsXG4gIEdST1VQX01FTUJFUl9NVVNUX0JFX0FSUkFZOiAgICAgICAgICAgICAgICAgICAgICAgJ0lmIHByZXNlbnQsIHRoZSBtZW1iZXIgcHJvcGVydHkgb2YgYSBHcm91cCBtdXN0IGJlIGFuIEFycmF5JyxcbiAgR1JPVVBfTVVTVF9CRV9OT05fTlVMTF9NQVBfT0JKRUNUOiAgICAgICAgICAgICAgICAnXCJncm91cFwiIG11c3QgYmUgYSBub24tbnVsbCBtYXAgb2JqZWN0JyxcbiAgSURfTVVTVF9CRV9VTklRVUU6ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnXCJpZFwiIHByb3BlcnRpZXMgbXVzdCBiZSB1bmlxdWUgd2l0aGluIGVhY2ggaW50ZXJhY3Rpb24gY29tcG9uZW50IGFycmF5JyxcbiAgSURfTVVTVF9CRV9WQUxJRF9VVUlEX1JFRjogICAgICAgICAgICAgICAgICAgICAgICAnXCJpZFwiIHByb3BlcnR5IHZhbHVlIG11c3QgYmUgYSB2YWxpZCBVVUlEIHN0cmluZyBmb3Igc3RhdGVtZW50IHJlZmVyZW5jZSBvYmplY3RzLicsXG4gIElEX01VU1RfQkVfVkFMSUQ6ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0lkIHdhcyBub3QgYSB2YWxpZCBVVUlEJyxcbiAgSURfU0hPVUxEX05PVF9DT05UQUlOX1dISVRFU1BBQ0VTOiAgICAgICAgICAgICAgICAnXCJpZFwiIHByb3BlcnRpZXMgb24gaW50ZXJhY3Rpb24gY29tcG9uZW50cyBzaG91bGQgbm90IGNvbnRhaW4gd2hpdGVzcGFjZScsXG4gIElEU19TSE9VTERfQkVfR0VORVJBVEVEX0JZX0xSUzogICAgICAgICAgICAgICAgICAgJ0lkcyBzaG91bGQgYmUgZ2VuZXJhdGVkIGJ5IHRoZSBBY3Rpdml0eSBQcm92aWRlciwgYW5kIG11c3QgYmUgZ2VuZXJhdGVkIGJ5IHRoZSBMUlMnLFxuICBJRklfTVVTVF9CRV9NQk9YX1VSSTogICAgICAgICAgICAgICAgICAgICAgICAgICAgICdcIm1ib3hcIiBwcm9wZXJ0eSB3YXMgcmVxdWlyZWQgdG8gYmUgYSBtYWlsdG8gVVJJIHN0cmluZyBidXQgd2FzIG5vdCBhIHN0cmluZyBhdCBhbGwuJyxcbiAgSUZJX01VU1RfQkVfVkFMSURfTUJPWF9GT1JNQVQ6ICAgICAgICAgICAgICAgICAgICAnXCJtYm94XCIgcHJvcGVydHkgd2FzIHJlcXVpcmVkIHRvIGJlIGEgbWFpbHRvIFVSSSBzdHJpbmcgYnV0IGRpZCBub3QgbWF0Y2ggdGhlIG1haWx0byBmb3JtYXQuJyxcbiAgSU5URVJBQ1RJT05fQUNUSVZJVFlfU0hPVUxEX0hBVkU6ICAgICAgICAgICAgICAgICAnSW50ZXJhY3Rpb24gQWN0aXZpdHkgRGVmaW5pdGlvbnMgc2hvdWxkIGhhdmUgYSB0eXBlIHByb3BlcnR5IG9mJyxcbiAgSU5URVJBQ1RJT05fQ09NUE9ORU5UX01VU1RfTk9UX0JFX05VTEw6ICAgICAgICAgICAnVGhpcyBpbnRlcmFjdGlvbiBjb21wb25lbnQgY29sbGVjdGlvbiBtZW1iZXIgbXVzdCBiZSBhIG5vbi1udWxsIG1hcCBvYmplY3QnLFxuICBJTlRFUkFDVElPTl9DT01QT05FTlRfU0hPVUxEX0JFX0FSUkFZOiAgICAgICAgICAgICdUaGlzIGludGVyYWN0aW9uIGNvbXBvbmVudCBjb2xsZWN0aW9uIHByb3BlcnR5IHNob3VsZCBiZSBhbiBhcnJheS4nLFxuICBJTlRFUkFDVElPTl9UWVBFX01VU1RfQkVfQ01JOiAgICAgICAgICAgICAgICAgICAgICdJZiBwcmVzZW50LCB0aGUgXCJpbnRlcmFjdGlvblR5cGVcIiB2YWx1ZSBtdXN0IGJlIGEgQ01JIGludGVyYWN0aW9uIHR5cGUgb3B0aW9uLicsXG4gIElOVEVSQUNUSU9OX1RZUEVfTVVTVF9CRV9WQUxJRDogICAgICAgICAgICAgICAgICAgJ1RoaXMgaW50ZXJhY3Rpb24gY29tcG9uZW50IGNvbGxlY3Rpb24gcHJvcGVydHkgaXMgbm90IGFzc29jaWF0ZWQgd2l0aCB0aGUgcHJlc2VudCBpbnRlcmFjdGlvblR5cGUgb2Y6ICcsXG4gIElOVkFMSURfSlNPTjogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0ludmFsaWQgSlNPTi4gVGhlIHN0YXRlbWVudCBjb3VsZCBub3QgYmUgcGFyc2VkLicsXG4gIExBTkdVQUdFX01BUF9LRVlfSU5WQUxJRDogICAgICAgICAgICAgICAgICAgICAgICAgJ2tleSwgTGFuZ3VhZ2UgZG9lcyBub3QgY29uZm9ybSB0byBSRkMgNTY0NicsXG4gIExBTkdVQUdFX01BUF9LRVlfTVVTVF9CRV9TVFJJTkc6ICAgICAgICAgICAgICAgICAgJ2tleTogTGFuZ3VhZ2UgTWFwIHZhbHVlIHNob3VsZCBiZSBhIFN0cmluZywgYnV0IHdhcyBub3QnLFxuICBMQU5HVUFHRV9NQVBTX01VU1RfTk9UX0JFX05VTEw6ICAgICAgICAgICAgICAgICAgICdMYW5ndWFnZSBNYXBzLCB3aGVuIHByZXNlbnQsIG11c3QgYmUgbm9uLW51bGwgbWFwIG9iamVjdHMnLFxuICBMQU5HVUFHRV9NVVNUX0JFX1NUUklORzogICAgICAgICAgICAgICAgICAgICAgICAgICdUaGUgbGFuZ3VhZ2UgcHJvcGVydHkgbXVzdCBiZSBlbmNvZGVkIGFzIGFuIFJGQyA1NjQ2IGNvbXBsaWFudCBzdHJpbmcsIGJ1dCB3YXMgbm90LicsXG4gIExFTkdUSF9NVVNUX0JFX0lOVEVHRVI6ICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1wibGVuZ3RoXCIgcHJvcGVydHkgbXVzdCBiZSBwcm92aWRlZCB3aXRoIGFuIGludGVnZXIgdmFsdWUnLFxuICBNQVhfTVVTVF9CRV9HUkVBVEVSX1RIQU5fTUlOOiAgICAgICAgICAgICAgICAgICAgICdJZiBib3RoIFwibWF4XCIgYW5kIFwibWluXCIgYXJlIHByZXNlbnQsIHRoZSBtYXggcHJvcGVydHkgdmFsdWUgc2hvdWxkIGJlIGdyZWF0ZXIgdGhhbiBtaW4nLFxuICBNRU1CRVJfTVVTVF9CRV9QUk9WSURFRF9GT1JfQU5PTllNT1VTX0dST1VQUzogICAgICdcIm1lbWJlclwiIHByb3BlcnR5IG11c3QgYmUgcHJvdmlkZWQgZm9yIEFub255bW91cyBHcm91cHMuJyxcbiAgTVVTVF9CRV9CT09MRUFOX1BSRVNFTlQ6ICAgICAgICAgICAgICAgICAgICAgICAgICAncHJvcGVydHkgd2FzIHJlcXVpcmVkIHRvIGJlIGEgQm9vbGVhbiBidXQgd2FzIGFic2VudC4nLFxuICBNVVNUX0JFX0JPT0xFQU46ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdwcm9wZXJ0eSwgaWYgcHJlc2VudCwgbXVzdCBiZSBhIEJvb2xlYW4uJyxcbiAgTVVTVF9CRV9JUklfU1RSSU5HOiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAncHJvcGVydHksIGlmIHByZXNlbnQsIHNob3VsZCBiZSBhIElSSS1saWtlIGFic29sdXRlIFVSSSBwZXIgUkZDIDM5ODcuJyxcbiAgTVVTVF9CRV9OVU1CRVJfUFJFU0VOVDogICAgICAgICAgICAgICAgICAgICAgICAgICAncHJvcGVydHkgd2FzIHJlcXVpcmVkIHRvIGJlIGEgTnVtYmVyIGJ1dCB3YXMgYWJzZW50LicsXG4gIE1VU1RfQkVfTlVNQkVSOiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ3Byb3BlcnR5LCBpZiBwcmVzZW50LCBtdXN0IGJlIGEgTnVtYmVyLicsXG4gIE1VU1RfQkVfUFJFU0VOVDogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ3Byb3BlcnR5IHdhcyByZXF1aXJlZCB0byBiZSBhIHN0cmluZyBidXQgd2FzIGFic2VudC4nLFxuICBNVVNUX0JFX1NUUklORzogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdwcm9wZXJ0eSwgaWYgcHJlc2VudCwgbXVzdCBiZSBhIHN0cmluZy4nLFxuICBNVVNUX0JFX1VSSV9QUkVTRU5UOiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdwcm9wZXJ0eSB3YXMgcmVxdWlyZWQgdG8gYmUgYSBVUkkgc3RyaW5nIGJ1dCB3YXMgYWJzZW50LicsXG4gIE1VU1RfQkVfVVJJX1NUUklORzogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ3Byb3BlcnR5LCBpZiBwcmVzZW50LCBtdXN0IGJlIGEgVVJJIHN0cmluZy4nLFxuICBPQkpFQ1RfTVVTVF9CRV9ERUZJTkVEOiAgICAgICAgICAgICAgICAgICAgICAgICAgICdcIm9iamVjdFwiIHByb3BlcnR5IG11c3QgYmUgcHJvdmlkZWQuJyxcbiAgT0JKRUNUX01VU1RfQkVfTk9OX05VTExfTUFQX09CSkVDVDogICAgICAgICAgICAgICAnXCJvYmplY3RcIiBwcm9wZXJ0eSBtdXN0IGJlIGEgbm9uLW51bGwgbWFwIG9iamVjdC4nLFxuICBPQkpFQ1RfVFlQRV9NVVNUX0JFX1NUQVRFTUVOVF9SRUY6ICAgICAgICAgICAgICAgICdcIm9iamVjdFR5cGVcIiBwcm9wZXJ0eSB2YWx1ZSBtdXN0IGJlIFwiU3RhdGVtZW50UmVmXCIgZm9yIHN0YXRlbWVudCByZWZlcmVuY2Ugb2JqZWN0cy4nLFxuICBPQkpFQ1RfVFlQRV9NVVNUX0JFX1ZBTElEX09QVElPTjogICAgICAgICAgICAgICAgICdvYmplY3RcXCdzIFwib2JqZWN0VHlwZVwiIGRpZCBub3QgbWF0Y2ggYSB2YWxpZCBvcHRpb24nLFxuICBSQVdfTVVTVF9CRV9HUkVBVEVSX1RIQU5fTUlOOiAgICAgICAgICAgICAgICAgICAgICdJZiBib3RoIFwicmF3XCIgYW5kIFwibWluXCIgYXJlIHByZXNlbnQsIHRoZSByYXcgcHJvcGVydHkgdmFsdWUgc2hvdWxkIGJlIGdyZWF0ZXIgdGhhbiBtaW4nLFxuICBSQVdfTVVTVF9CRV9MRVNTX1RIQU5fTUFYOiAgICAgICAgICAgICAgICAgICAgICAgICdJZiBib3RoIFwicmF3XCIgYW5kIFwibWF4XCIgYXJlIHByZXNlbnQsIHRoZSByYXcgcHJvcGVydHkgdmFsdWUgc2hvdWxkIGJlIGxlc3MgdGhhbiBtYXgnLFxuICBSRUdJU1RSQVRJT05fTVVTVF9CRV9VVUlEX1NUUklORzogICAgICAgICAgICAgICAgICdJZiBwcmVzZW50LCB0aGUgcmVnaXN0cmF0aW9uIHByb3BlcnR5IG11c3QgYmUgYSBVVUlEIHN0cmluZy4nLFxuICBSRVNVTFRfTVVTVF9CRV9NQVBfT0JKRUNUOiAgICAgICAgICAgICAgICAgICAgICAgICdJZiBwcmVzZW50LCB0aGUgcmVzdWx0IG11c3QgYmUgYSBtYXAgb2JqZWN0JyxcbiAgUkVWSVNJT05fTVVTVF9CRV9BR0VOVF9PUl9HUk9VUDogICAgICAgICAgICAgICAgICAnVGhlIHJldmlzaW9uIHByb3BlcnR5IG11c3Qgbm90IGJlIHVzZWQgaWYgdGhlIFN0YXRlbWVudFxcJ3MgT2JqZWN0IGlzIGFuIEFnZW50IG9yIEdyb3VwLicsXG4gIFNDQUxFRF9NVVNUX0JFX0JFVFdFRU5fMF8xOiAgICAgICAgICAgICAgICAgICAgICAgJ0lmIHByZXNlbnQsIHRoZSBzY2FsZWQgcHJvcGVydHkgdmFsdWUgbXVzdCBiZSBiZXR3ZWVuIDAgYW5kIDEnLFxuICBTSEEyX01VU1RfQkVfUFJPVklERURfT05fQVRUQUNITUVOVF9PQkpFQ1RTOiAgICAgICdcInNoYTJcIiBwcm9wZXJ0eSBtdXN0IGJlIHByb3ZpZGVkIG9uIGF0dGFjaG1lbnQgb2JqZWN0cycsXG4gIFNIQTJfTVVTVF9DT05UQUlOX0JBU0VfNjRfU1RSSU5HOiAgICAgICAgICAgICAgICAgJ1wic2hhMlwiIHByb3BlcnR5IG11c3QgY29udGFpbiBhIHN0cmluZyB3aXRoIGJhc2U2NCBjb250ZW50cycsXG4gIFNUQVRFTUVOVF9BUkdVTUVOVF9JU19OT1RfVkFMSUQ6ICAgICAgICAgICAgICAgICAgJ1N0YXRlbWVudCBhcmd1bWVudCBwcm92aWRlZCB3YXMgbm90IGEgdmFsaWQgb2JqZWN0IG9yIGEgdmFsaWQgSlNPTiBzdHJpbmcuJyxcbiAgU1RBVEVNRU5UX0FSR1VNRU5UX01VU1RfQkVfUFJPVklERUQ6ICAgICAgICAgICAgICAnTm8gc3RhdGVtZW50IGFyZ3VtZW50IHByb3ZpZGVkLicsXG4gIFNUQVRFTUVOVF9NVVNUX0JFX1BBUlNFRF9DT1JSRUNUTFk6ICAgICAgICAgICAgICAgJ051bGwgb3Igbm9uLW9iamVjdCBzdGF0ZW1lbnQgdmFsdWUgcGFyc2VkIGZyb20gcHJvdmlkZWQgc3RhdG1lbnQgSlNPTi4nLFxuICBTVEFURU1FTlRfTVVTVF9OT1RfQkVfTlVMTDogICAgICAgICAgICAgICAgICAgICAgICdOdWxsIHN0YXRlbWVudCBhcmd1bWVudCBwcm92aWRlZC4nLFxuICBTVEFURU1FTlRfUkVGX01VU1RfTk9UX0JFX05VTExfTUFQX09CSkVDVFM6ICAgICAgICdTdGF0ZW1lbnRSZWYgaW5zdGFuY2VzIG11c3QgYmUgbm9uLW51bGwgbWFwIG9iamVjdHMnLFxuICBTVUJfU1RBVEVNRU5UX01VU1RfTk9UX0NPTlRBSU5fU1VCX1NUQVRFTUVOVDogICAgICdBIFN1YlN0YXRlbWVudCBtdXN0IG5vdCBjb250YWluIGEgU3ViU3RhdGVtZW50JyxcbiAgVU5FWFBFQ1RFRDogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnVW5leHBlY3RlZCBwcm9wZXJ0eSBub3QgcGVybWl0dGVkJyxcbiAgVkVSQl9NVVNUX0JFX1BST1ZJREVEOiAgICAgICAgICAgICAgICAgICAgICAgICAgICAnVmVyYiBtdXN0IGJlIHByb3ZpZGVkJyxcbiAgVkVSQl9NVVNUX05PVF9CRV9OVUxMOiAgICAgICAgICAgICAgICAgICAgICAgICAgICAnVmVyYiBwcm9wZXJ0eSB2YWx1ZSBtdXN0IGEgbm9uLW51bGwgbWFwIG9iamVjdC4nLFxuICBWRVJTSU9OX01VU1RfQ09NUExZX1NFTUFOVElDX1ZFUlNJT05JTkc6ICAgICAgICAgICdcInZlcnNpb25cIiBtdXN0IGJlIGEgbm9uLW51bGwgc3RyaW5nIHRoYXQgY29tcGxpZXMgd2l0aCBTZW1hbnRpYyBWZXJzaW9uaW5nIDEuMC4wJ1xufSk7XG5cbmV4cG9ydCB7eGFwaUVycm9yTGV2ZWxzfTtcbmV4cG9ydCB7eGFwaVZhbGlkYXRpb25FcnJvcnN9O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG5jb25zdCB4YXBpR2VuZXJhbCA9IE9iamVjdC5mcmVlemUoe1xuICBGSVJTVF9SRVBPUlRfVkVSU1RJT04gICAgICAgICAgICAgOiAnMS4wLjAnLFxuICBHUk9VUF9BVVRIT1JJVFlfQUdFTlRfTUVNQkVSUyAgICAgOiAyLFxuICBJTlRFUkFDVElPTl9ERUZJTklUSU9OX1RZUEUgICAgICAgOiAnaHR0cDovL2FkbG5ldC5nb3YvZXhwYXBpL2FjdGl2aXRpZXMvY21pLmludGVyYWN0aW9uJyxcbiAgTUFYX1NDQUxFRF9WQUxVRSAgICAgICAgICAgICAgICAgIDogMSxcbiAgTUlOX1NDQUxFRF9WQUxVRSAgICAgICAgICAgICAgICAgIDogMCxcbiAgTk9fSU5ERVhfRk9VTkQgICAgICAgICAgICAgICAgICAgIDogLTEsXG4gIE5VTUVSX09GX1NQRUNJRklFRF9JRklfUFJPUEVSVElFUyA6IDFcbn0pO1xuXG5leHBvcnQge3hhcGlHZW5lcmFsfTtcbiIsIid1c2Ugc3RyaWN0JztcblxuZXhwb3J0IGNvbnN0IGludGVyYWN0aW9uVHlwZXMgPSBPYmplY3QuZnJlZXplKHtcbiAgQ0hPSUNFOiAgICAgICAnY2hvaWNlJyxcbiAgRklMTF9JTjogICAgICAnZmlsbC1pbicsXG4gIExJS0VSVDogICAgICAgJ2xpa2VydCcsXG4gIExPTkdfRklMTF9JTjogJ2xvbmctZmlsbC1pbicsXG4gIE1BVENISU5HOiAgICAgJ21hdGNoaW5nJyxcbiAgTlVNRVJJQzogICAgICAnbnVtZXJpYycsXG4gIE9USEVSOiAgICAgICAgJ290aGVyJyxcbiAgUEVSRk9STUFOQ0U6ICAncGVyZm9ybWFuY2UnLFxuICBTRVFVRU5DSU5HOiAgICdzZXF1ZW5jaW5nJyxcbiAgVFJVRV9GQUxTRTogICAndHJ1ZS1mYWxzZSdcbn0pO1xuXG5leHBvcnQgY29uc3QgeGFwaVZhbGlkYXRpb25JbnRlcmFjdGlvblR5cGVzID0gT2JqZWN0LmZyZWV6ZShbXG4gIGludGVyYWN0aW9uVHlwZXMuQ0hPSUNFLFxuICBpbnRlcmFjdGlvblR5cGVzLkZJTExfSU4sXG4gIGludGVyYWN0aW9uVHlwZXMuTElLRVJULFxuICBpbnRlcmFjdGlvblR5cGVzLkxPTkdfRklMTF9JTixcbiAgaW50ZXJhY3Rpb25UeXBlcy5NQVRDSElORyxcbiAgaW50ZXJhY3Rpb25UeXBlcy5OVU1FUklDLFxuICBpbnRlcmFjdGlvblR5cGVzLk9USEVSLFxuICBpbnRlcmFjdGlvblR5cGVzLlBFUkZPUk1BTkNFLFxuICBpbnRlcmFjdGlvblR5cGVzLlNFUVVFTkNJTkcsXG4gIGludGVyYWN0aW9uVHlwZXMuVFJVRV9GQUxTRVxuXSk7XG4iLCIndXNlIHN0cmljdCc7XG5cbmNvbnN0IHByb3BlcnRpZXMgPSBPYmplY3QuZnJlZXplKHtcbiAgQUNDT1VOVDogICAgICAgICAgICAgICAgICAgJ2FjY291bnQnLFxuICBBQ1RJVklUWTogICAgICAgICAgICAgICAgICAnYWN0aXZpdHknLFxuICBBQ1RPUjogICAgICAgICAgICAgICAgICAgICAnYWN0b3InLFxuICBBR0VOVDogICAgICAgICAgICAgICAgICAgICAnYWdlbnQnLFxuICBBVFRBQ0hNRU5UOiAgICAgICAgICAgICAgICAnYXR0YWNobWVudCcsXG4gIEFUVEFDSE1FTlRTOiAgICAgICAgICAgICAgICdhdHRhY2htZW50cycsXG4gIEFVVEhPUklUWTogICAgICAgICAgICAgICAgICdhdXRob3JpdHknLFxuICBDQVRFR09SWTogICAgICAgICAgICAgICAgICAnY2F0ZWdvcnknLFxuICBDSE9JQ0U6ICAgICAgICAgICAgICAgICAgICAnY2hvaWNlJyxcbiAgQ0hPSUNFUzogICAgICAgICAgICAgICAgICAgJ2Nob2ljZXMnLFxuICBDT01QTEVUSU9OOiAgICAgICAgICAgICAgICAnY29tcGxldGlvbicsXG4gIENPTlRFTlRfVFlQRTogICAgICAgICAgICAgICdjb250ZW50VHlwZScsXG4gIENPTlRFWFRfQUNUSVZJVElFUzogICAgICAgICdjb250ZXh0QWN0aXZpdGllcycsXG4gIENPTlRFWFQ6ICAgICAgICAgICAgICAgICAgICdjb250ZXh0JyxcbiAgQ09SUkVDVF9SRVNQT05TRVNfUEFUVEVSTjogJ2NvcnJlY3RSZXNwb25zZXNQYXR0ZXJuJyxcbiAgREFURV9USU1FOiAgICAgICAgICAgICAgICAgJ2RhdGVUaW1lJyxcbiAgREVGSU5JVElPTjogICAgICAgICAgICAgICAgJ2RlZmluaXRpb24nLFxuICBERVNDUklQVElPTjogICAgICAgICAgICAgICAnZGVzY3JpcHRpb24nLFxuICBESVNQTEFZOiAgICAgICAgICAgICAgICAgICAnZGlzcGxheScsXG4gIERVUkFUSU9OOiAgICAgICAgICAgICAgICAgICdkdXJhdGlvbicsXG4gIEVYVEVOU0lPTlM6ICAgICAgICAgICAgICAgICdleHRlbnNpb25zJyxcbiAgRklMRV9VUkw6ICAgICAgICAgICAgICAgICAgJ2ZpbGVVcmwnLFxuICBHUk9VUDogICAgICAgICAgICAgICAgICAgICAnZ3JvdXAnLFxuICBHUk9VUElORzogICAgICAgICAgICAgICAgICAnZ3JvdXBpbmcnLFxuICBIT01FX1BBR0U6ICAgICAgICAgICAgICAgICAnaG9tZVBhZ2UnLFxuICBJRDogICAgICAgICAgICAgICAgICAgICAgICAnaWQnLFxuICBJTlNUUlVDVE9SOiAgICAgICAgICAgICAgICAnaW5zdHJ1Y3RvcicsXG4gIElOVEVSQUNUSU9OX0NPTVBPTkVOVFM6ICAgICdpbnRlcmFjdGlvbkNvbXBvbmVudHMnLFxuICBJTlRFUkFDVElPTl9UWVBFOiAgICAgICAgICAnaW50ZXJhY3Rpb25UeXBlJyxcbiAgTEFOR1VBR0VfTUFQOiAgICAgICAgICAgICAgJ2xhbmd1YWdlTWFwJyxcbiAgTEFOR1VBR0U6ICAgICAgICAgICAgICAgICAgJ2xhbmd1YWdlJyxcbiAgTEVOR1RIOiAgICAgICAgICAgICAgICAgICAgJ2xlbmd0aCcsXG4gIExJS0VSVDogICAgICAgICAgICAgICAgICAgICdsaWtlcnQnLFxuICBNQVRDSElORzogICAgICAgICAgICAgICAgICAnbWF0Y2hpbmcnLFxuICBNQVg6ICAgICAgICAgICAgICAgICAgICAgICAnbWF4JyxcbiAgTUJPWF9TSEFfMV9TVU06ICAgICAgICAgICAgJ21ib3hfc2hhMXN1bScsXG4gIE1CT1g6ICAgICAgICAgICAgICAgICAgICAgICdtYm94JyxcbiAgTUVNQkVSOiAgICAgICAgICAgICAgICAgICAgJ21lbWJlcicsXG4gIE1JTjogICAgICAgICAgICAgICAgICAgICAgICdtaW4nLFxuICBNT1JFX0lORk86ICAgICAgICAgICAgICAgICAnbW9yZUluZm8nLFxuICBOQU1FOiAgICAgICAgICAgICAgICAgICAgICAnbmFtZScsXG4gIE9CSkVDVF9UWVBFOiAgICAgICAgICAgICAgICdvYmplY3RUeXBlJyxcbiAgT0JKRUNUOiAgICAgICAgICAgICAgICAgICAgJ29iamVjdCcsXG4gIE9QRU5fSUQ6ICAgICAgICAgICAgICAgICAgICdvcGVuSUQnLFxuICBPVEhFUjogICAgICAgICAgICAgICAgICAgICAnb3RoZXInLFxuICBQQVJFTlQ6ICAgICAgICAgICAgICAgICAgICAncGFyZW50JyxcbiAgUEVSRk9STUFOQ0U6ICAgICAgICAgICAgICAgJ3BlcmZvcm1hbmNlJyxcbiAgUExBVEZPUk06ICAgICAgICAgICAgICAgICAgJ3BsYXRmb3JtJyxcbiAgUkFXOiAgICAgICAgICAgICAgICAgICAgICAgJ3JhdycsXG4gIFJFR0lTVFJBVElPTjogICAgICAgICAgICAgICdyZWdpc3RyYXRpb24nLFxuICBSRVNQT05TRTogICAgICAgICAgICAgICAgICAncmVzcG9uc2UnLFxuICBSRVNVTFQ6ICAgICAgICAgICAgICAgICAgICAncmVzdWx0JyxcbiAgUkVWSVNJT046ICAgICAgICAgICAgICAgICAgJ3JldmlzaW9uJyxcbiAgU0NBTEU6ICAgICAgICAgICAgICAgICAgICAgJ3NjYWxlJyxcbiAgU0NBTEVEOiAgICAgICAgICAgICAgICAgICAgJ3NjYWxlZCcsXG4gIFNDT1JFOiAgICAgICAgICAgICAgICAgICAgICdzY29yZScsXG4gIFNFUVVFTkNJTkc6ICAgICAgICAgICAgICAgICdzZXF1ZW5jaW5nJyxcbiAgU0hBMjogICAgICAgICAgICAgICAgICAgICAgJ3NoYTInLFxuICBTT1VSQ0U6ICAgICAgICAgICAgICAgICAgICAnc291cmNlJyxcbiAgU1RBVEVNRU5UX1JFRjogICAgICAgICAgICAgJ3N0YXRlbWVudFJlZicsXG4gIFNUQVRFTUVOVDogICAgICAgICAgICAgICAgICdzdGF0ZW1lbnQnLFxuICBTVEVQUzogICAgICAgICAgICAgICAgICAgICAnc3RlcHMnLFxuICBTVE9SRUQ6ICAgICAgICAgICAgICAgICAgICAnc3RvcmVkJyxcbiAgU1VCX0NPTlRFWFQ6ICAgICAgICAgICAgICAgJ3N1YkNvbnRleHQnLFxuICBTVUNDRVNTOiAgICAgICAgICAgICAgICAgICAnc3VjY2VzcycsXG4gIFRBUkdFVDogICAgICAgICAgICAgICAgICAgICd0YXJnZXQnLFxuICBURUFNOiAgICAgICAgICAgICAgICAgICAgICAndGVhbScsXG4gIFRJTUVTVEFNUDogICAgICAgICAgICAgICAgICd0aW1lc3RhbXAnLFxuICBUWVBFOiAgICAgICAgICAgICAgICAgICAgICAndHlwZScsXG4gIFVTQUdFX1RZUEU6ICAgICAgICAgICAgICAgICd1c2FnZVR5cGUnLFxuICBWRVJCOiAgICAgICAgICAgICAgICAgICAgICAndmVyYicsXG4gIFZFUlNJT046ICAgICAgICAgICAgICAgICAgICd2ZXJzaW9uJ1xufSk7XG5cbmNvbnN0IG9iamVjdFR5cGVzID0gT2JqZWN0LmZyZWV6ZSh7XG4gIEdST1VQOiAgICAgICAgICdHcm91cCcsXG4gIEFHRU5UOiAgICAgICAgICdBZ2VudCcsXG4gIEFDVElWSVRZOiAgICAgICdBY3Rpdml0eScsXG4gIFNUQVRFTUVOVF9SRUY6ICdTdGF0ZW1lbnRSZWYnLFxuICBTVUJfU1RBVEVNRU5UOiAnU3ViU3RhdGVtZW50J1xufSk7XG5cbmNvbnN0IHhhcGlWYWxpZGF0aW9uSWZpUHJvcGVydHlOYW1lcyA9IE9iamVjdC5mcmVlemUoW1xuICBwcm9wZXJ0aWVzLkFDQ09VTlQsXG4gIHByb3BlcnRpZXMuTUJPWF9TSEFfMV9TVU0sXG4gIHByb3BlcnRpZXMuTUJPWCxcbiAgcHJvcGVydGllcy5PUEVOX0lEXG5dKTtcblxuY29uc3QgeEFwaVZhbGlkT2JqZWN0VHlwZXMgPSBPYmplY3QuZnJlZXplKFtcbiAgb2JqZWN0VHlwZXMuR1JPVVAsXG4gIG9iamVjdFR5cGVzLkFHRU5ULFxuICBvYmplY3RUeXBlcy5BQ1RJVklUWSxcbiAgb2JqZWN0VHlwZXMuU1RBVEVNRU5UX1JFRixcbiAgb2JqZWN0VHlwZXMuU1VCX1NUQVRFTUVOVFxuXSk7XG5cbmNvbnN0IHhhcGlXaGl0ZUxpc3RQcm9wZXJ0aWVzID0gT2JqZWN0LmZyZWV6ZSh7XG4gIElGSTogW1xuICAgIHByb3BlcnRpZXMuSE9NRV9QQUdFLFxuICAgIHByb3BlcnRpZXMuTkFNRVxuICBdLFxuICBVUkk6IFtcbiAgICBwcm9wZXJ0aWVzLklELFxuICAgIHByb3BlcnRpZXMuRElTUExBWVxuICBdLFxuICBDT01QT05FTlRfQVJSQVk6IFtcbiAgICBwcm9wZXJ0aWVzLklELFxuICAgIHByb3BlcnRpZXMuREVTQ1JJUFRJT05cbiAgXSxcbiAgQUNUSVZJVFlfREVGSU5JVElPTjogW1xuICAgIHByb3BlcnRpZXMuTkFNRSxcbiAgICBwcm9wZXJ0aWVzLkRFU0NSSVBUSU9OLFxuICAgIHByb3BlcnRpZXMuVFlQRSxcbiAgICBwcm9wZXJ0aWVzLk1PUkVfSU5GTyxcbiAgICBwcm9wZXJ0aWVzLkVYVEVOU0lPTlMsXG4gICAgcHJvcGVydGllcy5JTlRFUkFDVElPTl9UWVBFLFxuICAgIHByb3BlcnRpZXMuQ09SUkVDVF9SRVNQT05TRVNfUEFUVEVSTixcbiAgICBwcm9wZXJ0aWVzLkNIT0lDRVMsXG4gICAgcHJvcGVydGllcy5TQ0FMRSxcbiAgICBwcm9wZXJ0aWVzLlNPVVJDRSxcbiAgICBwcm9wZXJ0aWVzLlRBUkdFVCxcbiAgICBwcm9wZXJ0aWVzLlNURVBTXG4gIF0sXG4gIEFDVElWSVRZOiBbXG4gICAgcHJvcGVydGllcy5PQkpFQ1RfVFlQRSxcbiAgICBwcm9wZXJ0aWVzLklELFxuICAgIHByb3BlcnRpZXMuREVGSU5JVElPTlxuICBdLFxuICBTVEFURU1FTlRfUkVGOiBbXG4gICAgcHJvcGVydGllcy5JRCxcbiAgICBwcm9wZXJ0aWVzLk9CSkVDVF9UWVBFXG4gIF0sXG4gIFNDT1JFOiBbXG4gICAgcHJvcGVydGllcy5TQ0FMRUQsXG4gICAgcHJvcGVydGllcy5SQVcsXG4gICAgcHJvcGVydGllcy5NSU4sXG4gICAgcHJvcGVydGllcy5NQVhcbiAgXSxcbiAgUkVTVUxUOiBbXG4gICAgcHJvcGVydGllcy5TQ09SRSxcbiAgICBwcm9wZXJ0aWVzLlNVQ0NFU1MsXG4gICAgcHJvcGVydGllcy5DT01QTEVUSU9OLFxuICAgIHByb3BlcnRpZXMuUkVTUE9OU0UsXG4gICAgcHJvcGVydGllcy5EVVJBVElPTixcbiAgICBwcm9wZXJ0aWVzLkVYVEVOU0lPTlNcbiAgXSxcbiAgQVRUQUNITUVOVDogW1xuICAgIHByb3BlcnRpZXMuVVNBR0VfVFlQRSxcbiAgICBwcm9wZXJ0aWVzLkRJU1BMQVksXG4gICAgcHJvcGVydGllcy5ERVNDUklQVElPTixcbiAgICBwcm9wZXJ0aWVzLkNPTlRFTlRfVFlQRSxcbiAgICBwcm9wZXJ0aWVzLkxFTkdUSCxcbiAgICBwcm9wZXJ0aWVzLlNIQTIsXG4gICAgcHJvcGVydGllcy5GSUxFX1VSTFxuICBdLFxuIEFHRU5UOiBbXG4gICBwcm9wZXJ0aWVzLk9CSkVDVF9UWVBFLFxuICAgcHJvcGVydGllcy5OQU1FLFxuICAgcHJvcGVydGllcy5BQ0NPVU5ULFxuICAgcHJvcGVydGllcy5NQk9YX1NIQV8xX1NVTSxcbiAgIHByb3BlcnRpZXMuTUJPWCxcbiAgIHByb3BlcnRpZXMuT1BFTl9JRFxuIF0sXG4gR1JPVVA6IFtcbiAgIHByb3BlcnRpZXMuT0JKRUNUX1RZUEUsXG4gICBwcm9wZXJ0aWVzLk5BTUUsXG4gICBwcm9wZXJ0aWVzLk1FTUJFUixcbiAgIHByb3BlcnRpZXMuQUNDT1VOVCxcbiAgIHByb3BlcnRpZXMuTUJPWF9TSEFfMV9TVU0sXG4gICBwcm9wZXJ0aWVzLk1CT1gsXG4gICBwcm9wZXJ0aWVzLk9QRU5fSURcbiBdLFxuIENPTlRFWFRfQUNUSVZJVElFUzogW1xuICAgcHJvcGVydGllcy5QQVJFTlQsXG4gICBwcm9wZXJ0aWVzLkdST1VQSU5HLFxuICAgcHJvcGVydGllcy5DQVRFR09SWSxcbiAgIHByb3BlcnRpZXMuT1RIRVJcbiBdLFxuIFNUQVRFTUVOVDogW1xuICAgcHJvcGVydGllcy5JRCxcbiAgIHByb3BlcnRpZXMuQUNUT1IsXG4gICBwcm9wZXJ0aWVzLlZFUkIsXG4gICBwcm9wZXJ0aWVzLk9CSkVDVCxcbiAgIHByb3BlcnRpZXMuUkVTVUxULFxuICAgcHJvcGVydGllcy5DT05URVhULFxuICAgcHJvcGVydGllcy5USU1FU1RBTVAsXG4gICBwcm9wZXJ0aWVzLlNUT1JFRCxcbiAgIHByb3BlcnRpZXMuQVVUSE9SSVRZLFxuICAgcHJvcGVydGllcy5WRVJTSU9OLFxuICAgcHJvcGVydGllcy5BVFRBQ0hNRU5UU1xuIF0sXG4gU1VCX1NUQVRFTUVOVDogW1xuICAgcHJvcGVydGllcy5BQ1RPUixcbiAgIHByb3BlcnRpZXMuVkVSQixcbiAgIHByb3BlcnRpZXMuT0JKRUNULFxuICAgcHJvcGVydGllcy5SRVNVTFQsXG4gICBwcm9wZXJ0aWVzLkNPTlRFWFQsXG4gICBwcm9wZXJ0aWVzLlRJTUVTVEFNUCxcbiAgIHByb3BlcnRpZXMuQVRUQUNITUVOVFMsXG4gICBwcm9wZXJ0aWVzLk9CSkVDVF9UWVBFXG4gXSxcbiBFWFRFTlNJT05TOiBbXG4gICBwcm9wZXJ0aWVzLlJFR0lTVFJBVElPTixcbiAgIHByb3BlcnRpZXMuSU5TVFJVQ1RPUixcbiAgIHByb3BlcnRpZXMuVEVBTSxcbiAgIHByb3BlcnRpZXMuQ09OVEVYVF9BQ1RJVklUSUVTLFxuICAgcHJvcGVydGllcy5SRVZJU0lPTixcbiAgIHByb3BlcnRpZXMuUExBVEZPUk0sXG4gICBwcm9wZXJ0aWVzLkxBTkdVQUdFLFxuICAgcHJvcGVydGllcy5TVEFURU1FTlQsXG4gICBwcm9wZXJ0aWVzLkVYVEVOU0lPTlNcbiBdXG59KTtcblxuZXhwb3J0IHtwcm9wZXJ0aWVzfTtcbmV4cG9ydCB7b2JqZWN0VHlwZXN9O1xuZXhwb3J0IHt4YXBpVmFsaWRhdGlvbklmaVByb3BlcnR5TmFtZXN9O1xuZXhwb3J0IHt4QXBpVmFsaWRPYmplY3RUeXBlc307XG5leHBvcnQge3hhcGlXaGl0ZUxpc3RQcm9wZXJ0aWVzfTtcbiIsIid1c2Ugc3RyaWN0JztcblxuY29uc3QgeGFwaVZhbGlkYXRpb25SZWdleCA9IE9iamVjdC5mcmVlemUoe1xuICBVVUlEOiAgICAgICAgICAgICAgICAvXlswLTlhLWZdezh9LVswLTlhLWZdezR9LVswLTlhLWZdezR9LVswLTlhLWZdezR9LVswLTlhLWZdezEyfSQvaSxcbiAgSVNPXzg2MDFfRFVSQVRJT046ICAgL15QKChcXGQrKFtcXC4sXVxcZCspP1kpPyhcXGQrKFtcXC4sXVxcZCspP00pPyhcXGQrKFtcXC4sXVxcZCspP1cpPyhcXGQrKFtcXC4sXVxcZCspP0QpPyk/KFQoXFxkKyhbXFwuLF1cXGQrKT9IKT8oXFxkKyhbXFwuLF1cXGQrKT9NKT8oXFxkKyhbXFwuLF1cXGQrKT9TKT8pPyQvLFxuICBJU09fODYwMV9EQVRFX1RJTUU6ICAvXihcXGR7NH18WytcXC1dXFxkezZ9KSg/Oi0oXFxkezJ9KSg/Oi0oXFxkezJ9KSk/KT8oPzpUKFxcZHsyfSk6KFxcZHsyfSkoPzo6KFxcZHsyfSkoPzpcXC4oXFxkezN9KSk/KT8oPzooWil8KFsrXFwtXSkoXFxkezJ9KSg/OjooXFxkezJ9KSk/KT8pPyQvLFxuICBNQUlMVE9fVVJJOiAgICAgICAgICAvXm1haWx0bzovLFxuICBDT05UQUlOU19XSElURVNQQUNFOiAvXFxzL2csXG4gIFNFTVZFUl8xX1BfMF9QXzA6ICAgIC9eKChcXGQrKVxcLihcXGQrKVxcLihcXGQrKSkoPzotKFtcXGRBLVphLXpcXC1dKykpPyQvLFxuICBCQVNFXzY0OiAgICAgICAgICAgICAvXig/OltBLVphLXowLTlcXCtcXC9dezR9KSooPzpbQS1aYS16MC05XFwrXFwvXXsyfT09fFtBLVphLXowLTlcXCtcXC9dezN9PXxbQS1aYS16MC05XFwrXFwvXXs0fSkkLyxcbiAgSVJJOiAgICAgICAgICAgICAgICAgL15bYS16XSg/OltcXC1hLXowLTlcXCtcXC5dKSo6KD86XFwvXFwvKD86KD86JVswLTlhLWZdWzAtOWEtZl18W1xcLWEtejAtOVxcLl9+XFx1MDBBMC1cXHVEN0ZGXFx1RjkwMC1cXHVGRENGXFx1RkRGMC1cXHVGRkVGXFx1MTAwMDAtXFx1MUZGRkRcXHUyMDAwMC1cXHUyRkZGRFxcdTMwMDAwLVxcdTNGRkZEXFx1NDAwMDAtXFx1NEZGRkRcXHU1MDAwMC1cXHU1RkZGRFxcdTYwMDAwLVxcdTZGRkZEXFx1NzAwMDAtXFx1N0ZGRkRcXHU4MDAwMC1cXHU4RkZGRFxcdTkwMDAwLVxcdTlGRkZEXFx1QTAwMDAtXFx1QUZGRkRcXHVCMDAwMC1cXHVCRkZGRFxcdUMwMDAwLVxcdUNGRkZEXFx1RDAwMDAtXFx1REZGRkRcXHVFMTAwMC1cXHVFRkZGRCFcXCQmJ1xcKFxcKVxcKlxcKyw7PTpdKSpAKT8oPzpcXFsoPzooPzooPzpbMC05YS1mXXsxLDR9Oil7Nn0oPzpbMC05YS1mXXsxLDR9OlswLTlhLWZdezEsNH18KD86WzAtOV18WzEtOV1bMC05XXwxWzAtOV1bMC05XXwyWzAtNF1bMC05XXwyNVswLTVdKSg/OlxcLig/OlswLTldfFsxLTldWzAtOV18MVswLTldWzAtOV18MlswLTRdWzAtOV18MjVbMC01XSkpezN9KXw6Oig/OlswLTlhLWZdezEsNH06KXs1fSg/OlswLTlhLWZdezEsNH06WzAtOWEtZl17MSw0fXwoPzpbMC05XXxbMS05XVswLTldfDFbMC05XVswLTldfDJbMC00XVswLTldfDI1WzAtNV0pKD86XFwuKD86WzAtOV18WzEtOV1bMC05XXwxWzAtOV1bMC05XXwyWzAtNF1bMC05XXwyNVswLTVdKSl7M30pfCg/OlswLTlhLWZdezEsNH0pPzo6KD86WzAtOWEtZl17MSw0fTopezR9KD86WzAtOWEtZl17MSw0fTpbMC05YS1mXXsxLDR9fCg/OlswLTldfFsxLTldWzAtOV18MVswLTldWzAtOV18MlswLTRdWzAtOV18MjVbMC01XSkoPzpcXC4oPzpbMC05XXxbMS05XVswLTldfDFbMC05XVswLTldfDJbMC00XVswLTldfDI1WzAtNV0pKXszfSl8KD86WzAtOWEtZl17MSw0fTpbMC05YS1mXXsxLDR9KT86Oig/OlswLTlhLWZdezEsNH06KXszfSg/OlswLTlhLWZdezEsNH06WzAtOWEtZl17MSw0fXwoPzpbMC05XXxbMS05XVswLTldfDFbMC05XVswLTldfDJbMC00XVswLTldfDI1WzAtNV0pKD86XFwuKD86WzAtOV18WzEtOV1bMC05XXwxWzAtOV1bMC05XXwyWzAtNF1bMC05XXwyNVswLTVdKSl7M30pfCg/Oig/OlswLTlhLWZdezEsNH06KXswLDJ9WzAtOWEtZl17MSw0fSk/OjooPzpbMC05YS1mXXsxLDR9Oil7Mn0oPzpbMC05YS1mXXsxLDR9OlswLTlhLWZdezEsNH18KD86WzAtOV18WzEtOV1bMC05XXwxWzAtOV1bMC05XXwyWzAtNF1bMC05XXwyNVswLTVdKSg/OlxcLig/OlswLTldfFsxLTldWzAtOV18MVswLTldWzAtOV18MlswLTRdWzAtOV18MjVbMC01XSkpezN9KXwoPzooPzpbMC05YS1mXXsxLDR9Oil7MCwzfVswLTlhLWZdezEsNH0pPzo6WzAtOWEtZl17MSw0fTooPzpbMC05YS1mXXsxLDR9OlswLTlhLWZdezEsNH18KD86WzAtOV18WzEtOV1bMC05XXwxWzAtOV1bMC05XXwyWzAtNF1bMC05XXwyNVswLTVdKSg/OlxcLig/OlswLTldfFsxLTldWzAtOV18MVswLTldWzAtOV18MlswLTRdWzAtOV18MjVbMC01XSkpezN9KXwoPzooPzpbMC05YS1mXXsxLDR9Oil7MCw0fVswLTlhLWZdezEsNH0pPzo6KD86WzAtOWEtZl17MSw0fTpbMC05YS1mXXsxLDR9fCg/OlswLTldfFsxLTldWzAtOV18MVswLTldWzAtOV18MlswLTRdWzAtOV18MjVbMC01XSkoPzpcXC4oPzpbMC05XXxbMS05XVswLTldfDFbMC05XVswLTldfDJbMC00XVswLTldfDI1WzAtNV0pKXszfSl8KD86KD86WzAtOWEtZl17MSw0fTopezAsNX1bMC05YS1mXXsxLDR9KT86OlswLTlhLWZdezEsNH18KD86KD86WzAtOWEtZl17MSw0fTopezAsNn1bMC05YS1mXXsxLDR9KT86Oil8dlswLTlhLWZdK1tcXC1hLXowLTlcXC5ffiFcXCQmJ1xcKFxcKVxcKlxcKyw7PTpdKylcXF18KD86WzAtOV18WzEtOV1bMC05XXwxWzAtOV1bMC05XXwyWzAtNF1bMC05XXwyNVswLTVdKSg/OlxcLig/OlswLTldfFsxLTldWzAtOV18MVswLTldWzAtOV18MlswLTRdWzAtOV18MjVbMC01XSkpezN9fCg/OiVbMC05YS1mXVswLTlhLWZdfFtcXC1hLXowLTlcXC5fflxcdTAwQTAtXFx1RDdGRlxcdUY5MDAtXFx1RkRDRlxcdUZERjAtXFx1RkZFRlxcdTEwMDAwLVxcdTFGRkZEXFx1MjAwMDAtXFx1MkZGRkRcXHUzMDAwMC1cXHUzRkZGRFxcdTQwMDAwLVxcdTRGRkZEXFx1NTAwMDAtXFx1NUZGRkRcXHU2MDAwMC1cXHU2RkZGRFxcdTcwMDAwLVxcdTdGRkZEXFx1ODAwMDAtXFx1OEZGRkRcXHU5MDAwMC1cXHU5RkZGRFxcdUEwMDAwLVxcdUFGRkZEXFx1QjAwMDAtXFx1QkZGRkRcXHVDMDAwMC1cXHVDRkZGRFxcdUQwMDAwLVxcdURGRkZEXFx1RTEwMDAtXFx1RUZGRkQhXFwkJidcXChcXClcXCpcXCssOz1AXSkqKSg/OjpbMC05XSopPyg/OlxcLyg/Oig/OiVbMC05YS1mXVswLTlhLWZdfFtcXC1hLXowLTlcXC5fflxcdTAwQTAtXFx1RDdGRlxcdUY5MDAtXFx1RkRDRlxcdUZERjAtXFx1RkZFRlxcdTEwMDAwLVxcdTFGRkZEXFx1MjAwMDAtXFx1MkZGRkRcXHUzMDAwMC1cXHUzRkZGRFxcdTQwMDAwLVxcdTRGRkZEXFx1NTAwMDAtXFx1NUZGRkRcXHU2MDAwMC1cXHU2RkZGRFxcdTcwMDAwLVxcdTdGRkZEXFx1ODAwMDAtXFx1OEZGRkRcXHU5MDAwMC1cXHU5RkZGRFxcdUEwMDAwLVxcdUFGRkZEXFx1QjAwMDAtXFx1QkZGRkRcXHVDMDAwMC1cXHVDRkZGRFxcdUQwMDAwLVxcdURGRkZEXFx1RTEwMDAtXFx1RUZGRkQhXFwkJidcXChcXClcXCpcXCssOz06QF0pKSopKnxcXC8oPzooPzooPzooPzolWzAtOWEtZl1bMC05YS1mXXxbXFwtYS16MC05XFwuX35cXHUwMEEwLVxcdUQ3RkZcXHVGOTAwLVxcdUZEQ0ZcXHVGREYwLVxcdUZGRUZcXHUxMDAwMC1cXHUxRkZGRFxcdTIwMDAwLVxcdTJGRkZEXFx1MzAwMDAtXFx1M0ZGRkRcXHU0MDAwMC1cXHU0RkZGRFxcdTUwMDAwLVxcdTVGRkZEXFx1NjAwMDAtXFx1NkZGRkRcXHU3MDAwMC1cXHU3RkZGRFxcdTgwMDAwLVxcdThGRkZEXFx1OTAwMDAtXFx1OUZGRkRcXHVBMDAwMC1cXHVBRkZGRFxcdUIwMDAwLVxcdUJGRkZEXFx1QzAwMDAtXFx1Q0ZGRkRcXHVEMDAwMC1cXHVERkZGRFxcdUUxMDAwLVxcdUVGRkZEIVxcJCYnXFwoXFwpXFwqXFwrLDs9OkBdKSkrKSg/OlxcLyg/Oig/OiVbMC05YS1mXVswLTlhLWZdfFtcXC1hLXowLTlcXC5fflxcdTAwQTAtXFx1RDdGRlxcdUY5MDAtXFx1RkRDRlxcdUZERjAtXFx1RkZFRlxcdTEwMDAwLVxcdTFGRkZEXFx1MjAwMDAtXFx1MkZGRkRcXHUzMDAwMC1cXHUzRkZGRFxcdTQwMDAwLVxcdTRGRkZEXFx1NTAwMDAtXFx1NUZGRkRcXHU2MDAwMC1cXHU2RkZGRFxcdTcwMDAwLVxcdTdGRkZEXFx1ODAwMDAtXFx1OEZGRkRcXHU5MDAwMC1cXHU5RkZGRFxcdUEwMDAwLVxcdUFGRkZEXFx1QjAwMDAtXFx1QkZGRkRcXHVDMDAwMC1cXHVDRkZGRFxcdUQwMDAwLVxcdURGRkZEXFx1RTEwMDAtXFx1RUZGRkQhXFwkJidcXChcXClcXCpcXCssOz06QF0pKSopKik/fCg/Oig/Oig/OiVbMC05YS1mXVswLTlhLWZdfFtcXC1hLXowLTlcXC5fflxcdTAwQTAtXFx1RDdGRlxcdUY5MDAtXFx1RkRDRlxcdUZERjAtXFx1RkZFRlxcdTEwMDAwLVxcdTFGRkZEXFx1MjAwMDAtXFx1MkZGRkRcXHUzMDAwMC1cXHUzRkZGRFxcdTQwMDAwLVxcdTRGRkZEXFx1NTAwMDAtXFx1NUZGRkRcXHU2MDAwMC1cXHU2RkZGRFxcdTcwMDAwLVxcdTdGRkZEXFx1ODAwMDAtXFx1OEZGRkRcXHU5MDAwMC1cXHU5RkZGRFxcdUEwMDAwLVxcdUFGRkZEXFx1QjAwMDAtXFx1QkZGRkRcXHVDMDAwMC1cXHVDRkZGRFxcdUQwMDAwLVxcdURGRkZEXFx1RTEwMDAtXFx1RUZGRkQhXFwkJidcXChcXClcXCpcXCssOz06QF0pKSspKD86XFwvKD86KD86JVswLTlhLWZdWzAtOWEtZl18W1xcLWEtejAtOVxcLl9+XFx1MDBBMC1cXHVEN0ZGXFx1RjkwMC1cXHVGRENGXFx1RkRGMC1cXHVGRkVGXFx1MTAwMDAtXFx1MUZGRkRcXHUyMDAwMC1cXHUyRkZGRFxcdTMwMDAwLVxcdTNGRkZEXFx1NDAwMDAtXFx1NEZGRkRcXHU1MDAwMC1cXHU1RkZGRFxcdTYwMDAwLVxcdTZGRkZEXFx1NzAwMDAtXFx1N0ZGRkRcXHU4MDAwMC1cXHU4RkZGRFxcdTkwMDAwLVxcdTlGRkZEXFx1QTAwMDAtXFx1QUZGRkRcXHVCMDAwMC1cXHVCRkZGRFxcdUMwMDAwLVxcdUNGRkZEXFx1RDAwMDAtXFx1REZGRkRcXHVFMTAwMC1cXHVFRkZGRCFcXCQmJ1xcKFxcKVxcKlxcKyw7PTpAXSkpKikqfCg/ISg/OiVbMC05YS1mXVswLTlhLWZdfFtcXC1hLXowLTlcXC5fflxcdTAwQTAtXFx1RDdGRlxcdUY5MDAtXFx1RkRDRlxcdUZERjAtXFx1RkZFRlxcdTEwMDAwLVxcdTFGRkZEXFx1MjAwMDAtXFx1MkZGRkRcXHUzMDAwMC1cXHUzRkZGRFxcdTQwMDAwLVxcdTRGRkZEXFx1NTAwMDAtXFx1NUZGRkRcXHU2MDAwMC1cXHU2RkZGRFxcdTcwMDAwLVxcdTdGRkZEXFx1ODAwMDAtXFx1OEZGRkRcXHU5MDAwMC1cXHU5RkZGRFxcdUEwMDAwLVxcdUFGRkZEXFx1QjAwMDAtXFx1QkZGRkRcXHVDMDAwMC1cXHVDRkZGRFxcdUQwMDAwLVxcdURGRkZEXFx1RTEwMDAtXFx1RUZGRkQhXFwkJidcXChcXClcXCpcXCssOz06QF0pKSkoPzpcXD8oPzooPzolWzAtOWEtZl1bMC05YS1mXXxbXFwtYS16MC05XFwuX35cXHUwMEEwLVxcdUQ3RkZcXHVGOTAwLVxcdUZEQ0ZcXHVGREYwLVxcdUZGRUZcXHUxMDAwMC1cXHUxRkZGRFxcdTIwMDAwLVxcdTJGRkZEXFx1MzAwMDAtXFx1M0ZGRkRcXHU0MDAwMC1cXHU0RkZGRFxcdTUwMDAwLVxcdTVGRkZEXFx1NjAwMDAtXFx1NkZGRkRcXHU3MDAwMC1cXHU3RkZGRFxcdTgwMDAwLVxcdThGRkZEXFx1OTAwMDAtXFx1OUZGRkRcXHVBMDAwMC1cXHVBRkZGRFxcdUIwMDAwLVxcdUJGRkZEXFx1QzAwMDAtXFx1Q0ZGRkRcXHVEMDAwMC1cXHVERkZGRFxcdUUxMDAwLVxcdUVGRkZEIVxcJCYnXFwoXFwpXFwqXFwrLDs9OkBdKXxbXFx1RTAwMC1cXHVGOEZGXFx1RjAwMDAtXFx1RkZGRkR8XFx1MTAwMDAwLVxcdTEwRkZGRFxcL1xcP10pKik/KD86XFwjKD86KD86JVswLTlhLWZdWzAtOWEtZl18W1xcLWEtejAtOVxcLl9+XFx1MDBBMC1cXHVEN0ZGXFx1RjkwMC1cXHVGRENGXFx1RkRGMC1cXHVGRkVGXFx1MTAwMDAtXFx1MUZGRkRcXHUyMDAwMC1cXHUyRkZGRFxcdTMwMDAwLVxcdTNGRkZEXFx1NDAwMDAtXFx1NEZGRkRcXHU1MDAwMC1cXHU1RkZGRFxcdTYwMDAwLVxcdTZGRkZEXFx1NzAwMDAtXFx1N0ZGRkRcXHU4MDAwMC1cXHU4RkZGRFxcdTkwMDAwLVxcdTlGRkZEXFx1QTAwMDAtXFx1QUZGRkRcXHVCMDAwMC1cXHVCRkZGRFxcdUMwMDAwLVxcdUNGRkZEXFx1RDAwMDAtXFx1REZGRkRcXHVFMTAwMC1cXHVFRkZGRCFcXCQmJ1xcKFxcKVxcKlxcKyw7PTpAXSl8W1xcL1xcP10pKik/JC9pLFxuICBCQ1BfNDc6ICAgICAgICAgICAgICAvXig/Oihlbi1HQi1vZWR8aS0oPzphbWl8Ym5ufGRlZmF1bHR8ZW5vY2hpYW58aGFrfGtsaW5nb258bHV4fG1pbmdvfG5hdmFqb3xwd258dGFvfHRheXx0c3UpfHNnbi0oPzpCRS1GUnxCRS1OTHxDSC1ERSkpfChhcnQtbG9qYmFufGNlbC1nYXVsaXNofG5vLSg/OmJva3xueW4pfHpoLSg/Omd1b3l1fGhha2thfG1pbnxtaW4tbmFufHhpYW5nKSkpJHxeKHgoPzotWzAtOWEtel17MSw4fSkrKSR8Xig/OigoPzpbYS16XXsyLDN9KD86KD86LVthLXpdezN9KXsxLDN9KT8pfFthLXpdezR9fFthLXpdezUsOH0pKD86LShbYS16XXs0fSkpPyg/Oi0oW2Etel17Mn18WzAtOV17M30pKT8oKD86LSg/OlthLXowLTldezUsOH18WzAtOV1bYS16MC05XXszfSkpKik/KCg/Oi1bMC05YS13eS16XSg/Oi1bYS16MC05XXsyLDh9KXsxLH0pKik/KC14KD86LVswLTlhLXpdezEsOH0pKyk/KSQvaVxufSk7XG5cbmNvbnN0IGRhdGVGb3JtYXRSZWdleFBvc2l0aW9ucyA9IE9iamVjdC5mcmVlemUoe1xuICBZRUFSOiAgICAgICAgICAgICAxLFxuICBNT05USDogICAgICAgICAgICAyLFxuICBEQVk6ICAgICAgICAgICAgICAzLFxuICBIT1VSOiAgICAgICAgICAgICA0LFxuICBNSU5VVEU6ICAgICAgICAgICA1LFxuICBTRUNPTkQ6ICAgICAgICAgICA2LFxuICBNU0VDT05EOiAgICAgICAgICA3LFxuICBaT05FOiAgICAgICAgICAgICA4LFxuICBSRUxBVElWRV9USU1FOiAgICA5LFxuICBUSU1FX1pPTkVfSE9VUjogICAxMCxcbiAgVElNRV9aT05FX01JTlVURTogMTFcbn0pO1xuXG5leHBvcnQge3hhcGlWYWxpZGF0aW9uUmVnZXh9O1xuZXhwb3J0IHtkYXRlRm9ybWF0UmVnZXhQb3NpdGlvbnN9O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG5jb25zdFxuICBJU19TVFJJTkcgID0gJ1tvYmplY3QgU3RyaW5nXScsXG4gIElTX0FSUkFZICAgPSAnW29iamVjdCBBcnJheV0nLFxuICBJU19CT09MRUFOID0gJ1tvYmplY3QgQm9vbGVhbl0nLFxuICBJU19OVU1CRVIgID0gJ1tvYmplY3QgTnVtYmVyXSdcbjtcblxudmFyIHRvU3RyaW5nID0gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZztcbnZhciB4YXBpVmFsaWRhdGlvblV0aWxzO1xuXG54YXBpVmFsaWRhdGlvblV0aWxzID0ge1xuICBpc1N0cmluZyhvYmopIHtcbiAgICByZXR1cm4gdG9TdHJpbmcuY2FsbChvYmopID09PSBJU19TVFJJTkc7XG4gIH0sXG5cbiAgaXNPYmplY3Qob2JqKSB7XG4gICAgcmV0dXJuIG9iaiA9PT0gT2JqZWN0KG9iaik7XG4gIH0sXG5cbiAgaXNBcnJheTogQXJyYXkuaXNBcnJheSB8fCBmdW5jdGlvbihvYmopIHtcbiAgICByZXR1cm4gdG9TdHJpbmcuY2FsbChvYmopID09PSBJU19BUlJBWTtcbiAgfSxcblxuICBpc0Jvb2xlYW4ob2JqKSB7XG4gICAgcmV0dXJuIG9iaiA9PT0gdHJ1ZSB8fCBvYmogPT09IGZhbHNlIHx8IHRvU3RyaW5nLmNhbGwob2JqKSA9PT0gSVNfQk9PTEVBTjtcbiAgfSxcblxuICBpc051bWJlcihvYmopIHtcbiAgICByZXR1cm4gdG9TdHJpbmcuY2FsbChvYmopID09PSBJU19OVU1CRVI7XG4gIH0sXG5cbiAgaXNEZWZpbmVkKG9iaikge1xuICAgIHJldHVybiAob2JqICE9PSBudWxsIHx8IG9iaiAhPT0gdW5kZWZpbmVkKTtcbiAgfSxcblxuICBpc05vbk51bGxNYXBPYmplY3QodGFyZ2V0KSB7XG4gICAgICByZXR1cm4gdGhpcy5pc0RlZmluZWQodGFyZ2V0KSAmJiB0aGlzLmlzT2JqZWN0KHRhcmdldCkgJiYgIXRoaXMuaXNBcnJheSh0YXJnZXQpO1xuICB9LFxuXG4gIGlzVmFsaWRMYW5ndWFnZVRhZyh0YXJnZXQsIHZhbGlkTGFuZ3VhZ2VSZWdleCkge1xuICAgIC8vIFRPRE8gLSB1c2UgbW9yZSBwcmVjaXNlIDU2NDYgaGFuZGxpbmcsIHJhdGhlciB0aGFuIHRoaXMgc2ltcGxpZmllZCBCQ1AgNDcgcmVnZXgsIHdoaWNoIGNvbWJpbmVzIFJGQyA1NjQ2IGFuZCBSRkMgNDY0Ny5cbiAgICAvLyByZXR1cm4gdGhpcy5pc0RlZmluZWQodGFyZ2V0KSAmJiB0aGlzLmlzU3RyaW5nKHRhcmdldCkgJiYgeGFwaVZhbGlkYXRpb25SZWdleC5CQ1BfNDcudGVzdCh0YXJnZXQpO1xuICAgIHJldHVybiB0aGlzLmlzRGVmaW5lZCh0YXJnZXQpICYmIHRoaXMuaXNTdHJpbmcodGFyZ2V0KSAmJiB2YWxpZExhbmd1YWdlUmVnZXgudGVzdCh0YXJnZXQpO1xuICB9LFxuXG4gIGFkZFByb3BUb1RyYWNlKHRyYWNlLCBhZGRlbmR1bSkge1xuICAgIHJldHVybiB0aGlzLmlzRGVmaW5lZChhZGRlbmR1bSkgPyBgJHt0cmFjZX0uJHthZGRlbmR1bX1gIDogdHJhY2U7XG4gIH0sXG5cbiAgYWRkTG9va3VwVG9UcmFjZSh0cmFjZSwga2V5KSB7XG4gICAgcmV0dXJuICghdGhpcy5pc0RlZmluZWQoa2V5KSkgPyB0cmFjZSA6ICh0aGlzLmlzTnVtYmVyKGtleSkgPyBgJHt0cmFjZX1bJHtrZXl9XWAgOiBgJHt0cmFjZX1bXCIke2tleX1cIl1gKTtcbiAgfSxcblxuICBsb2NhbFRyYWNlVG9TdHJpbmcodHJhY2UsIGFkZGVuZHVtKSB7XG4gICAgcmV0dXJuIHRoaXMuYWRkUHJvcFRvVHJhY2UodHJhY2UsIGFkZGVuZHVtKTtcbiAgfSxcblxuICBpc0dyb3VwKGFjdG9yT3JHcm91cCwgZ3JvdXBUeXBlKSB7XG4gICAgLy8gcmV0dXJuIChhY3Rvck9yR3JvdXAubWVtYmVyICE9PSBudWxsICYmIGFjdG9yT3JHcm91cC5tZW1iZXIgIT09IHVuZGVmaW5lZCkgfHwgYWN0b3JPckdyb3VwLm9iamVjdFR5cGUgPT09IG9iamVjdFR5cGVzLkdST1VQO1xuICAgIHJldHVybiAoYWN0b3JPckdyb3VwLm1lbWJlciAhPT0gbnVsbCAmJiBhY3Rvck9yR3JvdXAubWVtYmVyICE9PSB1bmRlZmluZWQpIHx8IGFjdG9yT3JHcm91cC5vYmplY3RUeXBlID09PSBncm91cFR5cGU7XG4gIH1cbn07XG5cbmV4cG9ydCB7eGFwaVZhbGlkYXRpb25VdGlsc307XG4iLCIndXNlIHN0cmljdCc7XG5cbmltcG9ydCB7cHJvcGVydGllcywgb2JqZWN0VHlwZXMsIHhhcGlWYWxpZGF0aW9uSWZpUHJvcGVydHlOYW1lcywgeEFwaVZhbGlkT2JqZWN0VHlwZXMsIHhhcGlXaGl0ZUxpc3RQcm9wZXJ0aWVzfSBmcm9tICcuL2NvbnN0YW50cy9wcm9wZXJ0aWVzJztcbmltcG9ydCB7eGFwaUVycm9yTGV2ZWxzLCB4YXBpVmFsaWRhdGlvbkVycm9yc30gZnJvbSAnLi9jb25zdGFudHMvZXJyb3JzJztcbmltcG9ydCB7eGFwaVZhbGlkYXRpb25JbnRlcmFjdGlvblR5cGVzfSBmcm9tICcuL2NvbnN0YW50cy9pbnRlcmFjdGlvbi10eXBlcyc7XG5pbXBvcnQge3hhcGlWYWxpZGF0aW9uUmVnZXgsIGRhdGVGb3JtYXRSZWdleFBvc2l0aW9uc30gZnJvbSAnLi9jb25zdGFudHMvcmVnZXgnO1xuaW1wb3J0IHt4YXBpR2VuZXJhbH0gZnJvbSAnLi9jb25zdGFudHMvZ2VuZXJhbCc7XG5pbXBvcnQge3hhcGlWYWxpZGF0aW9uVXRpbHN9IGZyb20gJy4vdXRpbHMvdXRpbHMnO1xuXG52YXIgeGFwaVZhbGlkYXRpb247XG5cbmZ1bmN0aW9uIG1ha2VWMVJlcG9ydChpbnN0YW5jZSwgZXJyb3JzKSB7XG4gIHZhciB2ZXJzaW9uO1xuXG4gIGluc3RhbmNlID0gaW5zdGFuY2UgfHwgbnVsbDtcbiAgZXJyb3JzICAgPSBlcnJvcnMgICB8fCBudWxsO1xuICB2ZXJzaW9uICA9IHhhcGlHZW5lcmFsLkZJUlNUX1JFUE9SVF9WRVJTVElPTjtcbiAgcmV0dXJuIHtpbnN0YW5jZSwgZXJyb3JzLCB2ZXJzaW9ufTtcbn1cblxuZnVuY3Rpb24gbWFrZVYxU2luZ2xlRXJyb3JSZXBvcnQoaW5zdGFuY2UsIGVycm9yKSB7XG4gIHJldHVybiBtYWtlVjFSZXBvcnQoaW5zdGFuY2UsIGVycm9yID09PSBudWxsIHx8IGVycm9yID09PSB1bmRlZmluZWQgPyBbXSA6IFtlcnJvcl0pO1xufVxuXG5mdW5jdGlvbiB2YWxpZGF0ZUFic2VuY2VPZk5vbldoaXRlbGlzdGVkUHJvcGVydGllcyh0YXJnZXQsIGFsbG93ZWRQcm9wZXJ0aWVzLCB0cmFjZSwgZXJyb3JzKSB7XG4gIHZhciBsb2NhbEVycm9ycywgbG9jYWxUcmFjZSwgcHJvcGVydHlOYW1lO1xuXG4gIGxvY2FsRXJyb3JzID0gZXJyb3JzIHx8IFtdO1xuICBsb2NhbFRyYWNlICA9IHRyYWNlICB8fCAnJztcblxuICBmb3IgKHByb3BlcnR5TmFtZSBpbiB0YXJnZXQpIHtcbiAgICBpZiAodGFyZ2V0Lmhhc093blByb3BlcnR5KHByb3BlcnR5TmFtZSkgJiYgYWxsb3dlZFByb3BlcnRpZXMuaW5kZXhPZihwcm9wZXJ0eU5hbWUpID09PSB4YXBpR2VuZXJhbC5OT19JTkRFWF9GT1VORCkge1xuICAgICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSwgcHJvcGVydHlOYW1lKSxcbiAgICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuVU5FWFBFQ1RFRCxcbiAgICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gbG9jYWxFcnJvcnM7XG59XG5cbmZ1bmN0aW9uIHZhbGlkYXRlUHJvcGVydHlJc1N0cmluZyhwYXJlbnQsIHByb3BlcnR5TmFtZSwgdHJhY2UsIGVycm9ycywgaXNSZXF1aXJlZCwgdmlvbGF0aW9uVHlwZSkge1xuICB2YXIgbG9jYWxFcnJvcnMsIGxvY2FsVHJhY2UsIHByb3BWYWx1ZSwgbG9jYWxWaW9sYXRpb25UeXBlO1xuXG4gIGxvY2FsRXJyb3JzICAgICAgICA9IGVycm9ycyB8fCBbXTtcbiAgbG9jYWxUcmFjZSAgICAgICAgID0gdHJhY2UgIHx8ICcnO1xuICBwcm9wVmFsdWUgICAgICAgICAgPSBwYXJlbnRbcHJvcGVydHlOYW1lXSxcbiAgbG9jYWxWaW9sYXRpb25UeXBlID0gdmlvbGF0aW9uVHlwZSB8fCB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT047XG5cbiAgaWYgKHByb3BWYWx1ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgaWYgKHByb3BWYWx1ZSA9PT0gbnVsbCB8fCAheGFwaVZhbGlkYXRpb25VdGlscy5pc1N0cmluZyhwcm9wVmFsdWUpKSB7XG4gICAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSwgcHJvcGVydHlOYW1lKSxcbiAgICAgICAgbWVzc2FnZTogYCR7cHJvcGVydHlOYW1lfSAke3hhcGlWYWxpZGF0aW9uRXJyb3JzLk1VU1RfQkVfU1RSSU5HfWAsXG4gICAgICAgIGxldmVsOiAgIGxvY2FsVmlvbGF0aW9uVHlwZVxuICAgICAgfSk7XG4gICAgfVxuICB9IGVsc2UgaWYgKGlzUmVxdWlyZWQpIHtcbiAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMubG9jYWxUcmFjZVRvU3RyaW5nKGxvY2FsVHJhY2UsIHByb3BlcnR5TmFtZSksXG4gICAgICBtZXNzYWdlOiBgJHtwcm9wZXJ0eU5hbWV9ICR7eGFwaVZhbGlkYXRpb25FcnJvcnMuTVVTVF9CRV9QUkVTRU5UfWAsXG4gICAgICBsZXZlbDogICBsb2NhbFZpb2xhdGlvblR5cGVcbiAgICB9KTtcbiAgfVxuXG4gIHJldHVybiBsb2NhbEVycm9ycztcbn1cblxuZnVuY3Rpb24gdmFsaWRhdGVQcm9wZXJ0eUlzVXJpKHRhcmdldCwgcHJvcGVydHlOYW1lLCB0cmFjZSwgZXJyb3JzLCBpc1JlcXVpcmVkKSB7XG4gIHZhciBsb2NhbEVycm9ycywgbG9jYWxUcmFjZSwgcHJvcFZhbHVlO1xuXG4gIGxvY2FsRXJyb3JzID0gZXJyb3JzIHx8IFtdO1xuICBsb2NhbFRyYWNlICA9IHRyYWNlICB8fCAnJztcbiAgcHJvcFZhbHVlICAgPSB0YXJnZXRbcHJvcGVydHlOYW1lXTtcblxuICBpZiAocHJvcFZhbHVlICE9PSB1bmRlZmluZWQpIHtcbiAgICBpZiAocHJvcFZhbHVlID09PSBudWxsIHx8ICF4YXBpVmFsaWRhdGlvblV0aWxzLmlzU3RyaW5nKHByb3BWYWx1ZSkpIHtcbiAgICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlLCBwcm9wZXJ0eU5hbWUpLFxuICAgICAgICBtZXNzYWdlOiBgJHtwcm9wZXJ0eU5hbWV9ICR7eGFwaVZhbGlkYXRpb25FcnJvcnMuTVVTVF9CRV9VUklfU1RSSU5HfWAsXG4gICAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgICAgfSk7XG4gICAgfSBlbHNlIGlmICgheGFwaVZhbGlkYXRpb25SZWdleC5JUkkudGVzdChwcm9wVmFsdWUpKSB7XG4gICAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgICAgdHJhY2U6ICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlLCBwcm9wZXJ0eU5hbWUpLFxuICAgICAgICBtZXNzYWdlOiBgJHtwcm9wZXJ0eU5hbWV9ICR7eGFwaVZhbGlkYXRpb25FcnJvcnMuTVVTVF9CRV9JUklfU1RSSU5HfWAsXG4gICAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5TSE9VTERfVklPTEFUSU9OXG4gICAgICB9KTtcbiAgICB9XG4gIH0gZWxzZSBpZiAoaXNSZXF1aXJlZCkge1xuICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSwgcHJvcGVydHlOYW1lKSxcbiAgICAgIG1lc3NhZ2U6IGAke3Byb3BlcnR5TmFtZX0gJHt4YXBpVmFsaWRhdGlvbkVycm9ycy5NVVNUX0JFX1VSSV9QUkVTRU5UfWAsXG4gICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICB9KTtcbiAgfVxuICByZXR1cm4gbG9jYWxFcnJvcnM7XG59XG5cbmZ1bmN0aW9uIHZhbGlkYXRlUHJvcGVydHlJc1VybCh0YXJnZXQsIHByb3BlcnR5TmFtZSwgdHJhY2UsIGVycm9ycywgaXNSZXF1aXJlZCkge1xuICAvLyBUT0RPIC0gY2hlY2sgd2hldGhlciBhIGZvcm1hbCBVUkwgZm9ybWF0IGRlZmluaXRpb24gaXMgcmVjb21tZW5kZWQvZW5mb3JjZWQgZm9yIHhBUElcbiAgcmV0dXJuIHZhbGlkYXRlUHJvcGVydHlJc1N0cmluZyh0YXJnZXQsIHByb3BlcnR5TmFtZSwgdHJhY2UsIGVycm9ycywgaXNSZXF1aXJlZCk7XG59XG5cbmZ1bmN0aW9uIHZhbGlkYXRlUHJvcGVydHlJc0Jvb2xlYW4ocGFyZW50LCBwcm9wZXJ0eU5hbWUsIHRyYWNlLCBlcnJvcnMsIGlzUmVxdWlyZWQpIHtcbiAgdmFyIGxvY2FsRXJyb3JzLCBsb2NhbFRyYWNlLCBwcm9wVmFsdWU7XG5cbiAgbG9jYWxFcnJvcnMgPSBlcnJvcnMgfHwgW107XG4gIGxvY2FsVHJhY2UgID0gdHJhY2UgIHx8ICcnO1xuICBwcm9wVmFsdWUgICA9IHBhcmVudFtwcm9wZXJ0eU5hbWVdO1xuXG4gIGlmIChwcm9wVmFsdWUgIT09IHVuZGVmaW5lZCkge1xuICAgIGlmIChwcm9wVmFsdWUgPT09IG51bGwgfHwgIXhhcGlWYWxpZGF0aW9uVXRpbHMuaXNCb29sZWFuKHByb3BWYWx1ZSkpIHtcbiAgICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlLCBwcm9wZXJ0eU5hbWUpLFxuICAgICAgICBtZXNzYWdlOiBgJHtwcm9wZXJ0eU5hbWV9ICR7eGFwaVZhbGlkYXRpb25FcnJvcnMuTVVTVF9CRV9CT09MRUFOfWAsXG4gICAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgICAgfSk7XG4gICAgfVxuICB9IGVsc2UgaWYgKGlzUmVxdWlyZWQpIHtcbiAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMubG9jYWxUcmFjZVRvU3RyaW5nKGxvY2FsVHJhY2UsIHByb3BlcnR5TmFtZSksXG4gICAgICBtZXNzYWdlOiBgJHtwcm9wZXJ0eU5hbWV9ICR7eGFwaVZhbGlkYXRpb25FcnJvcnMuTVVTVF9CRV9CT09MRUFOX1BSRVNFTlR9YCxcbiAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgIH0pO1xuICB9XG4gIHJldHVybiBsb2NhbEVycm9ycztcbn1cblxuZnVuY3Rpb24gdmFsaWRhdGVQcm9wZXJ0eUlzTnVtYmVyKHBhcmVudCwgcHJvcGVydHlOYW1lLCB0cmFjZSwgZXJyb3JzLCBpc1JlcXVpcmVkKSB7XG4gIHZhciBsb2NhbEVycm9ycywgbG9jYWxUcmFjZSwgcHJvcFZhbHVlO1xuXG4gIGxvY2FsRXJyb3JzID0gZXJyb3JzIHx8IFtdO1xuICBsb2NhbFRyYWNlICA9IHRyYWNlICB8fCAnJztcbiAgcHJvcFZhbHVlICAgPSBwYXJlbnRbcHJvcGVydHlOYW1lXTtcblxuICAgIGlmIChwcm9wVmFsdWUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgaWYgKHByb3BWYWx1ZSA9PT0gbnVsbCB8fCAheGFwaVZhbGlkYXRpb25VdGlscy5pc051bWJlcihwcm9wVmFsdWUpKSB7XG4gICAgICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMubG9jYWxUcmFjZVRvU3RyaW5nKGxvY2FsVHJhY2UsIHByb3BlcnR5TmFtZSksXG4gICAgICAgICAgbWVzc2FnZTogYCR7cHJvcGVydHlOYW1lfSAke3hhcGlWYWxpZGF0aW9uRXJyb3JzLk1VU1RfQkVfTlVNQkVSfWAsXG4gICAgICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoaXNSZXF1aXJlZCkge1xuICAgICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMubG9jYWxUcmFjZVRvU3RyaW5nKGxvY2FsVHJhY2UsIHByb3BlcnR5TmFtZSksXG4gICAgICAgIG1lc3NhZ2U6IGAke3Byb3BlcnR5TmFtZX0gJHt4YXBpVmFsaWRhdGlvbkVycm9ycy5NVVNUX0JFX05VTUJFUl9QUkVTRU5UfWAsXG4gICAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgICAgfSk7XG4gICAgfVxuICAgIHJldHVybiBsb2NhbEVycm9ycztcbn1cblxuZnVuY3Rpb24gdmFsaWRhdGVJRklQcm9wZXJ0aWVzKHRhcmdldCwgdHJhY2UsIGVycm9ycykge1xuICB2YXIgbG9jYWxFcnJvcnMsIGxvY2FsVHJhY2UsIGFjY291bnRUcmFjZTtcblxuICBsb2NhbEVycm9ycyA9IGVycm9ycyB8fCBbXTtcbiAgbG9jYWxUcmFjZSAgPSB0cmFjZSAgfHwgJyc7XG5cbiAgaWYgKHRhcmdldC5tYm94ICE9PSB1bmRlZmluZWQgJiYgdGFyZ2V0Lm1ib3ggIT09IG51bGwpIHtcbiAgICBpZiAoIXhhcGlWYWxpZGF0aW9uVXRpbHMuaXNTdHJpbmcodGFyZ2V0Lm1ib3gpKSB7XG4gICAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgICAgdHJhY2U6IHhhcGlWYWxpZGF0aW9uVXRpbHMubG9jYWxUcmFjZVRvU3RyaW5nKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuTUJPWCksXG4gICAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLklGSV9NVVNUX0JFX01CT1hfVVJJLFxuICAgICAgICBsZXZlbDogeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgICB9KTtcbiAgICB9IGVsc2UgaWYgKCF4YXBpVmFsaWRhdGlvblJlZ2V4Lk1BSUxUT19VUkkudGVzdCh0YXJnZXQubWJveCkpIHtcbiAgICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLk1CT1gpLFxuICAgICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5JRklfTVVTVF9CRV9WQUxJRF9NQk9YX0ZPUk1BVCxcbiAgICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICB2YWxpZGF0ZVByb3BlcnR5SXNTdHJpbmcodGFyZ2V0LCBwcm9wZXJ0aWVzLk1CT1hfU0hBXzFfU1VNLCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycywgIC8qaXNSZXF1aXJlZCovZmFsc2UpO1xuICB2YWxpZGF0ZVByb3BlcnR5SXNVcmkodGFyZ2V0LCBwcm9wZXJ0aWVzLk9QRU5fSUQsIGxvY2FsVHJhY2UsIGxvY2FsRXJyb3JzLCAvKmlzUmVxdWlyZWQqL2ZhbHNlKTtcblxuICBpZiAodGFyZ2V0LmFjY291bnQgIT09IHVuZGVmaW5lZCAmJiB0YXJnZXQuYWNjb3VudCAhPT0gbnVsbCkge1xuICAgIGFjY291bnRUcmFjZSA9IHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSwgcHJvcGVydGllcy5BQ0NPVU5UKTtcbiAgICB2YWxpZGF0ZVByb3BlcnR5SXNVcmkodGFyZ2V0LmFjY291bnQsIHByb3BlcnRpZXMuSE9NRV9QQUdFLGFjY291bnRUcmFjZSwgbG9jYWxFcnJvcnMsIC8qaXNSZXF1aXJlZCovdHJ1ZSk7XG4gICAgdmFsaWRhdGVQcm9wZXJ0eUlzU3RyaW5nKHRhcmdldC5hY2NvdW50LCBwcm9wZXJ0aWVzLk5BTUUsIGFjY291bnRUcmFjZSwgbG9jYWxFcnJvcnMsIC8qaXNSZXF1aXJlZCovdHJ1ZSk7XG4gICAgdmFsaWRhdGVBYnNlbmNlT2ZOb25XaGl0ZWxpc3RlZFByb3BlcnRpZXModGFyZ2V0LmFjY291bnQsIHhhcGlXaGl0ZUxpc3RQcm9wZXJ0aWVzLklGSSwgYWNjb3VudFRyYWNlLCBsb2NhbEVycm9ycyk7XG4gIH1cblxuICByZXR1cm4gbG9jYWxFcnJvcnM7XG59XG5cbmZ1bmN0aW9uIGdldElGSXModGFyZ2V0KSB7XG4gIHZhciBpZmlzO1xuXG4gIGlmICh0YXJnZXQgPT09IG51bGwgfHwgdGFyZ2V0ID09PSB1bmRlZmluZWQpIHtyZXR1cm4gW107fVxuXG4gIGlmaXMgPSB4YXBpVmFsaWRhdGlvbklmaVByb3BlcnR5TmFtZXMuZmlsdGVyKChuYW1lKSA9PiB7XG4gICAgaWYgKHRhcmdldFtuYW1lXSAhPT0gdW5kZWZpbmVkICYmIHRhcmdldFtuYW1lXSAhPT0gbnVsbCkge1xuICAgICAgcmV0dXJuIHtrZXk6IG5hbWUsIHZhbHVlOiB0YXJnZXRbbmFtZV19O1xuICAgIH1cbiAgfSk7XG5cbiAgcmV0dXJuIGlmaXM7XG59XG5cbmZ1bmN0aW9uIGdldElGSUNvdW50KHRhcmdldCkge1xuICByZXR1cm4gZ2V0SUZJcyh0YXJnZXQpLmxlbmd0aDtcbn1cblxuZnVuY3Rpb24gdmFsaWRhdGVFeHRlbnNpb25zKGV4dGVuc2lvbnMsIHRyYWNlLCBlcnJvcnMpIHtcbiAgdmFyIGxvY2FsRXJyb3JzLCBsb2NhbFRyYWNlO1xuXG4gIGxvY2FsRXJyb3JzID0gZXJyb3JzIHx8IFtdLFxuICBsb2NhbFRyYWNlICA9IHRyYWNlICB8fCBwcm9wZXJ0aWVzLkVYVEVOU0lPTlM7XG5cbiAgaWYgKGV4dGVuc2lvbnMgPT09IHVuZGVmaW5lZCkge3JldHVybiBsb2NhbEVycm9yczt9XG5cbiAgaWYgKCF4YXBpVmFsaWRhdGlvblV0aWxzLmlzTm9uTnVsbE1hcE9iamVjdChleHRlbnNpb25zKSkge1xuICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgdHJhY2U6ICAgbG9jYWxUcmFjZSxcbiAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLkVYVEVOU0lPTlNfTVVTVF9OT1RfQkVfTlVMTCxcbiAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgIH0pO1xuICB9XG4gIC8vIFRPRE8gLSBkb3VibGUtY2hlY2sgd2hhdCBmdXJ0aGVyIGVuZm9yY2VhYmxlIGNvbnN0cmFpbnRzIGV4aXN0IG9uIGV4dGVuc2lvbiBvYmplY3QgcHJvcGVydGllc1xuICByZXR1cm4gbG9jYWxFcnJvcnM7XG59XG5cbmZ1bmN0aW9uIHZhbGlkYXRlTGFuZ3VhZ2VNYXAobGFuZ3VhZ2VNYXAsIHRyYWNlLCBlcnJvcnMpIHtcbiAgdmFyIGxvY2FsRXJyb3JzLCBsb2NhbFRyYWNlLCBwcm9wTmFtZSwgbWFwcGVkVmFsdWU7XG5cbiAgbG9jYWxFcnJvcnMgPSBlcnJvcnMgfHwgW107XG4gIGxvY2FsVHJhY2UgID0gdHJhY2UgIHx8IHByb3BlcnRpZXMuTEFOR1VBR0VfTUFQO1xuXG4gIGlmIChsYW5ndWFnZU1hcCA9PT0gdW5kZWZpbmVkKSB7cmV0dXJuIGxvY2FsRXJyb3JzO31cblxuICBpZiAoIXhhcGlWYWxpZGF0aW9uVXRpbHMuaXNOb25OdWxsTWFwT2JqZWN0KGxhbmd1YWdlTWFwKSkge1xuICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRQcm9wVG9UcmFjZShsb2NhbFRyYWNlKSxcbiAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLkxBTkdVQUdFX01BUFNfTVVTVF9OT1RfQkVfTlVMTCxcbiAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgIH0pO1xuXG4gICAgcmV0dXJuIGxvY2FsRXJyb3JzO1xuICB9XG5cbiAgZm9yIChwcm9wTmFtZSBpbiBsYW5ndWFnZU1hcCkge1xuXG4gICAgaWYgKGxhbmd1YWdlTWFwLmhhc093blByb3BlcnR5KHByb3BOYW1lKSkge1xuICAgICAgaWYgKCF4YXBpVmFsaWRhdGlvblV0aWxzLmlzVmFsaWRMYW5ndWFnZVRhZyhwcm9wTmFtZSwgeGFwaVZhbGlkYXRpb25SZWdleC5CQ1BfNDcpKSB7XG4gICAgICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSwgcHJvcE5hbWUpLFxuICAgICAgICAgIG1lc3NhZ2U6IGAke3Byb3BOYW1lfSAke3hhcGlWYWxpZGF0aW9uRXJyb3JzLkxBTkdVQUdFX01BUF9LRVlfSU5WQUxJRH1gLFxuICAgICAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgbWFwcGVkVmFsdWUgPSBsYW5ndWFnZU1hcFtwcm9wTmFtZV07XG5cbiAgICAgIGlmIChtYXBwZWRWYWx1ZSA9PT0gbnVsbCB8fCBtYXBwZWRWYWx1ZSA9PT0gdW5kZWZpbmVkIHx8ICF4YXBpVmFsaWRhdGlvblV0aWxzLmlzU3RyaW5nKG1hcHBlZFZhbHVlKSkge1xuICAgICAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZExvb2t1cFRvVHJhY2UobG9jYWxUcmFjZSwgcHJvcE5hbWUpLFxuICAgICAgICAgIG1lc3NhZ2U6IGAke3Byb3BOYW1lfSAke3hhcGlWYWxpZGF0aW9uRXJyb3JzLkxBTkdVQUdFX01BUF9LRVlfTVVTVF9CRV9TVFJJTkd9YCxcbiAgICAgICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIGxvY2FsRXJyb3JzO1xufVxuXG5mdW5jdGlvbiB2YWxpZGF0ZVZlcmIodmVyYiwgdHJhY2UsIGVycm9ycykge1xuICB2YXIgbG9jYWxFcnJvcnMsIGxvY2FsVHJhY2U7XG5cbiAgbG9jYWxFcnJvcnMgPSBlcnJvcnMgfHwgW107XG4gIGxvY2FsVHJhY2UgID0gdHJhY2UgIHx8IHByb3BlcnRpZXMuVkVSQjtcblxuICBpZiAodmVyYiA9PT0gdW5kZWZpbmVkKSB7XG4gICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlKSxcbiAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLlZFUkJfTVVTVF9CRV9QUk9WSURFRCxcbiAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgIH0pO1xuXG4gICAgcmV0dXJuIGxvY2FsRXJyb3JzO1xuICB9XG5cbiAgaWYgKCF4YXBpVmFsaWRhdGlvblV0aWxzLmlzTm9uTnVsbE1hcE9iamVjdCh2ZXJiKSkge1xuICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSksXG4gICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5WRVJCX01VU1RfTk9UX0JFX05VTEwsXG4gICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICB9KTtcblxuICAgIHJldHVybiBsb2NhbEVycm9ycztcbiAgfVxuXG4gIHZhbGlkYXRlUHJvcGVydHlJc1VyaSh2ZXJiLCBwcm9wZXJ0aWVzLklELCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycywgIC8qaXNSZXF1aXJlZCovdHJ1ZSk7XG5cbiAgaWYgKHZlcmIuZGlzcGxheSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuRElTUExBWSksXG4gICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5ESVNQTEFZX1NIT1VMRF9CRV9QUk9WSURFRCxcbiAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5TSE9VTERfVklPTEFUSU9OXG4gICAgfSk7XG4gIH0gZWxzZSB7XG4gICAgdmFsaWRhdGVMYW5ndWFnZU1hcCh2ZXJiLmRpc3BsYXksIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSwgcHJvcGVydGllcy5ESVNQTEFZKSwgbG9jYWxFcnJvcnMpO1xuICB9XG5cbiAgdmFsaWRhdGVBYnNlbmNlT2ZOb25XaGl0ZWxpc3RlZFByb3BlcnRpZXModmVyYiwgeGFwaVdoaXRlTGlzdFByb3BlcnRpZXMuVVJJLCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycyk7XG5cbiAgcmV0dXJuIGxvY2FsRXJyb3JzO1xufVxuXG5mdW5jdGlvbiB2YWxpZGF0ZUludGVyYWN0aW9uQ29tcG9uZW50QXJyYXkoY29tcG9uZW50cywgaW50ZXJhY3Rpb25UeXBlLCBhbGxvd2VkSW50ZXJhY3Rpb25UeXBlcywgdHJhY2UsIGVycm9ycykge1xuICB2YXIgbG9jYWxFcnJvcnMsIGxvY2FsVHJhY2UsIGlzQWxsb3dlZENvbXBvbmVudFR5cGUsIGlkcywgcGVyQ29tcG9uZW50VHJhY2U7XG5cbiAgbG9jYWxFcnJvcnMgICAgICAgICAgICA9IGVycm9ycyB8fCBbXTtcbiAgbG9jYWxUcmFjZSAgICAgICAgICAgICA9IHRyYWNlICB8fCBwcm9wZXJ0aWVzLklOVEVSQUNUSU9OX0NPTVBPTkVOVFM7XG4gIGlzQWxsb3dlZENvbXBvbmVudFR5cGUgPSBhbGxvd2VkSW50ZXJhY3Rpb25UeXBlcy5pbmRleE9mKGludGVyYWN0aW9uVHlwZSkgIT09IHhhcGlHZW5lcmFsLk5PX0lOREVYX0ZPVU5EO1xuICBpZHMgICAgICAgICAgICAgICAgICAgID0gW107XG5cbiAgaWYgKGlzQWxsb3dlZENvbXBvbmVudFR5cGUgJiYgY29tcG9uZW50cyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgaWYgKGNvbXBvbmVudHMgPT09IG51bGwgfHwgIXhhcGlWYWxpZGF0aW9uVXRpbHMuaXNBcnJheShjb21wb25lbnRzKSkge1xuICAgICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICAgIHRyYWNlOiAgIGxvY2FsVHJhY2UsXG4gICAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLklOVEVSQUNUSU9OX0NPTVBPTkVOVF9TSE9VTERfQkVfQVJSQVksXG4gICAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5TSE9VTERfVklPTEFUSU9OXG4gICAgICB9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29tcG9uZW50cy5mb3JFYWNoKChpbnRlcmFjdGlvbkNvbXBvbmVudCwgaSkgPT4ge1xuICAgICAgICBwZXJDb21wb25lbnRUcmFjZSA9IHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkTG9va3VwVG9UcmFjZShsb2NhbFRyYWNlLCBpKTtcblxuICAgICAgICBpZiAoIXhhcGlWYWxpZGF0aW9uVXRpbHMuaXNOb25OdWxsTWFwT2JqZWN0KGludGVyYWN0aW9uQ29tcG9uZW50KSkge1xuICAgICAgICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgICAgICAgdHJhY2U6ICAgcGVyQ29tcG9uZW50VHJhY2UsXG4gICAgICAgICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5JTlRFUkFDVElPTl9DT01QT05FTlRfTVVTVF9OT1RfQkVfTlVMTCxcbiAgICAgICAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHZhbGlkYXRlUHJvcGVydHlJc1N0cmluZyhpbnRlcmFjdGlvbkNvbXBvbmVudCwgcHJvcGVydGllcy5JRCwgcGVyQ29tcG9uZW50VHJhY2UsIGxvY2FsRXJyb3JzLCAvKmlzUmVxdWlyZWQqL3RydWUsIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTik7XG4gICAgICAgICAgaWYgKGlkcy5pbmRleE9mKGludGVyYWN0aW9uQ29tcG9uZW50LmlkKSAhPT0geGFwaUdlbmVyYWwuTk9fSU5ERVhfRk9VTkQpIHtcbiAgICAgICAgICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgICAgICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKHBlckNvbXBvbmVudFRyYWNlLCBwcm9wZXJ0aWVzLklEKSxcbiAgICAgICAgICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuSURfTVVTVF9CRV9VTklRVUUsXG4gICAgICAgICAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGlkcy5wdXNoKGludGVyYWN0aW9uQ29tcG9uZW50LmlkKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAoaW50ZXJhY3Rpb25Db21wb25lbnQuaWQgJiYgeGFwaVZhbGlkYXRpb25SZWdleC5DT05UQUlOU19XSElURVNQQUNFLnRlc3QoaW50ZXJhY3Rpb25Db21wb25lbnQuaWQpKSB7XG4gICAgICAgICAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgICAgICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRQcm9wVG9UcmFjZShwZXJDb21wb25lbnRUcmFjZSwgcHJvcGVydGllcy5JRCksXG4gICAgICAgICAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLklEX1NIT1VMRF9OT1RfQ09OVEFJTl9XSElURVNQQUNFUyxcbiAgICAgICAgICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLlNIT1VMRF9WSU9MQVRJT05cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHZhbGlkYXRlTGFuZ3VhZ2VNYXAoaW50ZXJhY3Rpb25Db21wb25lbnQuZGVzY3JpcHRpb24sIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UocGVyQ29tcG9uZW50VHJhY2UsIHByb3BlcnRpZXMuREVTQ1JJUFRJT04pLCBsb2NhbEVycm9ycyk7XG4gICAgICAgICAgdmFsaWRhdGVBYnNlbmNlT2ZOb25XaGl0ZWxpc3RlZFByb3BlcnRpZXMoaW50ZXJhY3Rpb25Db21wb25lbnQsIHhhcGlXaGl0ZUxpc3RQcm9wZXJ0aWVzLkNPTVBPTkVOVF9BUlJBWSwgcGVyQ29tcG9uZW50VHJhY2UsIGxvY2FsRXJyb3JzKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG5cbiAgICB9XG4gIH0gZWxzZSBpZiAoaW50ZXJhY3Rpb25UeXBlICYmIGNvbXBvbmVudHMpIHtcbiAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgIHRyYWNlOiAgIGxvY2FsVHJhY2UsXG4gICAgICBtZXNzYWdlOiBgJHt4YXBpVmFsaWRhdGlvbkVycm9ycy5JTlRFUkFDVElPTl9UWVBFX01VU1RfQkVfVkFMSUR9ICR7aW50ZXJhY3Rpb25UeXBlfWAsXG4gICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuU0hPVUxEX1ZJT0xBVElPTlxuICAgIH0pO1xuICB9XG5cbiAgcmV0dXJuIGxvY2FsRXJyb3JzO1xufVxuXG5mdW5jdGlvbiB2YWxpZGF0ZUFjdGl2aXR5RGVmaW50aW9uKGRlZmluaXRpb24sIHRyYWNlLCBlcnJvcnMpIHtcbiAgdmFyIGxvY2FsRXJyb3JzLCBsb2NhbFRyYWNlLCBjb3JyZWN0UmVzcG9uc2VzUGF0dGVyblRyYWNlO1xuXG4gIGxvY2FsRXJyb3JzICAgICAgICAgICAgICAgICAgPSBlcnJvcnMgfHwgW107XG4gIGxvY2FsVHJhY2UgICAgICAgICAgICAgICAgICAgPSB0cmFjZSAgfHwgcHJvcGVydGllcy5ERUZJTklUSU9OO1xuICBjb3JyZWN0UmVzcG9uc2VzUGF0dGVyblRyYWNlID0geGFwaVZhbGlkYXRpb25VdGlscy5hZGRQcm9wVG9UcmFjZShsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLkNPUlJFQ1RfUkVTUE9OU0VTX1BBVFRFUk4pO1xuXG4gIGlmICgheGFwaVZhbGlkYXRpb25VdGlscy5pc05vbk51bGxNYXBPYmplY3QoZGVmaW5pdGlvbikpIHtcbiAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSksXG4gICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5ERUZJTklUSU9OU19NVVNUX0JFX09CSkVDVFMsXG4gICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICB9KTtcblxuICAgIHJldHVybiBsb2NhbEVycm9ycztcbiAgfVxuXG4gIHZhbGlkYXRlTGFuZ3VhZ2VNYXAoZGVmaW5pdGlvbi5uYW1lLCB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuTkFNRSksIGxvY2FsRXJyb3JzKTtcbiAgdmFsaWRhdGVMYW5ndWFnZU1hcChkZWZpbml0aW9uLmRlc2NyaXB0aW9uLCB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuREVTQ1JJUFRJT04pLCBsb2NhbEVycm9ycyk7XG5cbiAgdmFsaWRhdGVQcm9wZXJ0eUlzVXJpKGRlZmluaXRpb24sIHByb3BlcnRpZXMuVFlQRSwgbG9jYWxUcmFjZSwgbG9jYWxFcnJvcnMsICAvKmlzUmVxdWlyZWQqL2ZhbHNlKTtcbiAgdmFsaWRhdGVQcm9wZXJ0eUlzVXJsKGRlZmluaXRpb24sIHByb3BlcnRpZXMuTU9SRV9JTkZPLCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycywgIC8qaXNSZXF1aXJlZCovZmFsc2UpO1xuICB2YWxpZGF0ZUV4dGVuc2lvbnMoZGVmaW5pdGlvbi5leHRlbnNpb25zLCB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuRVhURU5TSU9OUyksIGxvY2FsRXJyb3JzKTtcblxuICBpZiAoZGVmaW5pdGlvbi5pbnRlcmFjdGlvblR5cGUgIT09IHVuZGVmaW5lZCkge1xuICAgIGlmIChkZWZpbml0aW9uLnR5cGUgIT09IHhhcGlHZW5lcmFsLklOVEVSQUNUSU9OX0RFRklOSVRJT05fVFlQRSkge1xuICAgICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMubG9jYWxUcmFjZVRvU3RyaW5nKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuVFlQRSksXG4gICAgICAgIG1lc3NhZ2U6IGAke3hhcGlWYWxpZGF0aW9uRXJyb3JzLklOVEVSQUNUSU9OX0FDVElWSVRZX1NIT1VMRF9IQVZFfSBcIiR7eGFwaUdlbmVyYWwuSU5URVJBQ1RJT05fREVGSU5JVElPTl9UWVBFfVwiYCxcbiAgICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLlNIT1VMRF9WSU9MQVRJT05cbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmICh4YXBpVmFsaWRhdGlvbkludGVyYWN0aW9uVHlwZXMuaW5kZXhPZihkZWZpbml0aW9uLmludGVyYWN0aW9uVHlwZSkgPT09IHhhcGlHZW5lcmFsLk5PX0lOREVYX0ZPVU5EKSB7XG4gICAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSwgcHJvcGVydGllcy5JTlRFUkFDVElPTl9UWVBFKSxcbiAgICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuSU5URVJBQ1RJT05fVFlQRV9NVVNUX0JFX0NNSSxcbiAgICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBpZiAoZGVmaW5pdGlvbi5jb3JyZWN0UmVzcG9uc2VzUGF0dGVybiAhPT0gdW5kZWZpbmVkKSB7XG4gICAgaWYgKCF4YXBpVmFsaWRhdGlvblV0aWxzLmlzQXJyYXkoZGVmaW5pdGlvbi5jb3JyZWN0UmVzcG9uc2VzUGF0dGVybikpIHtcbiAgICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgICB0cmFjZTogICBjb3JyZWN0UmVzcG9uc2VzUGF0dGVyblRyYWNlLFxuICAgICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5DT1JSRUNUX1JFU1BPTlNFU19QQVRURVJOX01VU1RfQkVfQVJSQVksXG4gICAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgICAgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGRlZmluaXRpb24uY29ycmVjdFJlc3BvbnNlc1BhdHRlcm4uZm9yRWFjaCgocmVzcG9uc2UsIGkpID0+IHtcbiAgICAgICAgaWYgKHJlc3BvbnNlID09PSBudWxsIHx8IHJlc3BvbnNlID09PSB1bmRlZmluZWQgfHwgIXhhcGlWYWxpZGF0aW9uVXRpbHMuaXNTdHJpbmcocmVzcG9uc2UpKSB7XG4gICAgICAgICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICAgICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZExvb2t1cFRvVHJhY2UoY29ycmVjdFJlc3BvbnNlc1BhdHRlcm5UcmFjZSwgaSksXG4gICAgICAgICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5DT1JSRUNUX1JFU1BPTlNFU19QQVRURVJOX01VU1RfQkVfU1RSSU5HUyxcbiAgICAgICAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICB2YWxpZGF0ZUludGVyYWN0aW9uQ29tcG9uZW50QXJyYXkoXG4gICAgZGVmaW5pdGlvbi5jaG9pY2VzLFxuICAgIGRlZmluaXRpb24uaW50ZXJhY3Rpb25UeXBlLFxuICAgIFtwcm9wZXJ0aWVzLkNIT0lDRSwgcHJvcGVydGllcy5TRVFVRU5DSU5HXSxcbiAgICB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuQ0hPSUNFUyksXG4gICAgbG9jYWxFcnJvcnNcbiAgKTtcblxuICB2YWxpZGF0ZUludGVyYWN0aW9uQ29tcG9uZW50QXJyYXkoXG4gICAgZGVmaW5pdGlvbi5zY2FsZSxcbiAgICBkZWZpbml0aW9uLmludGVyYWN0aW9uVHlwZSxcbiAgICBbcHJvcGVydGllcy5MSUtFUlRdLFxuICAgIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSwgcHJvcGVydGllcy5TQ0FMRSksXG4gICAgbG9jYWxFcnJvcnNcbiAgKTtcblxuICB2YWxpZGF0ZUludGVyYWN0aW9uQ29tcG9uZW50QXJyYXkoXG4gICAgZGVmaW5pdGlvbi5zb3VyY2UsXG4gICAgZGVmaW5pdGlvbi5pbnRlcmFjdGlvblR5cGUsXG4gICAgW3Byb3BlcnRpZXMuTUFUQ0hJTkddLFxuICAgIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSwgcHJvcGVydGllcy5TT1VSQ0UpLFxuICAgIGxvY2FsRXJyb3JzXG4gICk7XG5cbiAgdmFsaWRhdGVJbnRlcmFjdGlvbkNvbXBvbmVudEFycmF5KFxuICAgIGRlZmluaXRpb24udGFyZ2V0LFxuICAgIGRlZmluaXRpb24uaW50ZXJhY3Rpb25UeXBlLFxuICAgIFtwcm9wZXJ0aWVzLk1BVENISU5HXSxcbiAgICB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuVEFSR0VUKSxcbiAgICBsb2NhbEVycm9yc1xuICApO1xuXG4gIHZhbGlkYXRlSW50ZXJhY3Rpb25Db21wb25lbnRBcnJheShcbiAgICBkZWZpbml0aW9uLnN0ZXBzLFxuICAgIGRlZmluaXRpb24uaW50ZXJhY3Rpb25UeXBlLFxuICAgIFtwcm9wZXJ0aWVzLlBFUkZPUk1BTkNFXSxcbiAgICB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuU1RFUFMpLFxuICAgIGxvY2FsRXJyb3JzXG4gICk7XG5cbiAgdmFsaWRhdGVBYnNlbmNlT2ZOb25XaGl0ZWxpc3RlZFByb3BlcnRpZXMoZGVmaW5pdGlvbiwgeGFwaVdoaXRlTGlzdFByb3BlcnRpZXMuQUNUSVZJVFlfREVGSU5JVElPTiwgbG9jYWxUcmFjZSwgbG9jYWxFcnJvcnMpO1xuICByZXR1cm4gbG9jYWxFcnJvcnM7XG59XG5cbmZ1bmN0aW9uIHZhbGlkYXRlQWN0aXZpdHkoYWN0aXZpdHksIHRyYWNlLCBlcnJvcnMpIHtcbiAgdmFyIGxvY2FsRXJyb3JzLCBsb2NhbFRyYWNlO1xuXG4gIGxvY2FsRXJyb3JzID0gZXJyb3JzIHx8IFtdO1xuICBsb2NhbFRyYWNlICA9IHRyYWNlICB8fCBwcm9wZXJ0aWVzLkFDVElWSVRZO1xuXG4gIGlmICgheGFwaVZhbGlkYXRpb25VdGlscy5pc05vbk51bGxNYXBPYmplY3QoYWN0aXZpdHkpKSB7XG4gICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlKSxcbiAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLkFDVElWSVRJRVNfTVVTVF9OT1RfQkVfTlVMTCxcbiAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgIH0pO1xuXG4gICAgcmV0dXJuIGxvY2FsRXJyb3JzO1xuICB9XG5cbiAgdmFsaWRhdGVQcm9wZXJ0eUlzVXJpKGFjdGl2aXR5LCBwcm9wZXJ0aWVzLklELCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycywgIC8qaXNSZXF1aXJlZCovdHJ1ZSk7XG5cbiAgaWYgKGFjdGl2aXR5LmRlZmluaXRpb24gIT09IHVuZGVmaW5lZCkge1xuICAgIHZhbGlkYXRlQWN0aXZpdHlEZWZpbnRpb24oXG4gICAgICBhY3Rpdml0eS5kZWZpbml0aW9uLFxuICAgICAgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRQcm9wVG9UcmFjZShsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLkRFRklOSVRJT04pLFxuICAgICAgbG9jYWxFcnJvcnNcbiAgICApO1xuICB9XG5cbiAgdmFsaWRhdGVBYnNlbmNlT2ZOb25XaGl0ZWxpc3RlZFByb3BlcnRpZXMoYWN0aXZpdHksIHhhcGlXaGl0ZUxpc3RQcm9wZXJ0aWVzLkFDVElWSVRZLCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycyk7XG5cbiAgcmV0dXJuIGxvY2FsRXJyb3JzO1xufVxuXG5mdW5jdGlvbiB2YWxpZGF0ZVN0YXRlbWVudFJlZihzdGF0ZW1lbnRSZWYsIHRyYWNlLCBlcnJvcnMpIHtcbiAgdmFyIGxvY2FsRXJyb3JzLCBsb2NhbFRyYWNlO1xuXG4gIGxvY2FsRXJyb3JzID0gZXJyb3JzIHx8IFtdO1xuICBsb2NhbFRyYWNlICA9IHRyYWNlICB8fCBwcm9wZXJ0aWVzLlNUQVRFTUVOVF9SRUY7XG5cbiAgaWYgKCF4YXBpVmFsaWRhdGlvblV0aWxzLmlzTm9uTnVsbE1hcE9iamVjdChzdGF0ZW1lbnRSZWYpKSB7XG4gICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlKSxcbiAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLlNUQVRFTUVOVF9SRUZfTVVTVF9OT1RfQkVfTlVMTF9NQVBfT0JKRUNUUyxcbiAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgIH0pO1xuICAgIHJldHVybiBsb2NhbEVycm9ycztcbiAgfVxuXG5cbiAgaWYgKHN0YXRlbWVudFJlZi5vYmplY3RUeXBlICE9PSBvYmplY3RUeXBlcy5TVEFURU1FTlRfUkVGKSB7XG4gICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuT0JKRUNUX1RZUEUpLFxuICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuT0JKRUNUX1RZUEVfTVVTVF9CRV9TVEFURU1FTlRfUkVGLFxuICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgfSk7XG4gIH1cblxuICBpZiAoIXN0YXRlbWVudFJlZi5pZCB8fCAheGFwaVZhbGlkYXRpb25SZWdleC5VVUlELnRlc3Qoc3RhdGVtZW50UmVmLmlkKSkge1xuICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRQcm9wVG9UcmFjZShsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLklEKSxcbiAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLklEX01VU1RfQkVfVkFMSURfVVVJRF9SRUYsXG4gICAgICBsZXZlbDogIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgIH0pO1xuICB9XG5cbiAgdmFsaWRhdGVBYnNlbmNlT2ZOb25XaGl0ZWxpc3RlZFByb3BlcnRpZXMoc3RhdGVtZW50UmVmLCB4YXBpV2hpdGVMaXN0UHJvcGVydGllcy5TVEFURU1FTlRfUkVGLCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycyk7XG5cbiAgcmV0dXJuIGxvY2FsRXJyb3JzO1xufVxuXG5mdW5jdGlvbiB2YWxpZGF0ZVNjb3JlKHNjb3JlLCB0cmFjZSwgZXJyb3JzKSB7XG4gIHZhciBsb2NhbEVycm9ycywgbG9jYWxUcmFjZTtcblxuICBsb2NhbEVycm9ycyA9IGVycm9ycyB8fCBbXTtcbiAgbG9jYWxUcmFjZSAgPSB0cmFjZSAgfHwgcHJvcGVydGllcy5TQ09SRTtcblxuICBpZiAoc2NvcmUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgcmV0dXJuIGxvY2FsRXJyb3JzO1xuICB9XG5cbiAgdmFsaWRhdGVQcm9wZXJ0eUlzTnVtYmVyKHNjb3JlLCBwcm9wZXJ0aWVzLlNDQUxFRCwgbG9jYWxUcmFjZSwgbG9jYWxFcnJvcnMsICAvKmlzUmVxdWlyZWQqL2ZhbHNlKTtcblxuICBpZiAoc2NvcmUuc2NhbGVkICE9PSB1bmRlZmluZWQpIHtcbiAgICBpZiAoc2NvcmUuc2NhbGVkIDwgeGFwaUdlbmVyYWwuTUlOX1NDQUxFRF9WQUxVRSB8fCBzY29yZS5zY2FsZWQgPiB4YXBpR2VuZXJhbC5NQVhfU0NBTEVEX1ZBTFVFKSB7XG4gICAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRQcm9wVG9UcmFjZShsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLlNDQUxFRCksXG4gICAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLlNDQUxFRF9NVVNUX0JFX0JFVFdFRU5fMF8xLFxuICAgICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIGlmIChzY29yZS5taW4gIT09IHVuZGVmaW5lZCkge1xuICAgIHZhbGlkYXRlUHJvcGVydHlJc051bWJlcihzY29yZSwgcHJvcGVydGllcy5NSU4sIGxvY2FsVHJhY2UsIGxvY2FsRXJyb3JzLCAgLyppc1JlcXVpcmVkKi9mYWxzZSk7XG5cbiAgICAgIGlmIChzY29yZS5yYXcgIT09IHVuZGVmaW5lZCAmJiBzY29yZS5yYXcgPCBzY29yZS5taW4pIHtcbiAgICAgICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRQcm9wVG9UcmFjZShsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLlJBVyksXG4gICAgICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuUkFXX01VU1RfQkVfR1JFQVRFUl9USEFOX01JTixcbiAgICAgICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChzY29yZS5tYXggIT09IHVuZGVmaW5lZCAmJiBzY29yZS5tYXggPCBzY29yZS5taW4pIHtcbiAgICAgICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRQcm9wVG9UcmFjZShsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLk1BWCksXG4gICAgICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuTUFYX01VU1RfQkVfR1JFQVRFUl9USEFOX01JTixcbiAgICAgICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICAgICAgfSk7XG4gICAgICB9XG4gIH1cblxuICBpZiAoc2NvcmUubWF4ICE9PSB1bmRlZmluZWQpIHtcbiAgICB2YWxpZGF0ZVByb3BlcnR5SXNOdW1iZXIoc2NvcmUsIHByb3BlcnRpZXMuTUFYLCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycywgIC8qaXNSZXF1aXJlZCovZmFsc2UpO1xuXG4gICAgaWYgKHNjb3JlLnJhdyAhPT0gdW5kZWZpbmVkICYmIHNjb3JlLnJhdyA+IHNjb3JlLm1heCkge1xuICAgICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSwgcHJvcGVydGllcy5SQVcpLFxuICAgICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5SQVdfTVVTVF9CRV9MRVNTX1RIQU5fTUFYLFxuICAgICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIHZhbGlkYXRlUHJvcGVydHlJc051bWJlcihzY29yZSwgcHJvcGVydGllcy5SQVcsIGxvY2FsVHJhY2UsIGxvY2FsRXJyb3JzLCAgLyppc1JlcXVpcmVkKi9mYWxzZSk7XG4gIHZhbGlkYXRlQWJzZW5jZU9mTm9uV2hpdGVsaXN0ZWRQcm9wZXJ0aWVzKHNjb3JlLCB4YXBpV2hpdGVMaXN0UHJvcGVydGllcy5TQ09SRSwgbG9jYWxUcmFjZSwgbG9jYWxFcnJvcnMpO1xuXG4gIHJldHVybiBsb2NhbEVycm9ycztcbn1cblxuZnVuY3Rpb24gdmFsaWRhdGVSZXN1bHQocmVzdWx0LCB0cmFjZSwgZXJyb3JzKSB7XG4gIHZhciBsb2NhbEVycm9ycywgbG9jYWxUcmFjZTtcblxuICBsb2NhbEVycm9ycyA9IGVycm9ycyB8fCBbXTtcbiAgbG9jYWxUcmFjZSAgPSB0cmFjZSAgfHwgcHJvcGVydGllcy5SRVNVTFQ7XG5cbiAgaWYgKHJlc3VsdCA9PT0gdW5kZWZpbmVkKSB7cmV0dXJuIGxvY2FsRXJyb3JzO31cblxuICBpZiAoIXhhcGlWYWxpZGF0aW9uVXRpbHMuaXNOb25OdWxsTWFwT2JqZWN0KHJlc3VsdCkpIHtcbiAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSksXG4gICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5SRVNVTFRfTVVTVF9CRV9NQVBfT0JKRUNULFxuICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgfSk7XG5cbiAgICByZXR1cm4gbG9jYWxFcnJvcnM7XG4gIH1cblxuICB2YWxpZGF0ZVNjb3JlKHJlc3VsdC5zY29yZSwgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRQcm9wVG9UcmFjZShsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLlNDT1JFKSwgbG9jYWxFcnJvcnMpO1xuICB2YWxpZGF0ZVByb3BlcnR5SXNCb29sZWFuKHJlc3VsdCwgcHJvcGVydGllcy5TVUNDRVNTLCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycywgIC8qaXNSZXF1aXJlZCovZmFsc2UpO1xuICB2YWxpZGF0ZVByb3BlcnR5SXNCb29sZWFuKHJlc3VsdCwgcHJvcGVydGllcy5DT01QTEVUSU9OLCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycywgIC8qaXNSZXF1aXJlZCovZmFsc2UpO1xuICB2YWxpZGF0ZVByb3BlcnR5SXNTdHJpbmcocmVzdWx0LCBwcm9wZXJ0aWVzLlJFU1BPTlNFLCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycywgIC8qaXNSZXF1aXJlZCovZmFsc2UpO1xuICB2YWxpZGF0ZUV4dGVuc2lvbnMocmVzdWx0LmV4dGVuc2lvbnMsIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSwgcHJvcGVydGllcy5FWFRFTlNJT05TKSwgbG9jYWxFcnJvcnMpO1xuXG4gIGlmIChyZXN1bHQuZHVyYXRpb24gIT09IHVuZGVmaW5lZCAmJiAocmVzdWx0LmR1cmF0aW9uID09PSBudWxsIHx8ICF4YXBpVmFsaWRhdGlvblV0aWxzLmlzU3RyaW5nKHJlc3VsdC5kdXJhdGlvbikgfHwgIXhhcGlWYWxpZGF0aW9uUmVnZXguSVNPXzg2MDFfRFVSQVRJT04udGVzdChyZXN1bHQuZHVyYXRpb24pKSkge1xuICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRQcm9wVG9UcmFjZShsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLkRVUkFUSU9OKSxcbiAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLkRVUkFUSU9OX01VU1RfQkVfVkFMSUQsXG4gICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICB9KTtcbiAgfVxuXG4gIHZhbGlkYXRlQWJzZW5jZU9mTm9uV2hpdGVsaXN0ZWRQcm9wZXJ0aWVzKHJlc3VsdCwgeGFwaVdoaXRlTGlzdFByb3BlcnRpZXMuUkVTVUxULCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycyk7XG5cbiAgcmV0dXJuIGxvY2FsRXJyb3JzO1xufVxuXG5mdW5jdGlvbiB2YWxpZGF0ZVByb3BlcnR5SXNJU084NjAxU3RyaW5nKHBhcmVudCwgcHJvcGVydHlOYW1lLCB0cmFjZSwgZXJyb3JzKSB7XG4gIHZhciBsb2NhbEVycm9ycywgbG9jYWxUcmFjZSwgbWF0Y2hlZCwgZGF0ZXRpbWU7XG5cbiAgbG9jYWxFcnJvcnMgPSBlcnJvcnMgfHwgW107XG4gIGxvY2FsVHJhY2UgID0gdHJhY2UgIHx8IHByb3BlcnRpZXMuREFURV9USU1FO1xuICBkYXRldGltZSAgICA9IHBhcmVudFtwcm9wZXJ0eU5hbWVdO1xuXG4gIGlmIChkYXRldGltZSA9PT0gdW5kZWZpbmVkKSB7cmV0dXJuIGxvY2FsRXJyb3JzO31cblxuICBpZiAoZGF0ZXRpbWUgPT09IG51bGwgfHwgIXhhcGlWYWxpZGF0aW9uVXRpbHMuaXNTdHJpbmcoZGF0ZXRpbWUpKSB7XG4gICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlLCBwcm9wZXJ0eU5hbWUpLFxuICAgICAgbWVzc2FnZTogYCR7cHJvcGVydHlOYW1lfSAke3hhcGlWYWxpZGF0aW9uRXJyb3JzLk1VU1RfQkVfU1RSSU5HfWAsXG4gICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICB9KTtcblxuICAgIHJldHVybiBsb2NhbEVycm9ycztcbiAgfVxuXG4gIG1hdGNoZWQgPSB4YXBpVmFsaWRhdGlvblJlZ2V4LklTT184NjAxX0RBVEVfVElNRS5leGVjKGRhdGV0aW1lKTtcblxuICBpZiAobWF0Y2hlZCkge1xuICAgIGlmICghZGF0ZUluY2x1ZGVzWm9uZUluZm9ybWF0aW9uKG1hdGNoZWQpKSB7XG4gICAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSwgcHJvcGVydHlOYW1lKSxcbiAgICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuREFURV9TSE9VTERfSU5DTFVERV9aT05FX0lORk9STUFUSU9OLFxuICAgICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuU0hPVUxEX1ZJT0xBVElPTlxuICAgICAgfSk7XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSwgcHJvcGVydHlOYW1lKSxcbiAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLkRBVEVfTVVTVF9CRV9WQUxJRCxcbiAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgIH0pO1xuICB9XG5cbiAgcmV0dXJuIGxvY2FsRXJyb3JzO1xufVxuXG5mdW5jdGlvbiB2YWxpZGF0ZVZlcnNpb24odmVyc2lvbiwgdHJhY2UsIGVycm9ycykge1xuICB2YXIgbG9jYWxFcnJvcnMsIGxvY2FsVHJhY2U7XG5cbiAgbG9jYWxFcnJvcnMgPSBlcnJvcnMgfHwgW107XG4gIGxvY2FsVHJhY2UgID0gdHJhY2UgIHx8IHByb3BlcnRpZXMuVkVSU0lPTjtcblxuICBpZiAodmVyc2lvbiA9PT0gdW5kZWZpbmVkKSB7cmV0dXJuIGxvY2FsRXJyb3JzO31cblxuICBpZiAodmVyc2lvbiA9PT0gbnVsbCB8fCAheGFwaVZhbGlkYXRpb25VdGlscy5pc1N0cmluZyh2ZXJzaW9uKSB8fCAheGFwaVZhbGlkYXRpb25SZWdleC5TRU1WRVJfMV9QXzBfUF8wLnRlc3QodmVyc2lvbikpIHtcbiAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMubG9jYWxUcmFjZVRvU3RyaW5nKGxvY2FsVHJhY2UpLFxuICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuVkVSU0lPTl9NVVNUX0NPTVBMWV9TRU1BTlRJQ19WRVJTSU9OSU5HLFxuICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgfSk7XG4gIH1cblxuICByZXR1cm4gbG9jYWxFcnJvcnM7XG59XG5cbmZ1bmN0aW9uIHZhbGlkYXRlQXR0YWNobWVudE9iamVjdChhdHRhY2htZW50LCB0cmFjZSwgZXJyb3JzKSB7XG4gIHZhciBsb2NhbEVycm9ycywgbG9jYWxUcmFjZTtcblxuICBsb2NhbEVycm9ycyA9IGVycm9ycyB8fCBbXTtcbiAgbG9jYWxUcmFjZSAgPSB0cmFjZSB8fCBwcm9wZXJ0aWVzLkFUVEFDSE1FTlQ7XG5cbiAgaWYgKCF4YXBpVmFsaWRhdGlvblV0aWxzLmlzTm9uTnVsbE1hcE9iamVjdChhdHRhY2htZW50KSkge1xuICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSksXG4gICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5BVFRBQ0hNRU5UU19NVVNUX05PVF9CRV9OVUxMX01BUF9PQkpFQ1RTLFxuICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgfSk7XG5cbiAgICByZXR1cm4gbG9jYWxFcnJvcnM7XG4gIH1cblxuICBpZiAoYXR0YWNobWVudC5kaXNwbGF5ID09PSB1bmRlZmluZWQpIHtcbiAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMubG9jYWxUcmFjZVRvU3RyaW5nKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuRElTUExBWSksXG4gICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5ESVNQTEFZX1NIT1VMRF9CRV9QUk9WSURFRCxcbiAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgIH0pO1xuXG4gIH0gZWxzZSB7XG4gICAgdmFsaWRhdGVMYW5ndWFnZU1hcChhdHRhY2htZW50LmRpc3BsYXksIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSwgcHJvcGVydGllcy5ESVNQTEFZKSwgbG9jYWxFcnJvcnMpO1xuICB9XG5cbiAgdmFsaWRhdGVMYW5ndWFnZU1hcChhdHRhY2htZW50LmRlc2NyaXB0aW9uLCB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuREVTQ1JJUFRJT04pLCBsb2NhbEVycm9ycyk7XG4gIHZhbGlkYXRlUHJvcGVydHlJc1VyaShhdHRhY2htZW50LCBwcm9wZXJ0aWVzLlVTQUdFX1RZUEUsIGxvY2FsVHJhY2UsIGxvY2FsRXJyb3JzLCAvKmlzUmVxdWlyZWQqL3RydWUsIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTik7XG4gIHZhbGlkYXRlUHJvcGVydHlJc1VyaShhdHRhY2htZW50LCBwcm9wZXJ0aWVzLkZJTEVfVVJMLCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycywgIC8qaXNSZXF1aXJlZCovZmFsc2UsIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTik7XG5cbiAgLy8gVE9ETyAtIG1vcmUgY29tcGxldGUgdmFsaWRhdGlvbiBmb3IgSW50ZXJuZXQgTWVkaWEgVHlwZSB2aWEgUkZDIDIwNDZcbiAgdmFsaWRhdGVQcm9wZXJ0eUlzU3RyaW5nKGF0dGFjaG1lbnQsIHByb3BlcnRpZXMuQ09OVEVOVF9UWVBFLCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycywgLyppc1JlcXVpcmVkKi90cnVlLCB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT04pO1xuXG4gIGlmIChhdHRhY2htZW50Lmxlbmd0aCA9PT0gdW5kZWZpbmVkIHx8IGF0dGFjaG1lbnQubGVuZ3RoID09PSBudWxsIHx8ICF4YXBpVmFsaWRhdGlvblV0aWxzLmlzTnVtYmVyKGF0dGFjaG1lbnQubGVuZ3RoKSB8fCAoYXR0YWNobWVudC5sZW5ndGggJSAxICE9PSAwKSkge1xuICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSwgcHJvcGVydGllcy5MRU5HVEgpLFxuICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuTEVOR1RIX01VU1RfQkVfSU5URUdFUixcbiAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgIH0pO1xuICB9XG5cbiAgaWYgKGF0dGFjaG1lbnQuc2hhMiA9PT0gdW5kZWZpbmVkKSB7XG4gICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLlNIQTIpLFxuICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuU0hBMl9NVVNUX0JFX1BST1ZJREVEX09OX0FUVEFDSE1FTlRfT0JKRUNUUyxcbiAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgIH0pO1xuICB9IGVsc2UgaWYgKGF0dGFjaG1lbnQuc2hhMiA9PT0gbnVsbCB8fCAheGFwaVZhbGlkYXRpb25VdGlscy5pc1N0cmluZyhhdHRhY2htZW50LnNoYTIpIHx8ICF4YXBpVmFsaWRhdGlvblJlZ2V4LkJBU0VfNjQudGVzdChhdHRhY2htZW50LnNoYTIpKSB7XG4gICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLlNIQTIpLFxuICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuU0hBMl9NVVNUX0NPTlRBSU5fQkFTRV82NF9TVFJJTkcsXG4gICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICB9KTtcbiAgfVxuXG4gIHZhbGlkYXRlQWJzZW5jZU9mTm9uV2hpdGVsaXN0ZWRQcm9wZXJ0aWVzKGF0dGFjaG1lbnQsIHhhcGlXaGl0ZUxpc3RQcm9wZXJ0aWVzLkFUVEFDSE1FTlQsIGxvY2FsVHJhY2UsIGxvY2FsRXJyb3JzKTtcbiAgcmV0dXJuIGxvY2FsRXJyb3JzO1xufVxuXG5mdW5jdGlvbiB2YWxpZGF0ZUF0dGFjaG1lbnRzKGF0dGFjaG1lbnRzLCB0cmFjZSwgZXJyb3JzKSB7XG4gIHZhciBsb2NhbEVycm9ycywgbG9jYWxUcmFjZTtcblxuICBsb2NhbEVycm9ycyA9IGVycm9ycyB8fCBbXTtcbiAgbG9jYWxUcmFjZSAgPSB0cmFjZSAgfHwgcHJvcGVydGllcy5BVFRBQ0hNRU5UUztcblxuICBpZiAoYXR0YWNobWVudHMgPT09IHVuZGVmaW5lZCkge3JldHVybiBsb2NhbEVycm9yczt9XG5cbiAgaWYgKGF0dGFjaG1lbnRzID09PSBudWxsIHx8ICF4YXBpVmFsaWRhdGlvblV0aWxzLmlzQXJyYXkoYXR0YWNobWVudHMpKSB7XG4gICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlKSxcbiAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLkFUVEFDSE1FTlRTX01VU1RfQkVfTk9UX05VTExfQVJSQVksXG4gICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICB9KTtcblxuICAgIHJldHVybiBsb2NhbEVycm9ycztcbiAgfVxuXG4gIGF0dGFjaG1lbnRzLmZvckVhY2goKGF0dGFjaG1lbnQsIGkpID0+IHtcbiAgICB2YWxpZGF0ZUF0dGFjaG1lbnRPYmplY3QoYXR0YWNobWVudCwgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRMb29rdXBUb1RyYWNlKGxvY2FsVHJhY2UsIGkpLCBsb2NhbEVycm9ycyk7XG4gIH0pO1xuXG4gIHJldHVybiBsb2NhbEVycm9ycztcbn1cblxuZnVuY3Rpb24gdmFsaWRhdGVBZ2VudChhZ2VudCwgdHJhY2UsIGVycm9ycykge1xuICB2YXIgbG9jYWxFcnJvcnMsIGxvY2FsVHJhY2UsIGlmaUNvdW50O1xuXG4gIGxvY2FsRXJyb3JzID0gZXJyb3JzIHx8IFtdO1xuICBsb2NhbFRyYWNlICA9IHRyYWNlICB8fCBwcm9wZXJ0aWVzLkFHRU5UO1xuXG4gIGlmICgheGFwaVZhbGlkYXRpb25VdGlscy5pc05vbk51bGxNYXBPYmplY3QoYWdlbnQpKSB7XG4gICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlKSxcbiAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLkFHRU5UX01VU1RfQkVfTk9OX05VTExfTUFQX09CSkVDVCxcbiAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgIH0pO1xuICAgIHJldHVybiBsb2NhbEVycm9ycztcbiAgfVxuXG4gIGlmaUNvdW50ID0gZ2V0SUZJQ291bnQoYWdlbnQpO1xuXG4gIGlmIChpZmlDb3VudCAhPT0geGFwaUdlbmVyYWwuTlVNRVJfT0ZfU1BFQ0lGSUVEX0lGSV9QUk9QRVJUSUVTKSB7XG4gICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlKSxcbiAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLkFHRU5UX0lGSV9QUk9QRVJUSUVTX01VU1RfQkVfU1BFQ0lGSUVELFxuICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgfSk7XG4gIH1cblxuICBpZiAoYWdlbnQub2JqZWN0VHlwZSA9PT0gb2JqZWN0VHlwZXMuR1JPVVApIHtcbiAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMubG9jYWxUcmFjZVRvU3RyaW5nKGxvY2FsVHJhY2UpLFxuICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuQUdFTlRfTVVTVF9OT1RfSEFWRV9HUk9VUF9DSEFSQUNURVJJU1RJQ1MsXG4gICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICB9KTtcbiAgfVxuXG4gIHZhbGlkYXRlSUZJUHJvcGVydGllcyhhZ2VudCwgbG9jYWxUcmFjZSwgbG9jYWxFcnJvcnMpO1xuICB2YWxpZGF0ZVByb3BlcnR5SXNTdHJpbmcoYWdlbnQsIHByb3BlcnRpZXMuTkFNRSwgbG9jYWxUcmFjZSwgbG9jYWxFcnJvcnMsICAvKmlzUmVxdWlyZWQqL2ZhbHNlKTtcblxuICB2YWxpZGF0ZUFic2VuY2VPZk5vbldoaXRlbGlzdGVkUHJvcGVydGllcyhhZ2VudCwgeGFwaVdoaXRlTGlzdFByb3BlcnRpZXMuQUdFTlQsIGxvY2FsVHJhY2UsIGxvY2FsRXJyb3JzKTtcblxuICByZXR1cm4gbG9jYWxFcnJvcnM7XG59XG5cbmZ1bmN0aW9uIHZhbGlkYXRlR3JvdXAoZ3JvdXAsIHRyYWNlLCBlcnJvcnMpIHtcbiAgdmFyIGxvY2FsRXJyb3JzLCBsb2NhbFRyYWNlLCBtZW1iZXJUcmFjZSwgaWZpQ291bnQ7XG5cbiAgbG9jYWxFcnJvcnMgPSBlcnJvcnMgfHwgW107XG4gIGxvY2FsVHJhY2UgID0gdHJhY2UgIHx8IHByb3BlcnRpZXMuR1JPVVA7XG4gIG1lbWJlclRyYWNlID0geGFwaVZhbGlkYXRpb25VdGlscy5hZGRQcm9wVG9UcmFjZShsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLk1FTUJFUik7XG5cbiAgaWYgKCF4YXBpVmFsaWRhdGlvblV0aWxzLmlzTm9uTnVsbE1hcE9iamVjdChncm91cCkpIHtcbiAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMubG9jYWxUcmFjZVRvU3RyaW5nKGxvY2FsVHJhY2UpLFxuICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuR1JPVVBfTVVTVF9CRV9OT05fTlVMTF9NQVBfT0JKRUNULFxuICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgfSk7XG5cbiAgICByZXR1cm4gbG9jYWxFcnJvcnM7XG4gIH1cblxuICBpZmlDb3VudCA9IGdldElGSUNvdW50KGdyb3VwKTtcblxuICBpZiAoaWZpQ291bnQgPT09IDApIHtcbiAgICBpZiAoZ3JvdXAubWVtYmVyID09PSBudWxsIHx8IGdyb3VwLm1lbWJlciA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgICAgdHJhY2U6ICAgbWVtYmVyVHJhY2UsXG4gICAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLk1FTUJFUl9NVVNUX0JFX1BST1ZJREVEX0ZPUl9BTk9OWU1PVVNfR1JPVVBTLFxuICAgICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICAgIH0pO1xuICAgIH1cbiAgfSBlbHNlIGlmIChpZmlDb3VudCA+IHhhcGlHZW5lcmFsLk5VTUVSX09GX1NQRUNJRklFRF9JRklfUFJPUEVSVElFUykge1xuICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSksXG4gICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5HUk9VUF9JRklfUFJPUEVSVElFU19NVVNUX0JFX1NQRUNJRklFRCxcbiAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgIH0pO1xuICB9XG5cbiAgdmFsaWRhdGVJRklQcm9wZXJ0aWVzKGdyb3VwLCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycyk7XG5cbiAgdmFsaWRhdGVQcm9wZXJ0eUlzU3RyaW5nKGdyb3VwLCBwcm9wZXJ0aWVzLk5BTUUsIGxvY2FsVHJhY2UsIGxvY2FsRXJyb3JzLCAgLyppc1JlcXVpcmVkKi9mYWxzZSk7XG5cbiAgaWYgKGdyb3VwLm1lbWJlciAhPT0gdW5kZWZpbmVkKSB7XG4gICAgaWYgKGdyb3VwLm1lbWJlciA9PT0gbnVsbCB8fCAheGFwaVZhbGlkYXRpb25VdGlscy5pc0FycmF5KGdyb3VwLm1lbWJlcikpIHtcbiAgICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLk1FTUJFUiksXG4gICAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLkdST1VQX01FTUJFUl9NVVNUX0JFX0FSUkFZLFxuICAgICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICAgIH0pO1xuICAgIH0gZWxzZSB7XG4gICAgICBncm91cC5tZW1iZXIuZm9yRWFjaCgobWVtYmVyLCBpKSA9PiB7XG4gICAgICAgIHZhbGlkYXRlQWdlbnQobWVtYmVyLCB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZExvb2t1cFRvVHJhY2UobWVtYmVyVHJhY2UsIGkpLCBsb2NhbEVycm9ycyk7XG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICB2YWxpZGF0ZUFic2VuY2VPZk5vbldoaXRlbGlzdGVkUHJvcGVydGllcyhncm91cCwgeGFwaVdoaXRlTGlzdFByb3BlcnRpZXMuR1JPVVAsIGxvY2FsVHJhY2UsIGxvY2FsRXJyb3JzKTtcblxuICByZXR1cm4gbG9jYWxFcnJvcnM7XG59XG5cbmZ1bmN0aW9uIHZhbGlkYXRlQWN0b3IoYWN0b3IsIHRyYWNlLCBlcnJvcnMpIHtcbiAgdmFyIGxvY2FsRXJyb3JzLCBsb2NhbFRyYWNlO1xuXG4gIGxvY2FsRXJyb3JzID0gZXJyb3JzIHx8IFtdO1xuICBsb2NhbFRyYWNlICA9IHRyYWNlICB8fCBwcm9wZXJ0aWVzLkFDVE9SO1xuXG4gIGlmIChhY3RvciA9PT0gbnVsbCB8fCBhY3RvciA9PT0gdW5kZWZpbmVkKSB7XG4gICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlKSxcbiAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLkFDVE9SX01VU1RfQkVfUFJPVklERUQsXG4gICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICB9KTtcblxuICAgIHJldHVybiBsb2NhbEVycm9ycztcbiAgfVxuXG4gIGlmICh4YXBpVmFsaWRhdGlvblV0aWxzLmlzR3JvdXAoYWN0b3IsIG9iamVjdFR5cGVzLkdST1VQKSkge1xuICAgIHZhbGlkYXRlR3JvdXAoYWN0b3IsIGxvY2FsVHJhY2UsIGxvY2FsRXJyb3JzKTtcbiAgfSBlbHNlIHtcbiAgICB2YWxpZGF0ZUFnZW50KGFjdG9yLCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycyk7XG4gIH1cblxuICByZXR1cm4gbG9jYWxFcnJvcnM7XG59XG5cbmZ1bmN0aW9uIHZhbGlkYXRlQXV0aG9yaXR5KGF1dGhvcml0eSwgdHJhY2UsIGVycm9ycykge1xuICB2YXIgbG9jYWxFcnJvcnMsIGxvY2FsVHJhY2U7XG5cbiAgbG9jYWxFcnJvcnMgPSBlcnJvcnMgfHwgW107XG4gIGxvY2FsVHJhY2UgID0gdHJhY2UgIHx8IHByb3BlcnRpZXMuQVVUSE9SSVRZO1xuXG4gIGlmIChhdXRob3JpdHkgPT09IHVuZGVmaW5lZCkge1xuICAgIHJldHVybiBsb2NhbEVycm9ycztcbiAgfVxuXG4gIGlmICgheGFwaVZhbGlkYXRpb25VdGlscy5pc05vbk51bGxNYXBPYmplY3QoYXV0aG9yaXR5KSkge1xuICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSksXG4gICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5BVVRIT1JJVFlfTVVTVF9CRV9OT05fTlVMTF9NQVBfT0JKRUNULFxuICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgfSk7XG5cbiAgICByZXR1cm4gbG9jYWxFcnJvcnM7XG4gIH1cbiAgaWYgKHhhcGlWYWxpZGF0aW9uVXRpbHMuaXNHcm91cChhdXRob3JpdHksIG9iamVjdFR5cGVzLkdST1VQKSkge1xuICAgIHZhbGlkYXRlR3JvdXAoYXV0aG9yaXR5LCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycyk7XG4gICAgaWYgKCFhdXRob3JpdHkubWVtYmVyIHx8ICFhdXRob3JpdHkubWVtYmVyLmxlbmd0aCB8fCBhdXRob3JpdHkubWVtYmVyLmxlbmd0aCAhPT0geGFwaUdlbmVyYWwuR1JPVVBfQVVUSE9SSVRZX0FHRU5UX01FTUJFUlMpIHtcbiAgICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLk1FTUJFUiksXG4gICAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLkdST1VQX0FVVEhPUklUWV9BR0VOVF9NRU1CRVJTX01VU1RfQkVfVFdPLFxuICAgICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICAgIH0pO1xuICAgIH1cbiAgfSBlbHNlIHtcbiAgICB2YWxpZGF0ZUFnZW50KGF1dGhvcml0eSwgbG9jYWxUcmFjZSwgbG9jYWxFcnJvcnMpO1xuICB9XG5cbiAgcmV0dXJuIGxvY2FsRXJyb3JzO1xufVxuXG5mdW5jdGlvbiB2YWxpZGF0ZUNvbnRleHRBY3Rpdml0eVN1YkNvbnRleHQoc3ViQ29udGV4dCwgdHJhY2UsIGVycm9ycykge1xuICB2YXIgbG9jYWxFcnJvcnMsIGxvY2FsVHJhY2U7XG5cbiAgbG9jYWxFcnJvcnMgPSBlcnJvcnMgfHwgW107XG4gIGxvY2FsVHJhY2UgID0gdHJhY2UgIHx8IHByb3BlcnRpZXMuU1VCX0NPTlRFWFQ7XG5cbiAgaWYgKHN1YkNvbnRleHQgPT09IHVuZGVmaW5lZCkge3JldHVybiBsb2NhbEVycm9yczt9XG5cbiAgaWYgKHN1YkNvbnRleHQgPT09IG51bGwpIHtcbiAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMubG9jYWxUcmFjZVRvU3RyaW5nKGxvY2FsVHJhY2UpLFxuICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuQ09OVEVYVF9BQ1RJVklUSUVTX01VU1RfTk9UX0JFX05VTEwsXG4gICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICB9KTtcbiAgfSBlbHNlIGlmICh4YXBpVmFsaWRhdGlvblV0aWxzLmlzQXJyYXkoc3ViQ29udGV4dCkpIHtcbiAgICBzdWJDb250ZXh0LmZvckVhY2goKGFjdGl2aXR5LCBpKSA9PiB7XG4gICAgICB2YWxpZGF0ZUFjdGl2aXR5KGFjdGl2aXR5LCB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZExvb2t1cFRvVHJhY2UobG9jYWxUcmFjZSwgaSksIGxvY2FsRXJyb3JzKTtcbiAgICB9KTtcbiAgfSBlbHNlIGlmICh4YXBpVmFsaWRhdGlvblV0aWxzLmlzT2JqZWN0KHN1YkNvbnRleHQpKSB7XG4gICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlKSxcbiAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLkNPTlRFWFRfQUNUSVZJVElFU19TSE9VTERfQkVfQU5fQVJSQVksXG4gICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuU0hPVUxEX1ZJT0xBVElPTlxuICAgIH0pO1xuXG4gICAgdmFsaWRhdGVBY3Rpdml0eShzdWJDb250ZXh0LCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycyk7XG4gIH0gZWxzZSB7XG4gICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlKSxcbiAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLkNPTlRFWFRfQUNUSVZJVElFU19NVVNUX0JFX0FSUkFZX09SX0FDVElWSVRZX09CSixcbiAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTn0pO1xuICB9XG4gIHJldHVybiBsb2NhbEVycm9ycztcbn1cblxuZnVuY3Rpb24gdmFsaWRhdGVDb250ZXh0QWN0aXZpdGllcyhjb250ZXh0QWN0aXZpdGllcywgdHJhY2UsIGVycm9ycykge1xuICB2YXIgbG9jYWxFcnJvcnMsIGxvY2FsVHJhY2U7XG5cbiAgbG9jYWxFcnJvcnMgPSBlcnJvcnMgfHwgW107XG4gIGxvY2FsVHJhY2UgID0gdHJhY2UgIHx8IHByb3BlcnRpZXMuQ09OVEVYVF9BQ1RJVklUSUVTO1xuXG4gIGlmIChjb250ZXh0QWN0aXZpdGllcyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgcmV0dXJuIGxvY2FsRXJyb3JzO1xuICB9XG5cbiAgaWYgKCF4YXBpVmFsaWRhdGlvblV0aWxzLmlzTm9uTnVsbE1hcE9iamVjdChjb250ZXh0QWN0aXZpdGllcykpIHtcbiAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMubG9jYWxUcmFjZVRvU3RyaW5nKGxvY2FsVHJhY2UpLFxuICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuQ09OVEVYVF9BQ1RJVklUSUVTX01VU1RfQkVfTk9OX05VTExfTUFQX09CSkVDVCxcbiAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgIH0pO1xuICAgIHJldHVybiBsb2NhbEVycm9ycztcbiAgfVxuXG4gIHZhbGlkYXRlQ29udGV4dEFjdGl2aXR5U3ViQ29udGV4dChjb250ZXh0QWN0aXZpdGllcy5wYXJlbnQsIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSwgcHJvcGVydGllcy5QQVJFTlQpLCBsb2NhbEVycm9ycyk7XG4gIHZhbGlkYXRlQ29udGV4dEFjdGl2aXR5U3ViQ29udGV4dChjb250ZXh0QWN0aXZpdGllcy5ncm91cGluZywgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRQcm9wVG9UcmFjZShsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLkdST1VQSU5HKSwgbG9jYWxFcnJvcnMpO1xuICB2YWxpZGF0ZUNvbnRleHRBY3Rpdml0eVN1YkNvbnRleHQoY29udGV4dEFjdGl2aXRpZXMuY2F0ZWdvcnksIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSwgcHJvcGVydGllcy5DQVRFR09SWSksIGxvY2FsRXJyb3JzKTtcbiAgdmFsaWRhdGVDb250ZXh0QWN0aXZpdHlTdWJDb250ZXh0KGNvbnRleHRBY3Rpdml0aWVzLm90aGVyLCB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuT1RIRVIpLCBsb2NhbEVycm9ycyk7XG5cbiAgdmFsaWRhdGVBYnNlbmNlT2ZOb25XaGl0ZWxpc3RlZFByb3BlcnRpZXMoY29udGV4dEFjdGl2aXRpZXMsIHhhcGlXaGl0ZUxpc3RQcm9wZXJ0aWVzLkNPTlRFWFRfQUNUSVZJVElFUywgbG9jYWxUcmFjZSwgbG9jYWxFcnJvcnMpO1xuXG4gIHJldHVybiBsb2NhbEVycm9ycztcbn1cblxuZnVuY3Rpb24gdmFsaWRhdGVDb250ZXh0KGNvbnRleHQsIHRyYWNlLCBlcnJvcnMsIHN0YXRlbWVudE9iamVjdE9iamVjdFR5cGUpIHtcbiAgdmFyIGxvY2FsRXJyb3JzLCBsb2NhbFRyYWNlO1xuXG4gIGxvY2FsRXJyb3JzID0gZXJyb3JzIHx8IFtdO1xuICBsb2NhbFRyYWNlID0gdHJhY2UgfHwgcHJvcGVydGllcy5DT05URVhUO1xuXG4gIGlmIChjb250ZXh0ID09PSB1bmRlZmluZWQpIHtyZXR1cm4gbG9jYWxFcnJvcnM7fVxuXG4gIGlmICgheGFwaVZhbGlkYXRpb25VdGlscy5pc05vbk51bGxNYXBPYmplY3QoY29udGV4dCkpIHtcbiAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgIHRyYWNlOiAgIGxvY2FsVHJhY2UsXG4gICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5DT05URVhUX01VU1RfQkVfTk9OX05VTF9NQVBfT0JKRUNULFxuICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgfSk7XG5cbiAgICByZXR1cm4gbG9jYWxFcnJvcnM7XG4gIH1cblxuICBpZiAoY29udGV4dC5yZWdpc3RyYXRpb24gIT09IHVuZGVmaW5lZCAmJiAoY29udGV4dC5yZWdpc3RyYXRpb24gPT09IG51bGwgfHwgIXhhcGlWYWxpZGF0aW9uVXRpbHMuaXNTdHJpbmcoY29udGV4dC5yZWdpc3RyYXRpb24pIHx8ICF4YXBpVmFsaWRhdGlvblJlZ2V4LlVVSUQudGVzdChjb250ZXh0LnJlZ2lzdHJhdGlvbikpKSB7XG4gICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLlJFR0lTVFJBVElPTiksXG4gICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5SRUdJU1RSQVRJT05fTVVTVF9CRV9VVUlEX1NUUklORyxcbiAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgIH0pO1xuICB9XG5cbiAgaWYgKFtvYmplY3RUeXBlcy5HUk9VUCwgb2JqZWN0VHlwZXMuQUdFTlRdLmluZGV4T2Yoc3RhdGVtZW50T2JqZWN0T2JqZWN0VHlwZSkgIT09IHhhcGlHZW5lcmFsLk5PX0lOREVYX0ZPVU5EKSB7XG4gICAgaWYgKGNvbnRleHQucmV2aXNpb24gIT09IHVuZGVmaW5lZCkge1xuICAgICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMubG9jYWxUcmFjZVRvU3RyaW5nKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuUkVWSVNJT04pLFxuICAgICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5SRVZJU0lPTl9NVVNUX0JFX0FHRU5UX09SX0dST1VQLFxuICAgICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmIChjb250ZXh0LnBsYXRmb3JtICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLlBMQVRGT1JNKSxcbiAgICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuUExBVEZPUk1fTVVTVF9OT1RfQkVfVVNFRF9XSVRIX1JFVklTSU9OX0FHRU5UX09SX0dST1VQLFxuICAgICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIHZhbGlkYXRlUHJvcGVydHlJc1N0cmluZyhjb250ZXh0LCBwcm9wZXJ0aWVzLlJFVklTSU9OLCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycywgLyppc1JlcXVpcmVkKi9mYWxzZSwgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OKTtcbiAgdmFsaWRhdGVQcm9wZXJ0eUlzU3RyaW5nKGNvbnRleHQsIHByb3BlcnRpZXMuUExBVEZPUk0sIGxvY2FsVHJhY2UsIGxvY2FsRXJyb3JzLCAvKmlzUmVxdWlyZWQqL2ZhbHNlLCB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT04pO1xuXG4gIGlmIChjb250ZXh0LnRlYW0gIT09IHVuZGVmaW5lZCkge1xuICAgICAgdmFsaWRhdGVHcm91cChjb250ZXh0LnRlYW0sIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSwgcHJvcGVydGllcy5URUFNKSwgbG9jYWxFcnJvcnMpO1xuICB9XG5cbiAgaWYgKGNvbnRleHQuY29udGV4dEFjdGl2aXRpZXMgIT09IHVuZGVmaW5lZCkge1xuICAgIHZhbGlkYXRlQ29udGV4dEFjdGl2aXRpZXMoY29udGV4dC5jb250ZXh0QWN0aXZpdGllcywgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRQcm9wVG9UcmFjZShsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLkNPTlRFWFRfQUNUSVZJVElFUyksIGxvY2FsRXJyb3JzKTtcbiAgfVxuXG4gIGlmIChjb250ZXh0Lmxhbmd1YWdlICE9PSB1bmRlZmluZWQgJiYgIXhhcGlWYWxpZGF0aW9uVXRpbHMuaXNWYWxpZExhbmd1YWdlVGFnKGNvbnRleHQubGFuZ3VhZ2UsIHhhcGlWYWxpZGF0aW9uUmVnZXguQkNQXzQ3KSkge1xuICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSwgcHJvcGVydGllcy5MQU5HVUFHRSksXG4gICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5MQU5HVUFHRV9NVVNUX0JFX1NUUklORyxcbiAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgIH0pO1xuICB9XG5cbiAgaWYgKGNvbnRleHQuc3RhdGVtZW50ICE9PSB1bmRlZmluZWQpIHtcbiAgICB2YWxpZGF0ZVN0YXRlbWVudFJlZihjb250ZXh0LnN0YXRlbWVudCwgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRQcm9wVG9UcmFjZShsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLlNUQVRFTUVOVCksIGxvY2FsRXJyb3JzKTtcbiAgfVxuXG4gIGlmIChjb250ZXh0Lmluc3RydWN0b3IgIT09IHVuZGVmaW5lZCkge1xuICAgIGlmICh4YXBpVmFsaWRhdGlvblV0aWxzLmlzR3JvdXAoY29udGV4dC5pbnN0cnVjdG9yLCBvYmplY3RUeXBlcy5HUk9VUCkpIHtcbiAgICAgIHZhbGlkYXRlR3JvdXAoY29udGV4dC5pbnN0cnVjdG9yLCB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuSU5TVFJVQ1RPUiksIGxvY2FsRXJyb3JzKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdmFsaWRhdGVBZ2VudChjb250ZXh0Lmluc3RydWN0b3IsIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSwgcHJvcGVydGllcy5JTlNUUlVDVE9SKSwgbG9jYWxFcnJvcnMpO1xuICAgIH1cbiAgfVxuXG4gIHZhbGlkYXRlRXh0ZW5zaW9ucyhjb250ZXh0LmV4dGVuc2lvbnMsIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSwgcHJvcGVydGllcy5FWFRFTlNJT05TKSwgbG9jYWxFcnJvcnMpO1xuICB2YWxpZGF0ZUFic2VuY2VPZk5vbldoaXRlbGlzdGVkUHJvcGVydGllcyhjb250ZXh0LCB4YXBpV2hpdGVMaXN0UHJvcGVydGllcy5FWFRFTlNJT05TLGxvY2FsVHJhY2UsbG9jYWxFcnJvcnMpO1xuXG4gIHJldHVybiBsb2NhbEVycm9ycztcbn1cblxuZnVuY3Rpb24gdmFsaWRhdGVPYmplY3Qob2JqZWN0LCB0cmFjZSwgZXJyb3JzLCBpc1dpdGhpblN1YlN0YXRlbWVudCkge1xuICB2YXIgbG9jYWxFcnJvcnMsIGxvY2FsVHJhY2UsIG9iamVjdFR5cGU7XG5cbiAgbG9jYWxFcnJvcnMgPSBlcnJvcnMgfHwgW107XG4gIGxvY2FsVHJhY2UgID0gdHJhY2UgIHx8IHByb3BlcnRpZXMuT0JKRUNUO1xuXG4gIGlmIChvYmplY3QgPT09IHVuZGVmaW5lZCkge1xuICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSksXG4gICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5PQkpFQ1RfTVVTVF9CRV9ERUZJTkVELFxuICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgfSk7XG5cbiAgICByZXR1cm4gbG9jYWxFcnJvcnM7XG4gIH1cblxuICBpZiAoIXhhcGlWYWxpZGF0aW9uVXRpbHMuaXNOb25OdWxsTWFwT2JqZWN0KG9iamVjdCkpIHtcbiAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMubG9jYWxUcmFjZVRvU3RyaW5nKGxvY2FsVHJhY2UpLFxuICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuT0JKRUNUX01VU1RfQkVfTk9OX05VTExfTUFQX09CSkVDVCxcbiAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgIH0pO1xuXG4gICAgcmV0dXJuIGxvY2FsRXJyb3JzO1xuICB9XG5cbiAgdmFsaWRhdGVQcm9wZXJ0eUlzU3RyaW5nKG9iamVjdCwgcHJvcGVydGllcy5PQkpFQ1RfVFlQRSwgbG9jYWxUcmFjZSwgbG9jYWxFcnJvcnMsIC8qaXNSZXF1aXJlZCovdHJ1ZSwgeGFwaUVycm9yTGV2ZWxzLlNIT1VMRF9WSU9MQVRJT04pO1xuXG4gIG9iamVjdFR5cGUgPSBvYmplY3Qub2JqZWN0VHlwZSB8fCBvYmplY3RUeXBlcy5BQ1RJVklUWTtcblxuICBzd2l0Y2ggKG9iamVjdFR5cGUpIHtcbiAgICBjYXNlIG9iamVjdFR5cGVzLkFDVElWSVRZOlxuICAgICAgdmFsaWRhdGVBY3Rpdml0eShvYmplY3QsIGxvY2FsVHJhY2UsIGxvY2FsRXJyb3JzKTtcbiAgICAgIGJyZWFrO1xuICAgIGNhc2Ugb2JqZWN0VHlwZXMuQUdFTlQ6XG4gICAgICB2YWxpZGF0ZUFnZW50KG9iamVjdCwgbG9jYWxUcmFjZSwgbG9jYWxFcnJvcnMpO1xuICAgICAgYnJlYWs7XG4gICAgY2FzZSBvYmplY3RUeXBlcy5HUk9VUDpcbiAgICAgIHZhbGlkYXRlR3JvdXAob2JqZWN0LCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycyk7XG4gICAgICBicmVhaztcbiAgICBjYXNlIG9iamVjdFR5cGVzLlNUQVRFTUVOVF9SRUY6XG4gICAgICB2YWxpZGF0ZVN0YXRlbWVudFJlZihvYmplY3QsIGxvY2FsVHJhY2UsIGxvY2FsRXJyb3JzKTtcbiAgICAgIGJyZWFrO1xuICAgIGNhc2Ugb2JqZWN0VHlwZXMuU1VCX1NUQVRFTUVOVDpcbiAgICAgIGlmIChpc1dpdGhpblN1YlN0YXRlbWVudCkge1xuICAgICAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLk9CSkVDVF9UWVBFKSxcbiAgICAgICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5TVUJfU1RBVEVNRU5UX01VU1RfTk9UX0NPTlRBSU5fU1VCX1NUQVRFTUVOVCxcbiAgICAgICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgICB2YWxpZGF0ZShvYmplY3QsIGxvY2FsVHJhY2UsIGxvY2FsRXJyb3JzLCAgLyppc1N1YlN0YXRlbWVudCovdHJ1ZSk7XG4gICAgICBicmVhaztcbiAgICBkZWZhdWx0OlxuICAgICAgbG9jYWxFcnJvcnMucHVzaCh7XG4gICAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMubG9jYWxUcmFjZVRvU3RyaW5nKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuT0JKRUNUX1RZUEUpLFxuICAgICAgICBtZXNzYWdlOiBgJHt4YXBpVmFsaWRhdGlvbkVycm9ycy5PQkpFQ1RfVFlQRV9NVVNUX0JFX1ZBTElEX09QVElPTn0gJHt4QXBpVmFsaWRPYmplY3RUeXBlcy50b1N0cmluZygpfWAsXG4gICAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgICAgfSk7XG4gIH1cblxuICByZXR1cm4gbG9jYWxFcnJvcnM7XG59XG5cbmZ1bmN0aW9uIHZhbGlkYXRlKHN0YXRlbWVudCwgdHJhY2UsIGVycm9ycywgaXNTdWJTdGF0ZW1lbnQpIHtcbiAgdmFyIGxvY2FsRXJyb3JzLCBsb2NhbFRyYWNlLCBzdGF0ZW1lbnRPYmplY3RPYmplY3RUeXBlLCB3aGl0ZWxpc3RlZFByb3BlcnRpZXM7XG5cbiAgbG9jYWxFcnJvcnMgPSBlcnJvcnMgfHwgW107XG4gIGxvY2FsVHJhY2UgID0gdHJhY2UgIHx8IHByb3BlcnRpZXMuU1RBVEVNRU5UO1xuXG4gIHdoaXRlbGlzdGVkUHJvcGVydGllcyA9IHhhcGlXaGl0ZUxpc3RQcm9wZXJ0aWVzLlNUQVRFTUVOVDtcblxuICBpZiAoIXhhcGlWYWxpZGF0aW9uVXRpbHMuaXNOb25OdWxsTWFwT2JqZWN0KHN0YXRlbWVudCkpIHtcbiAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgIHRyYWNlOiAgIHhhcGlWYWxpZGF0aW9uVXRpbHMubG9jYWxUcmFjZVRvU3RyaW5nKGxvY2FsVHJhY2UpLFxuICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuU1RBVEVNRU5UX1JFRl9NVVNUX05PVF9CRV9OVUxMX01BUF9PQkpFQ1RTLFxuICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgfSk7XG5cbiAgICByZXR1cm4gbG9jYWxFcnJvcnM7XG4gIH1cblxuICBpZiAoIWlzU3ViU3RhdGVtZW50KSB7XG4gICAgaWYgKHN0YXRlbWVudC5pZCA9PT0gbnVsbCB8fCBzdGF0ZW1lbnQuaWQgPT09IHVuZGVmaW5lZCB8fCAheGFwaVZhbGlkYXRpb25VdGlscy5pc1N0cmluZyhzdGF0ZW1lbnQuaWQpKSB7XG4gICAgICBsb2NhbEVycm9ycy5wdXNoKHtcbiAgICAgICAgdHJhY2U6ICAgeGFwaVZhbGlkYXRpb25VdGlscy5sb2NhbFRyYWNlVG9TdHJpbmcobG9jYWxUcmFjZSwgcHJvcGVydGllcy5JRCksXG4gICAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLklEU19TSE9VTERfQkVfR0VORVJBVEVEX0JZX0xSUyxcbiAgICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLlNIT1VMRF9WSU9MQVRJT05cbiAgICAgIH0pO1xuICAgIH0gZWxzZSBpZiAoIXhhcGlWYWxpZGF0aW9uUmVnZXguVVVJRC50ZXN0KHN0YXRlbWVudC5pZCkpIHtcbiAgICAgIGxvY2FsRXJyb3JzLnB1c2goe1xuICAgICAgICB0cmFjZTogICB4YXBpVmFsaWRhdGlvblV0aWxzLmxvY2FsVHJhY2VUb1N0cmluZyhsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLklEKSxcbiAgICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuSURfTVVTVF9CRV9WQUxJRCxcbiAgICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgICB9KTtcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgd2hpdGVsaXN0ZWRQcm9wZXJ0aWVzID0geGFwaVdoaXRlTGlzdFByb3BlcnRpZXMuU1VCX1NUQVRFTUVOVDtcbiAgfVxuXG4gIHZhbGlkYXRlQWN0b3Ioc3RhdGVtZW50LmFjdG9yLCB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuQUNUT1IpLCBsb2NhbEVycm9ycyk7XG4gIHZhbGlkYXRlVmVyYihzdGF0ZW1lbnQudmVyYiwgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRQcm9wVG9UcmFjZShsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLlZFUkIpLCBsb2NhbEVycm9ycyk7XG4gIHZhbGlkYXRlT2JqZWN0KHN0YXRlbWVudC5vYmplY3QsIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSwgcHJvcGVydGllcy5PQkpFQ1QpLCBsb2NhbEVycm9ycywgaXNTdWJTdGF0ZW1lbnQpO1xuICB2YWxpZGF0ZVJlc3VsdChzdGF0ZW1lbnQucmVzdWx0LCB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuUkVTVUxUKSwgbG9jYWxFcnJvcnMpO1xuXG4gIHN0YXRlbWVudE9iamVjdE9iamVjdFR5cGUgPSBzdGF0ZW1lbnQub2JqZWN0ICYmIHN0YXRlbWVudC5vYmplY3Qub2JqZWN0VHlwZSA/IHN0YXRlbWVudC5vYmplY3Qub2JqZWN0VHlwZSA6IG9iamVjdFR5cGVzLkFDVElWSVRZO1xuXG4gIHZhbGlkYXRlQ29udGV4dChzdGF0ZW1lbnQuY29udGV4dCwgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRQcm9wVG9UcmFjZShsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLkNPTlRFWFQpLCBsb2NhbEVycm9ycywgc3RhdGVtZW50T2JqZWN0T2JqZWN0VHlwZSk7XG4gIHZhbGlkYXRlUHJvcGVydHlJc0lTTzg2MDFTdHJpbmcoc3RhdGVtZW50LCBwcm9wZXJ0aWVzLlRJTUVTVEFNUCwgbG9jYWxUcmFjZSwgbG9jYWxFcnJvcnMpO1xuICB2YWxpZGF0ZVByb3BlcnR5SXNJU084NjAxU3RyaW5nKHN0YXRlbWVudCwgcHJvcGVydGllcy5TVE9SRUQsIGxvY2FsVHJhY2UsIGxvY2FsRXJyb3JzKTtcblxuICB2YWxpZGF0ZUF1dGhvcml0eShzdGF0ZW1lbnQuYXV0aG9yaXR5LCB4YXBpVmFsaWRhdGlvblV0aWxzLmFkZFByb3BUb1RyYWNlKGxvY2FsVHJhY2UsIHByb3BlcnRpZXMuQVVUSE9SSVRZKSwgbG9jYWxFcnJvcnMpO1xuICB2YWxpZGF0ZVZlcnNpb24oc3RhdGVtZW50LnZlcnNpb24sIHhhcGlWYWxpZGF0aW9uVXRpbHMuYWRkUHJvcFRvVHJhY2UobG9jYWxUcmFjZSwgcHJvcGVydGllcy5WRVJTSU9OKSwgbG9jYWxFcnJvcnMpO1xuICB2YWxpZGF0ZUF0dGFjaG1lbnRzKHN0YXRlbWVudC5hdHRhY2htZW50cywgeGFwaVZhbGlkYXRpb25VdGlscy5hZGRQcm9wVG9UcmFjZShsb2NhbFRyYWNlLCBwcm9wZXJ0aWVzLkFUVEFDSE1FTlRTKSwgbG9jYWxFcnJvcnMpO1xuXG4gIHZhbGlkYXRlQWJzZW5jZU9mTm9uV2hpdGVsaXN0ZWRQcm9wZXJ0aWVzKHN0YXRlbWVudCwgd2hpdGVsaXN0ZWRQcm9wZXJ0aWVzLCBsb2NhbFRyYWNlLCBsb2NhbEVycm9ycyk7XG5cbiAgcmV0dXJuIGxvY2FsRXJyb3JzO1xufVxuXG5mdW5jdGlvbiBtYWtlU3RhdGVtZW50UmVwb3J0KHN0YXRlbWVudCkge1xuICB2YXIgbG9jYWxFcnJvcnM7XG5cbiAgbG9jYWxFcnJvcnMgPSBbXTtcbiAgdmFsaWRhdGUoc3RhdGVtZW50LCBwcm9wZXJ0aWVzLlNUQVRFTUVOVCwgbG9jYWxFcnJvcnMsICAvKmlzUmVxdWlyZWQqL2ZhbHNlKTtcblxuICByZXR1cm4gbWFrZVYxUmVwb3J0KHN0YXRlbWVudCwgbG9jYWxFcnJvcnMpO1xufVxuXG5mdW5jdGlvbiB2YWxpZGF0ZUFtYmlndW91c1R5cGVTdGF0ZW1lbnQoc3RhdGVtZW50KSB7XG4gIHZhciBzdGF0ZW1lbnRPYmplY3Q7XG5cbiAgaWYgKHN0YXRlbWVudCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgcmV0dXJuIG1ha2VWMVNpbmdsZUVycm9yUmVwb3J0KC8qaW5zdGFuY2UqL251bGwsIHtcbiAgICAgIHRyYWNlOiAgIHByb3BlcnRpZXMuU1RBVEVNRU5ULFxuICAgICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuU1RBVEVNRU5UX0FSR1VNRU5UX01VU1RfQkVfUFJPVklERUQsXG4gICAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgICB9KTtcbiAgfVxuXG4gIGlmIChzdGF0ZW1lbnQgPT09IG51bGwpIHtcbiAgICByZXR1cm4gbWFrZVYxU2luZ2xlRXJyb3JSZXBvcnQoLyppbnN0YW5jZSovbnVsbCwge1xuICAgICAgdHJhY2U6ICAgcHJvcGVydGllcy5TVEFURU1FTlQsXG4gICAgICBtZXNzYWdlOiB4YXBpVmFsaWRhdGlvbkVycm9ycy5TVEFURU1FTlRfTVVTVF9OT1RfQkVfTlVMTCxcbiAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgIH0pO1xuICB9XG5cbiAgaWYgKHhhcGlWYWxpZGF0aW9uVXRpbHMuaXNTdHJpbmcoc3RhdGVtZW50KSkge1xuICAgIHRyeSB7XG4gICAgICBzdGF0ZW1lbnRPYmplY3QgPSBKU09OLnBhcnNlKHN0YXRlbWVudCk7XG4gICAgICBpZiAoc3RhdGVtZW50T2JqZWN0ID09PSBudWxsIHx8ICF4YXBpVmFsaWRhdGlvblV0aWxzLmlzT2JqZWN0KHN0YXRlbWVudE9iamVjdCkgfHwgeGFwaVZhbGlkYXRpb25VdGlscy5pc0FycmF5KHN0YXRlbWVudE9iamVjdCkpIHtcbiAgICAgICAgcmV0dXJuIG1ha2VWMVNpbmdsZUVycm9yUmVwb3J0KHN0YXRlbWVudE9iamVjdCwge1xuICAgICAgICAgIHRyYWNlOiAgIHByb3BlcnRpZXMuU1RBVEVNRU5ULFxuICAgICAgICAgIG1lc3NhZ2U6IHhhcGlWYWxpZGF0aW9uRXJyb3JzLlNUQVRFTUVOVF9NVVNUX0JFX1BBUlNFRF9DT1JSRUNUTFksXG4gICAgICAgICAgbGV2ZWw6ICAgeGFwaUVycm9yTGV2ZWxzLk1VU1RfVklPTEFUSU9OXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHJldHVybiBtYWtlVjFTaW5nbGVFcnJvclJlcG9ydChzdGF0ZW1lbnRPYmplY3QsIHtcbiAgICAgICAgdHJhY2U6ICAgcHJvcGVydGllcy5TVEFURU1FTlQsXG4gICAgICAgIG1lc3NhZ2U6IGAke3hhcGlWYWxpZGF0aW9uRXJyb3JzLklOVkFMSURfSlNPTn06ICR7ZS5tZXNzYWdlfWAsXG4gICAgICAgIGxldmVsOiAgIHhhcGlFcnJvckxldmVscy5NVVNUX1ZJT0xBVElPTlxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIG1ha2VTdGF0ZW1lbnRSZXBvcnQoc3RhdGVtZW50T2JqZWN0KTtcbiAgfVxuXG4gIGlmICh4YXBpVmFsaWRhdGlvblV0aWxzLmlzT2JqZWN0KHN0YXRlbWVudCkgJiYgIXhhcGlWYWxpZGF0aW9uVXRpbHMuaXNBcnJheShzdGF0ZW1lbnQpKSB7XG4gICAgcmV0dXJuIG1ha2VTdGF0ZW1lbnRSZXBvcnQoc3RhdGVtZW50KTtcbiAgfVxuXG4gIHJldHVybiBtYWtlVjFTaW5nbGVFcnJvclJlcG9ydCgvKmluc3RhbmNlKi9udWxsLCB7XG4gICAgdHJhY2U6ICAgcHJvcGVydGllcy5TVEFURU1FTlQsXG4gICAgbWVzc2FnZTogeGFwaVZhbGlkYXRpb25FcnJvcnMuU1RBVEVNRU5UX0FSR1VNRU5UX0lTX05PVF9WQUxJRCxcbiAgICBsZXZlbDogICB4YXBpRXJyb3JMZXZlbHMuTVVTVF9WSU9MQVRJT05cbiAgfSk7XG59XG5cbmZ1bmN0aW9uIGRhdGVJbmNsdWRlc1pvbmVJbmZvcm1hdGlvbihtYXRjaGVkKSB7XG4gIHJldHVybiBtYXRjaGVkW2RhdGVGb3JtYXRSZWdleFBvc2l0aW9ucy5aT05FXSB8fFxuICAgICAgICAgIChtYXRjaGVkW2RhdGVGb3JtYXRSZWdleFBvc2l0aW9ucy5SRUxBVElWRV9USU1FXSAmJiBtYXRjaGVkW2RhdGVGb3JtYXRSZWdleFBvc2l0aW9ucy5USU1FX1pPTkVfSE9VUl0pO1xufVxuXG54YXBpVmFsaWRhdGlvbiA9IHtcbiAgdmFsaWRhdGVTdGF0ZW1lbnQ6IHZhbGlkYXRlQW1iaWd1b3VzVHlwZVN0YXRlbWVudFxufTtcblxubW9kdWxlLmV4cG9ydHMgPSB4YXBpVmFsaWRhdGlvbjtcbiJdfQ==