9012 lines
745 KiB
JavaScript
9012 lines
745 KiB
JavaScript
;(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);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
|
// shim for using process in browser
|
|
|
|
var process = module.exports = {};
|
|
|
|
process.nextTick = (function () {
|
|
var canSetImmediate = typeof window !== 'undefined'
|
|
&& window.setImmediate;
|
|
var canPost = typeof window !== 'undefined'
|
|
&& window.postMessage && window.addEventListener
|
|
;
|
|
|
|
if (canSetImmediate) {
|
|
return function (f) { return window.setImmediate(f) };
|
|
}
|
|
|
|
if (canPost) {
|
|
var queue = [];
|
|
window.addEventListener('message', function (ev) {
|
|
if (ev.source === window && ev.data === 'process-tick') {
|
|
ev.stopPropagation();
|
|
if (queue.length > 0) {
|
|
var fn = queue.shift();
|
|
fn();
|
|
}
|
|
}
|
|
}, true);
|
|
|
|
return function nextTick(fn) {
|
|
queue.push(fn);
|
|
window.postMessage('process-tick', '*');
|
|
};
|
|
}
|
|
|
|
return function nextTick(fn) {
|
|
setTimeout(fn, 0);
|
|
};
|
|
})();
|
|
|
|
process.title = 'browser';
|
|
process.browser = true;
|
|
process.env = {};
|
|
process.argv = [];
|
|
|
|
process.binding = function (name) {
|
|
throw new Error('process.binding is not supported');
|
|
}
|
|
|
|
// TODO(shtylman)
|
|
process.cwd = function () { return '/' };
|
|
process.chdir = function (dir) {
|
|
throw new Error('process.chdir is not supported');
|
|
};
|
|
|
|
},{}],2:[function(require,module,exports){
|
|
var global=self;/**
|
|
* @license
|
|
* Lo-Dash 1.3.1 (Custom Build) <http://lodash.com/>
|
|
* Build: `lodash modern -o ./dist/lodash.js`
|
|
* Copyright 2012-2013 The Dojo Foundation <http://dojofoundation.org/>
|
|
* Based on Underscore.js 1.4.4 <http://underscorejs.org/>
|
|
* Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud Inc.
|
|
* Available under MIT license <http://lodash.com/license>
|
|
*/
|
|
;(function(window) {
|
|
|
|
/** Used as a safe reference for `undefined` in pre ES5 environments */
|
|
var undefined;
|
|
|
|
/** Used to pool arrays and objects used internally */
|
|
var arrayPool = [],
|
|
objectPool = [];
|
|
|
|
/** Used to generate unique IDs */
|
|
var idCounter = 0;
|
|
|
|
/** Used internally to indicate various things */
|
|
var indicatorObject = {};
|
|
|
|
/** Used to prefix keys to avoid issues with `__proto__` and properties on `Object.prototype` */
|
|
var keyPrefix = +new Date + '';
|
|
|
|
/** Used as the size when optimizations are enabled for large arrays */
|
|
var largeArraySize = 75;
|
|
|
|
/** Used as the max size of the `arrayPool` and `objectPool` */
|
|
var maxPoolSize = 40;
|
|
|
|
/** Used to match empty string literals in compiled template source */
|
|
var reEmptyStringLeading = /\b__p \+= '';/g,
|
|
reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
|
|
reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
|
|
|
|
/** Used to match HTML entities */
|
|
var reEscapedHtml = /&(?:amp|lt|gt|quot|#39);/g;
|
|
|
|
/**
|
|
* Used to match ES6 template delimiters
|
|
* http://people.mozilla.org/~jorendorff/es6-draft.html#sec-7.8.6
|
|
*/
|
|
var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
|
|
|
|
/** Used to match regexp flags from their coerced string values */
|
|
var reFlags = /\w*$/;
|
|
|
|
/** Used to match "interpolate" template delimiters */
|
|
var reInterpolate = /<%=([\s\S]+?)%>/g;
|
|
|
|
/** Used to detect functions containing a `this` reference */
|
|
var reThis = (reThis = /\bthis\b/) && reThis.test(runInContext) && reThis;
|
|
|
|
/** Used to detect and test whitespace */
|
|
var whitespace = (
|
|
// whitespace
|
|
' \t\x0B\f\xA0\ufeff' +
|
|
|
|
// line terminators
|
|
'\n\r\u2028\u2029' +
|
|
|
|
// unicode category "Zs" space separators
|
|
'\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000'
|
|
);
|
|
|
|
/** Used to match leading whitespace and zeros to be removed */
|
|
var reLeadingSpacesAndZeros = RegExp('^[' + whitespace + ']*0+(?=.$)');
|
|
|
|
/** Used to ensure capturing order of template delimiters */
|
|
var reNoMatch = /($^)/;
|
|
|
|
/** Used to match HTML characters */
|
|
var reUnescapedHtml = /[&<>"']/g;
|
|
|
|
/** Used to match unescaped characters in compiled string literals */
|
|
var reUnescapedString = /['\n\r\t\u2028\u2029\\]/g;
|
|
|
|
/** Used to assign default `context` object properties */
|
|
var contextProps = [
|
|
'Array', 'Boolean', 'Date', 'Function', 'Math', 'Number', 'Object',
|
|
'RegExp', 'String', '_', 'attachEvent', 'clearTimeout', 'isFinite', 'isNaN',
|
|
'parseInt', 'setImmediate', 'setTimeout'
|
|
];
|
|
|
|
/** Used to make template sourceURLs easier to identify */
|
|
var templateCounter = 0;
|
|
|
|
/** `Object#toString` result shortcuts */
|
|
var argsClass = '[object Arguments]',
|
|
arrayClass = '[object Array]',
|
|
boolClass = '[object Boolean]',
|
|
dateClass = '[object Date]',
|
|
errorClass = '[object Error]',
|
|
funcClass = '[object Function]',
|
|
numberClass = '[object Number]',
|
|
objectClass = '[object Object]',
|
|
regexpClass = '[object RegExp]',
|
|
stringClass = '[object String]';
|
|
|
|
/** Used to identify object classifications that `_.clone` supports */
|
|
var cloneableClasses = {};
|
|
cloneableClasses[funcClass] = false;
|
|
cloneableClasses[argsClass] = cloneableClasses[arrayClass] =
|
|
cloneableClasses[boolClass] = cloneableClasses[dateClass] =
|
|
cloneableClasses[numberClass] = cloneableClasses[objectClass] =
|
|
cloneableClasses[regexpClass] = cloneableClasses[stringClass] = true;
|
|
|
|
/** Used to determine if values are of the language type Object */
|
|
var objectTypes = {
|
|
'boolean': false,
|
|
'function': true,
|
|
'object': true,
|
|
'number': false,
|
|
'string': false,
|
|
'undefined': false
|
|
};
|
|
|
|
/** Used to escape characters for inclusion in compiled string literals */
|
|
var stringEscapes = {
|
|
'\\': '\\',
|
|
"'": "'",
|
|
'\n': 'n',
|
|
'\r': 'r',
|
|
'\t': 't',
|
|
'\u2028': 'u2028',
|
|
'\u2029': 'u2029'
|
|
};
|
|
|
|
/** Detect free variable `exports` */
|
|
var freeExports = objectTypes[typeof exports] && exports;
|
|
|
|
/** Detect free variable `module` */
|
|
var freeModule = objectTypes[typeof module] && module && module.exports == freeExports && module;
|
|
|
|
/** Detect free variable `global`, from Node.js or Browserified code, and use it as `window` */
|
|
var freeGlobal = objectTypes[typeof global] && global;
|
|
if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal)) {
|
|
window = freeGlobal;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* A basic implementation of `_.indexOf` without support for binary searches
|
|
* or `fromIndex` constraints.
|
|
*
|
|
* @private
|
|
* @param {Array} array The array to search.
|
|
* @param {Mixed} value The value to search for.
|
|
* @param {Number} [fromIndex=0] The index to search from.
|
|
* @returns {Number} Returns the index of the matched value or `-1`.
|
|
*/
|
|
function basicIndexOf(array, value, fromIndex) {
|
|
var index = (fromIndex || 0) - 1,
|
|
length = array.length;
|
|
|
|
while (++index < length) {
|
|
if (array[index] === value) {
|
|
return index;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* An implementation of `_.contains` for cache objects that mimics the return
|
|
* signature of `_.indexOf` by returning `0` if the value is found, else `-1`.
|
|
*
|
|
* @private
|
|
* @param {Object} cache The cache object to inspect.
|
|
* @param {Mixed} value The value to search for.
|
|
* @returns {Number} Returns `0` if `value` is found, else `-1`.
|
|
*/
|
|
function cacheIndexOf(cache, value) {
|
|
var type = typeof value;
|
|
cache = cache.cache;
|
|
|
|
if (type == 'boolean' || value == null) {
|
|
return cache[value];
|
|
}
|
|
if (type != 'number' && type != 'string') {
|
|
type = 'object';
|
|
}
|
|
var key = type == 'number' ? value : keyPrefix + value;
|
|
cache = cache[type] || (cache[type] = {});
|
|
|
|
return type == 'object'
|
|
? (cache[key] && basicIndexOf(cache[key], value) > -1 ? 0 : -1)
|
|
: (cache[key] ? 0 : -1);
|
|
}
|
|
|
|
/**
|
|
* Adds a given `value` to the corresponding cache object.
|
|
*
|
|
* @private
|
|
* @param {Mixed} value The value to add to the cache.
|
|
*/
|
|
function cachePush(value) {
|
|
var cache = this.cache,
|
|
type = typeof value;
|
|
|
|
if (type == 'boolean' || value == null) {
|
|
cache[value] = true;
|
|
} else {
|
|
if (type != 'number' && type != 'string') {
|
|
type = 'object';
|
|
}
|
|
var key = type == 'number' ? value : keyPrefix + value,
|
|
typeCache = cache[type] || (cache[type] = {});
|
|
|
|
if (type == 'object') {
|
|
if ((typeCache[key] || (typeCache[key] = [])).push(value) == this.array.length) {
|
|
cache[type] = false;
|
|
}
|
|
} else {
|
|
typeCache[key] = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Used by `_.max` and `_.min` as the default `callback` when a given
|
|
* `collection` is a string value.
|
|
*
|
|
* @private
|
|
* @param {String} value The character to inspect.
|
|
* @returns {Number} Returns the code unit of given character.
|
|
*/
|
|
function charAtCallback(value) {
|
|
return value.charCodeAt(0);
|
|
}
|
|
|
|
/**
|
|
* Used by `sortBy` to compare transformed `collection` values, stable sorting
|
|
* them in ascending order.
|
|
*
|
|
* @private
|
|
* @param {Object} a The object to compare to `b`.
|
|
* @param {Object} b The object to compare to `a`.
|
|
* @returns {Number} Returns the sort order indicator of `1` or `-1`.
|
|
*/
|
|
function compareAscending(a, b) {
|
|
var ai = a.index,
|
|
bi = b.index;
|
|
|
|
a = a.criteria;
|
|
b = b.criteria;
|
|
|
|
// ensure a stable sort in V8 and other engines
|
|
// http://code.google.com/p/v8/issues/detail?id=90
|
|
if (a !== b) {
|
|
if (a > b || typeof a == 'undefined') {
|
|
return 1;
|
|
}
|
|
if (a < b || typeof b == 'undefined') {
|
|
return -1;
|
|
}
|
|
}
|
|
return ai < bi ? -1 : 1;
|
|
}
|
|
|
|
/**
|
|
* Creates a cache object to optimize linear searches of large arrays.
|
|
*
|
|
* @private
|
|
* @param {Array} [array=[]] The array to search.
|
|
* @returns {Null|Object} Returns the cache object or `null` if caching should not be used.
|
|
*/
|
|
function createCache(array) {
|
|
var index = -1,
|
|
length = array.length;
|
|
|
|
var cache = getObject();
|
|
cache['false'] = cache['null'] = cache['true'] = cache['undefined'] = false;
|
|
|
|
var result = getObject();
|
|
result.array = array;
|
|
result.cache = cache;
|
|
result.push = cachePush;
|
|
|
|
while (++index < length) {
|
|
result.push(array[index]);
|
|
}
|
|
return cache.object === false
|
|
? (releaseObject(result), null)
|
|
: result;
|
|
}
|
|
|
|
/**
|
|
* Used by `template` to escape characters for inclusion in compiled
|
|
* string literals.
|
|
*
|
|
* @private
|
|
* @param {String} match The matched character to escape.
|
|
* @returns {String} Returns the escaped character.
|
|
*/
|
|
function escapeStringChar(match) {
|
|
return '\\' + stringEscapes[match];
|
|
}
|
|
|
|
/**
|
|
* Gets an array from the array pool or creates a new one if the pool is empty.
|
|
*
|
|
* @private
|
|
* @returns {Array} The array from the pool.
|
|
*/
|
|
function getArray() {
|
|
return arrayPool.pop() || [];
|
|
}
|
|
|
|
/**
|
|
* Gets an object from the object pool or creates a new one if the pool is empty.
|
|
*
|
|
* @private
|
|
* @returns {Object} The object from the pool.
|
|
*/
|
|
function getObject() {
|
|
return objectPool.pop() || {
|
|
'array': null,
|
|
'cache': null,
|
|
'criteria': null,
|
|
'false': false,
|
|
'index': 0,
|
|
'leading': false,
|
|
'maxWait': 0,
|
|
'null': false,
|
|
'number': null,
|
|
'object': null,
|
|
'push': null,
|
|
'string': null,
|
|
'trailing': false,
|
|
'true': false,
|
|
'undefined': false,
|
|
'value': null
|
|
};
|
|
}
|
|
|
|
/**
|
|
* A no-operation function.
|
|
*
|
|
* @private
|
|
*/
|
|
function noop() {
|
|
// no operation performed
|
|
}
|
|
|
|
/**
|
|
* Releases the given `array` back to the array pool.
|
|
*
|
|
* @private
|
|
* @param {Array} [array] The array to release.
|
|
*/
|
|
function releaseArray(array) {
|
|
array.length = 0;
|
|
if (arrayPool.length < maxPoolSize) {
|
|
arrayPool.push(array);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Releases the given `object` back to the object pool.
|
|
*
|
|
* @private
|
|
* @param {Object} [object] The object to release.
|
|
*/
|
|
function releaseObject(object) {
|
|
var cache = object.cache;
|
|
if (cache) {
|
|
releaseObject(cache);
|
|
}
|
|
object.array = object.cache = object.criteria = object.object = object.number = object.string = object.value = null;
|
|
if (objectPool.length < maxPoolSize) {
|
|
objectPool.push(object);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Slices the `collection` from the `start` index up to, but not including,
|
|
* the `end` index.
|
|
*
|
|
* Note: This function is used, instead of `Array#slice`, to support node lists
|
|
* in IE < 9 and to ensure dense arrays are returned.
|
|
*
|
|
* @private
|
|
* @param {Array|Object|String} collection The collection to slice.
|
|
* @param {Number} start The start index.
|
|
* @param {Number} end The end index.
|
|
* @returns {Array} Returns the new array.
|
|
*/
|
|
function slice(array, start, end) {
|
|
start || (start = 0);
|
|
if (typeof end == 'undefined') {
|
|
end = array ? array.length : 0;
|
|
}
|
|
var index = -1,
|
|
length = end - start || 0,
|
|
result = Array(length < 0 ? 0 : length);
|
|
|
|
while (++index < length) {
|
|
result[index] = array[start + index];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Create a new `lodash` function using the given `context` object.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @param {Object} [context=window] The context object.
|
|
* @returns {Function} Returns the `lodash` function.
|
|
*/
|
|
function runInContext(context) {
|
|
// Avoid issues with some ES3 environments that attempt to use values, named
|
|
// after built-in constructors like `Object`, for the creation of literals.
|
|
// ES5 clears this up by stating that literals must use built-in constructors.
|
|
// See http://es5.github.com/#x11.1.5.
|
|
context = context ? _.defaults(window.Object(), context, _.pick(window, contextProps)) : window;
|
|
|
|
/** Native constructor references */
|
|
var Array = context.Array,
|
|
Boolean = context.Boolean,
|
|
Date = context.Date,
|
|
Function = context.Function,
|
|
Math = context.Math,
|
|
Number = context.Number,
|
|
Object = context.Object,
|
|
RegExp = context.RegExp,
|
|
String = context.String,
|
|
TypeError = context.TypeError;
|
|
|
|
/**
|
|
* Used for `Array` method references.
|
|
*
|
|
* Normally `Array.prototype` would suffice, however, using an array literal
|
|
* avoids issues in Narwhal.
|
|
*/
|
|
var arrayRef = [];
|
|
|
|
/** Used for native method references */
|
|
var objectProto = Object.prototype,
|
|
stringProto = String.prototype;
|
|
|
|
/** Used to restore the original `_` reference in `noConflict` */
|
|
var oldDash = context._;
|
|
|
|
/** Used to detect if a method is native */
|
|
var reNative = RegExp('^' +
|
|
String(objectProto.valueOf)
|
|
.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
.replace(/valueOf|for [^\]]+/g, '.+?') + '$'
|
|
);
|
|
|
|
/** Native method shortcuts */
|
|
var ceil = Math.ceil,
|
|
clearTimeout = context.clearTimeout,
|
|
concat = arrayRef.concat,
|
|
floor = Math.floor,
|
|
fnToString = Function.prototype.toString,
|
|
getPrototypeOf = reNative.test(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf,
|
|
hasOwnProperty = objectProto.hasOwnProperty,
|
|
push = arrayRef.push,
|
|
propertyIsEnumerable = objectProto.propertyIsEnumerable,
|
|
setImmediate = context.setImmediate,
|
|
setTimeout = context.setTimeout,
|
|
toString = objectProto.toString;
|
|
|
|
/* Native method shortcuts for methods with the same name as other `lodash` methods */
|
|
var nativeBind = reNative.test(nativeBind = toString.bind) && nativeBind,
|
|
nativeCreate = reNative.test(nativeCreate = Object.create) && nativeCreate,
|
|
nativeIsArray = reNative.test(nativeIsArray = Array.isArray) && nativeIsArray,
|
|
nativeIsFinite = context.isFinite,
|
|
nativeIsNaN = context.isNaN,
|
|
nativeKeys = reNative.test(nativeKeys = Object.keys) && nativeKeys,
|
|
nativeMax = Math.max,
|
|
nativeMin = Math.min,
|
|
nativeParseInt = context.parseInt,
|
|
nativeRandom = Math.random,
|
|
nativeSlice = arrayRef.slice;
|
|
|
|
/** Detect various environments */
|
|
var isIeOpera = reNative.test(context.attachEvent),
|
|
isV8 = nativeBind && !/\n|true/.test(nativeBind + isIeOpera);
|
|
|
|
/** Used to lookup a built-in constructor by [[Class]] */
|
|
var ctorByClass = {};
|
|
ctorByClass[arrayClass] = Array;
|
|
ctorByClass[boolClass] = Boolean;
|
|
ctorByClass[dateClass] = Date;
|
|
ctorByClass[funcClass] = Function;
|
|
ctorByClass[objectClass] = Object;
|
|
ctorByClass[numberClass] = Number;
|
|
ctorByClass[regexpClass] = RegExp;
|
|
ctorByClass[stringClass] = String;
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Creates a `lodash` object, which wraps the given `value`, to enable method
|
|
* chaining.
|
|
*
|
|
* In addition to Lo-Dash methods, wrappers also have the following `Array` methods:
|
|
* `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, `splice`,
|
|
* and `unshift`
|
|
*
|
|
* Chaining is supported in custom builds as long as the `value` method is
|
|
* implicitly or explicitly included in the build.
|
|
*
|
|
* The chainable wrapper functions are:
|
|
* `after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`,
|
|
* `compose`, `concat`, `countBy`, `createCallback`, `debounce`, `defaults`,
|
|
* `defer`, `delay`, `difference`, `filter`, `flatten`, `forEach`, `forIn`,
|
|
* `forOwn`, `functions`, `groupBy`, `initial`, `intersection`, `invert`,
|
|
* `invoke`, `keys`, `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`,
|
|
* `once`, `pairs`, `partial`, `partialRight`, `pick`, `pluck`, `push`, `range`,
|
|
* `reject`, `rest`, `reverse`, `shuffle`, `slice`, `sort`, `sortBy`, `splice`,
|
|
* `tap`, `throttle`, `times`, `toArray`, `transform`, `union`, `uniq`, `unshift`,
|
|
* `unzip`, `values`, `where`, `without`, `wrap`, and `zip`
|
|
*
|
|
* The non-chainable wrapper functions are:
|
|
* `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `has`,
|
|
* `identity`, `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`,
|
|
* `isElement`, `isEmpty`, `isEqual`, `isFinite`, `isFunction`, `isNaN`,
|
|
* `isNull`, `isNumber`, `isObject`, `isPlainObject`, `isRegExp`, `isString`,
|
|
* `isUndefined`, `join`, `lastIndexOf`, `mixin`, `noConflict`, `parseInt`,
|
|
* `pop`, `random`, `reduce`, `reduceRight`, `result`, `shift`, `size`, `some`,
|
|
* `sortedIndex`, `runInContext`, `template`, `unescape`, `uniqueId`, and `value`
|
|
*
|
|
* The wrapper functions `first` and `last` return wrapped values when `n` is
|
|
* passed, otherwise they return unwrapped values.
|
|
*
|
|
* @name _
|
|
* @constructor
|
|
* @alias chain
|
|
* @category Chaining
|
|
* @param {Mixed} value The value to wrap in a `lodash` instance.
|
|
* @returns {Object} Returns a `lodash` instance.
|
|
* @example
|
|
*
|
|
* var wrapped = _([1, 2, 3]);
|
|
*
|
|
* // returns an unwrapped value
|
|
* wrapped.reduce(function(sum, num) {
|
|
* return sum + num;
|
|
* });
|
|
* // => 6
|
|
*
|
|
* // returns a wrapped value
|
|
* var squares = wrapped.map(function(num) {
|
|
* return num * num;
|
|
* });
|
|
*
|
|
* _.isArray(squares);
|
|
* // => false
|
|
*
|
|
* _.isArray(squares.value());
|
|
* // => true
|
|
*/
|
|
function lodash(value) {
|
|
// don't wrap if already wrapped, even if wrapped by a different `lodash` constructor
|
|
return (value && typeof value == 'object' && !isArray(value) && hasOwnProperty.call(value, '__wrapped__'))
|
|
? value
|
|
: new lodashWrapper(value);
|
|
}
|
|
|
|
/**
|
|
* A fast path for creating `lodash` wrapper objects.
|
|
*
|
|
* @private
|
|
* @param {Mixed} value The value to wrap in a `lodash` instance.
|
|
* @returns {Object} Returns a `lodash` instance.
|
|
*/
|
|
function lodashWrapper(value) {
|
|
this.__wrapped__ = value;
|
|
}
|
|
// ensure `new lodashWrapper` is an instance of `lodash`
|
|
lodashWrapper.prototype = lodash.prototype;
|
|
|
|
/**
|
|
* An object used to flag environments features.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @type Object
|
|
*/
|
|
var support = lodash.support = {};
|
|
|
|
/**
|
|
* Detect if `Function#bind` exists and is inferred to be fast (all but V8).
|
|
*
|
|
* @memberOf _.support
|
|
* @type Boolean
|
|
*/
|
|
support.fastBind = nativeBind && !isV8;
|
|
|
|
/**
|
|
* By default, the template delimiters used by Lo-Dash are similar to those in
|
|
* embedded Ruby (ERB). Change the following template settings to use alternative
|
|
* delimiters.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @type Object
|
|
*/
|
|
lodash.templateSettings = {
|
|
|
|
/**
|
|
* Used to detect `data` property values to be HTML-escaped.
|
|
*
|
|
* @memberOf _.templateSettings
|
|
* @type RegExp
|
|
*/
|
|
'escape': /<%-([\s\S]+?)%>/g,
|
|
|
|
/**
|
|
* Used to detect code to be evaluated.
|
|
*
|
|
* @memberOf _.templateSettings
|
|
* @type RegExp
|
|
*/
|
|
'evaluate': /<%([\s\S]+?)%>/g,
|
|
|
|
/**
|
|
* Used to detect `data` property values to inject.
|
|
*
|
|
* @memberOf _.templateSettings
|
|
* @type RegExp
|
|
*/
|
|
'interpolate': reInterpolate,
|
|
|
|
/**
|
|
* Used to reference the data object in the template text.
|
|
*
|
|
* @memberOf _.templateSettings
|
|
* @type String
|
|
*/
|
|
'variable': '',
|
|
|
|
/**
|
|
* Used to import variables into the compiled template.
|
|
*
|
|
* @memberOf _.templateSettings
|
|
* @type Object
|
|
*/
|
|
'imports': {
|
|
|
|
/**
|
|
* A reference to the `lodash` function.
|
|
*
|
|
* @memberOf _.templateSettings.imports
|
|
* @type Function
|
|
*/
|
|
'_': lodash
|
|
}
|
|
};
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Creates a function that, when called, invokes `func` with the `this` binding
|
|
* of `thisArg` and prepends any `partialArgs` to the arguments passed to the
|
|
* bound function.
|
|
*
|
|
* @private
|
|
* @param {Function|String} func The function to bind or the method name.
|
|
* @param {Mixed} [thisArg] The `this` binding of `func`.
|
|
* @param {Array} partialArgs An array of arguments to be partially applied.
|
|
* @param {Object} [idicator] Used to indicate binding by key or partially
|
|
* applying arguments from the right.
|
|
* @returns {Function} Returns the new bound function.
|
|
*/
|
|
function createBound(func, thisArg, partialArgs, indicator) {
|
|
var isFunc = isFunction(func),
|
|
isPartial = !partialArgs,
|
|
key = thisArg;
|
|
|
|
// juggle arguments
|
|
if (isPartial) {
|
|
var rightIndicator = indicator;
|
|
partialArgs = thisArg;
|
|
}
|
|
else if (!isFunc) {
|
|
if (!indicator) {
|
|
throw new TypeError;
|
|
}
|
|
thisArg = func;
|
|
}
|
|
|
|
function bound() {
|
|
// `Function#bind` spec
|
|
// http://es5.github.com/#x15.3.4.5
|
|
var args = arguments,
|
|
thisBinding = isPartial ? this : thisArg;
|
|
|
|
if (!isFunc) {
|
|
func = thisArg[key];
|
|
}
|
|
if (partialArgs.length) {
|
|
args = args.length
|
|
? (args = nativeSlice.call(args), rightIndicator ? args.concat(partialArgs) : partialArgs.concat(args))
|
|
: partialArgs;
|
|
}
|
|
if (this instanceof bound) {
|
|
// ensure `new bound` is an instance of `func`
|
|
thisBinding = createObject(func.prototype);
|
|
|
|
// mimic the constructor's `return` behavior
|
|
// http://es5.github.com/#x13.2.2
|
|
var result = func.apply(thisBinding, args);
|
|
return isObject(result) ? result : thisBinding;
|
|
}
|
|
return func.apply(thisBinding, args);
|
|
}
|
|
return bound;
|
|
}
|
|
|
|
/**
|
|
* Creates a new object with the specified `prototype`.
|
|
*
|
|
* @private
|
|
* @param {Object} prototype The prototype object.
|
|
* @returns {Object} Returns the new object.
|
|
*/
|
|
function createObject(prototype) {
|
|
return isObject(prototype) ? nativeCreate(prototype) : {};
|
|
}
|
|
|
|
/**
|
|
* Used by `escape` to convert characters to HTML entities.
|
|
*
|
|
* @private
|
|
* @param {String} match The matched character to escape.
|
|
* @returns {String} Returns the escaped character.
|
|
*/
|
|
function escapeHtmlChar(match) {
|
|
return htmlEscapes[match];
|
|
}
|
|
|
|
/**
|
|
* Gets the appropriate "indexOf" function. If the `_.indexOf` method is
|
|
* customized, this method returns the custom method, otherwise it returns
|
|
* the `basicIndexOf` function.
|
|
*
|
|
* @private
|
|
* @returns {Function} Returns the "indexOf" function.
|
|
*/
|
|
function getIndexOf(array, value, fromIndex) {
|
|
var result = (result = lodash.indexOf) === indexOf ? basicIndexOf : result;
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Creates a function that juggles arguments, allowing argument overloading
|
|
* for `_.flatten` and `_.uniq`, before passing them to the given `func`.
|
|
*
|
|
* @private
|
|
* @param {Function} func The function to wrap.
|
|
* @returns {Function} Returns the new function.
|
|
*/
|
|
function overloadWrapper(func) {
|
|
return function(array, flag, callback, thisArg) {
|
|
// juggle arguments
|
|
if (typeof flag != 'boolean' && flag != null) {
|
|
thisArg = callback;
|
|
callback = !(thisArg && thisArg[flag] === array) ? flag : undefined;
|
|
flag = false;
|
|
}
|
|
if (callback != null) {
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
}
|
|
return func(array, flag, callback, thisArg);
|
|
};
|
|
}
|
|
|
|
/**
|
|
* A fallback implementation of `isPlainObject` which checks if a given `value`
|
|
* is an object created by the `Object` constructor, assuming objects created
|
|
* by the `Object` constructor have no inherited enumerable properties and that
|
|
* there are no `Object.prototype` extensions.
|
|
*
|
|
* @private
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if `value` is a plain object, else `false`.
|
|
*/
|
|
function shimIsPlainObject(value) {
|
|
var ctor,
|
|
result;
|
|
|
|
// avoid non Object objects, `arguments` objects, and DOM elements
|
|
if (!(value && toString.call(value) == objectClass) ||
|
|
(ctor = value.constructor, isFunction(ctor) && !(ctor instanceof ctor))) {
|
|
return false;
|
|
}
|
|
// In most environments an object's own properties are iterated before
|
|
// its inherited properties. If the last iterated property is an object's
|
|
// own property then there are no inherited enumerable properties.
|
|
forIn(value, function(value, key) {
|
|
result = key;
|
|
});
|
|
return result === undefined || hasOwnProperty.call(value, result);
|
|
}
|
|
|
|
/**
|
|
* Used by `unescape` to convert HTML entities to characters.
|
|
*
|
|
* @private
|
|
* @param {String} match The matched character to unescape.
|
|
* @returns {String} Returns the unescaped character.
|
|
*/
|
|
function unescapeHtmlChar(match) {
|
|
return htmlUnescapes[match];
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Checks if `value` is an `arguments` object.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is an `arguments` object, else `false`.
|
|
* @example
|
|
*
|
|
* (function() { return _.isArguments(arguments); })(1, 2, 3);
|
|
* // => true
|
|
*
|
|
* _.isArguments([1, 2, 3]);
|
|
* // => false
|
|
*/
|
|
function isArguments(value) {
|
|
return toString.call(value) == argsClass;
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is an array.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is an array, else `false`.
|
|
* @example
|
|
*
|
|
* (function() { return _.isArray(arguments); })();
|
|
* // => false
|
|
*
|
|
* _.isArray([1, 2, 3]);
|
|
* // => true
|
|
*/
|
|
var isArray = nativeIsArray;
|
|
|
|
/**
|
|
* A fallback implementation of `Object.keys` which produces an array of the
|
|
* given object's own enumerable property names.
|
|
*
|
|
* @private
|
|
* @type Function
|
|
* @param {Object} object The object to inspect.
|
|
* @returns {Array} Returns a new array of property names.
|
|
*/
|
|
var shimKeys = function (object) {
|
|
var index, iterable = object, result = [];
|
|
if (!iterable) return result;
|
|
if (!(objectTypes[typeof object])) return result;
|
|
for (index in iterable) {
|
|
if (hasOwnProperty.call(iterable, index)) {
|
|
result.push(index);
|
|
}
|
|
}
|
|
return result
|
|
};
|
|
|
|
/**
|
|
* Creates an array composed of the own enumerable property names of `object`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Object} object The object to inspect.
|
|
* @returns {Array} Returns a new array of property names.
|
|
* @example
|
|
*
|
|
* _.keys({ 'one': 1, 'two': 2, 'three': 3 });
|
|
* // => ['one', 'two', 'three'] (order is not guaranteed)
|
|
*/
|
|
var keys = !nativeKeys ? shimKeys : function(object) {
|
|
if (!isObject(object)) {
|
|
return [];
|
|
}
|
|
return nativeKeys(object);
|
|
};
|
|
|
|
/**
|
|
* Used to convert characters to HTML entities:
|
|
*
|
|
* Though the `>` character is escaped for symmetry, characters like `>` and `/`
|
|
* don't require escaping in HTML and have no special meaning unless they're part
|
|
* of a tag or an unquoted attribute value.
|
|
* http://mathiasbynens.be/notes/ambiguous-ampersands (under "semi-related fun fact")
|
|
*/
|
|
var htmlEscapes = {
|
|
'&': '&',
|
|
'<': '<',
|
|
'>': '>',
|
|
'"': '"',
|
|
"'": '''
|
|
};
|
|
|
|
/** Used to convert HTML entities to characters */
|
|
var htmlUnescapes = invert(htmlEscapes);
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Assigns own enumerable properties of source object(s) to the destination
|
|
* object. Subsequent sources will overwrite property assignments of previous
|
|
* sources. If a `callback` function is passed, it will be executed to produce
|
|
* the assigned values. The `callback` is bound to `thisArg` and invoked with
|
|
* two arguments; (objectValue, sourceValue).
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @type Function
|
|
* @alias extend
|
|
* @category Objects
|
|
* @param {Object} object The destination object.
|
|
* @param {Object} [source1, source2, ...] The source objects.
|
|
* @param {Function} [callback] The function to customize assigning values.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Object} Returns the destination object.
|
|
* @example
|
|
*
|
|
* _.assign({ 'name': 'moe' }, { 'age': 40 });
|
|
* // => { 'name': 'moe', 'age': 40 }
|
|
*
|
|
* var defaults = _.partialRight(_.assign, function(a, b) {
|
|
* return typeof a == 'undefined' ? b : a;
|
|
* });
|
|
*
|
|
* var food = { 'name': 'apple' };
|
|
* defaults(food, { 'name': 'banana', 'type': 'fruit' });
|
|
* // => { 'name': 'apple', 'type': 'fruit' }
|
|
*/
|
|
var assign = function (object, source, guard) {
|
|
var index, iterable = object, result = iterable;
|
|
if (!iterable) return result;
|
|
var args = arguments,
|
|
argsIndex = 0,
|
|
argsLength = typeof guard == 'number' ? 2 : args.length;
|
|
if (argsLength > 3 && typeof args[argsLength - 2] == 'function') {
|
|
var callback = lodash.createCallback(args[--argsLength - 1], args[argsLength--], 2);
|
|
} else if (argsLength > 2 && typeof args[argsLength - 1] == 'function') {
|
|
callback = args[--argsLength];
|
|
}
|
|
while (++argsIndex < argsLength) {
|
|
iterable = args[argsIndex];
|
|
if (iterable && objectTypes[typeof iterable]) {
|
|
var ownIndex = -1,
|
|
ownProps = objectTypes[typeof iterable] && keys(iterable),
|
|
length = ownProps ? ownProps.length : 0;
|
|
|
|
while (++ownIndex < length) {
|
|
index = ownProps[ownIndex];
|
|
result[index] = callback ? callback(result[index], iterable[index]) : iterable[index];
|
|
}
|
|
}
|
|
}
|
|
return result
|
|
};
|
|
|
|
/**
|
|
* Creates a clone of `value`. If `deep` is `true`, nested objects will also
|
|
* be cloned, otherwise they will be assigned by reference. If a `callback`
|
|
* function is passed, it will be executed to produce the cloned values. If
|
|
* `callback` returns `undefined`, cloning will be handled by the method instead.
|
|
* The `callback` is bound to `thisArg` and invoked with one argument; (value).
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to clone.
|
|
* @param {Boolean} [deep=false] A flag to indicate a deep clone.
|
|
* @param {Function} [callback] The function to customize cloning values.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @param- {Array} [stackA=[]] Tracks traversed source objects.
|
|
* @param- {Array} [stackB=[]] Associates clones with source counterparts.
|
|
* @returns {Mixed} Returns the cloned `value`.
|
|
* @example
|
|
*
|
|
* var stooges = [
|
|
* { 'name': 'moe', 'age': 40 },
|
|
* { 'name': 'larry', 'age': 50 }
|
|
* ];
|
|
*
|
|
* var shallow = _.clone(stooges);
|
|
* shallow[0] === stooges[0];
|
|
* // => true
|
|
*
|
|
* var deep = _.clone(stooges, true);
|
|
* deep[0] === stooges[0];
|
|
* // => false
|
|
*
|
|
* _.mixin({
|
|
* 'clone': _.partialRight(_.clone, function(value) {
|
|
* return _.isElement(value) ? value.cloneNode(false) : undefined;
|
|
* })
|
|
* });
|
|
*
|
|
* var clone = _.clone(document.body);
|
|
* clone.childNodes.length;
|
|
* // => 0
|
|
*/
|
|
function clone(value, deep, callback, thisArg, stackA, stackB) {
|
|
var result = value;
|
|
|
|
// allows working with "Collections" methods without using their `callback`
|
|
// argument, `index|key`, for this method's `callback`
|
|
if (typeof deep != 'boolean' && deep != null) {
|
|
thisArg = callback;
|
|
callback = deep;
|
|
deep = false;
|
|
}
|
|
if (typeof callback == 'function') {
|
|
callback = (typeof thisArg == 'undefined')
|
|
? callback
|
|
: lodash.createCallback(callback, thisArg, 1);
|
|
|
|
result = callback(result);
|
|
if (typeof result != 'undefined') {
|
|
return result;
|
|
}
|
|
result = value;
|
|
}
|
|
// inspect [[Class]]
|
|
var isObj = isObject(result);
|
|
if (isObj) {
|
|
var className = toString.call(result);
|
|
if (!cloneableClasses[className]) {
|
|
return result;
|
|
}
|
|
var isArr = isArray(result);
|
|
}
|
|
// shallow clone
|
|
if (!isObj || !deep) {
|
|
return isObj
|
|
? (isArr ? slice(result) : assign({}, result))
|
|
: result;
|
|
}
|
|
var ctor = ctorByClass[className];
|
|
switch (className) {
|
|
case boolClass:
|
|
case dateClass:
|
|
return new ctor(+result);
|
|
|
|
case numberClass:
|
|
case stringClass:
|
|
return new ctor(result);
|
|
|
|
case regexpClass:
|
|
return ctor(result.source, reFlags.exec(result));
|
|
}
|
|
// check for circular references and return corresponding clone
|
|
var initedStack = !stackA;
|
|
stackA || (stackA = getArray());
|
|
stackB || (stackB = getArray());
|
|
|
|
var length = stackA.length;
|
|
while (length--) {
|
|
if (stackA[length] == value) {
|
|
return stackB[length];
|
|
}
|
|
}
|
|
// init cloned object
|
|
result = isArr ? ctor(result.length) : {};
|
|
|
|
// add array properties assigned by `RegExp#exec`
|
|
if (isArr) {
|
|
if (hasOwnProperty.call(value, 'index')) {
|
|
result.index = value.index;
|
|
}
|
|
if (hasOwnProperty.call(value, 'input')) {
|
|
result.input = value.input;
|
|
}
|
|
}
|
|
// add the source value to the stack of traversed objects
|
|
// and associate it with its clone
|
|
stackA.push(value);
|
|
stackB.push(result);
|
|
|
|
// recursively populate clone (susceptible to call stack limits)
|
|
(isArr ? forEach : forOwn)(value, function(objValue, key) {
|
|
result[key] = clone(objValue, deep, callback, undefined, stackA, stackB);
|
|
});
|
|
|
|
if (initedStack) {
|
|
releaseArray(stackA);
|
|
releaseArray(stackB);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Creates a deep clone of `value`. If a `callback` function is passed,
|
|
* it will be executed to produce the cloned values. If `callback` returns
|
|
* `undefined`, cloning will be handled by the method instead. The `callback`
|
|
* is bound to `thisArg` and invoked with one argument; (value).
|
|
*
|
|
* Note: This method is loosely based on the structured clone algorithm. Functions
|
|
* and DOM nodes are **not** cloned. The enumerable properties of `arguments` objects and
|
|
* objects created by constructors other than `Object` are cloned to plain `Object` objects.
|
|
* See http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to deep clone.
|
|
* @param {Function} [callback] The function to customize cloning values.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Mixed} Returns the deep cloned `value`.
|
|
* @example
|
|
*
|
|
* var stooges = [
|
|
* { 'name': 'moe', 'age': 40 },
|
|
* { 'name': 'larry', 'age': 50 }
|
|
* ];
|
|
*
|
|
* var deep = _.cloneDeep(stooges);
|
|
* deep[0] === stooges[0];
|
|
* // => false
|
|
*
|
|
* var view = {
|
|
* 'label': 'docs',
|
|
* 'node': element
|
|
* };
|
|
*
|
|
* var clone = _.cloneDeep(view, function(value) {
|
|
* return _.isElement(value) ? value.cloneNode(true) : undefined;
|
|
* });
|
|
*
|
|
* clone.node == view.node;
|
|
* // => false
|
|
*/
|
|
function cloneDeep(value, callback, thisArg) {
|
|
return clone(value, true, callback, thisArg);
|
|
}
|
|
|
|
/**
|
|
* Assigns own enumerable properties of source object(s) to the destination
|
|
* object for all destination properties that resolve to `undefined`. Once a
|
|
* property is set, additional defaults of the same property will be ignored.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @type Function
|
|
* @category Objects
|
|
* @param {Object} object The destination object.
|
|
* @param {Object} [source1, source2, ...] The source objects.
|
|
* @param- {Object} [guard] Allows working with `_.reduce` without using its
|
|
* callback's `key` and `object` arguments as sources.
|
|
* @returns {Object} Returns the destination object.
|
|
* @example
|
|
*
|
|
* var food = { 'name': 'apple' };
|
|
* _.defaults(food, { 'name': 'banana', 'type': 'fruit' });
|
|
* // => { 'name': 'apple', 'type': 'fruit' }
|
|
*/
|
|
var defaults = function (object, source, guard) {
|
|
var index, iterable = object, result = iterable;
|
|
if (!iterable) return result;
|
|
var args = arguments,
|
|
argsIndex = 0,
|
|
argsLength = typeof guard == 'number' ? 2 : args.length;
|
|
while (++argsIndex < argsLength) {
|
|
iterable = args[argsIndex];
|
|
if (iterable && objectTypes[typeof iterable]) {
|
|
var ownIndex = -1,
|
|
ownProps = objectTypes[typeof iterable] && keys(iterable),
|
|
length = ownProps ? ownProps.length : 0;
|
|
|
|
while (++ownIndex < length) {
|
|
index = ownProps[ownIndex];
|
|
if (typeof result[index] == 'undefined') result[index] = iterable[index];
|
|
}
|
|
}
|
|
}
|
|
return result
|
|
};
|
|
|
|
/**
|
|
* This method is similar to `_.find`, except that it returns the key of the
|
|
* element that passes the callback check, instead of the element itself.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Object} object The object to search.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Mixed} Returns the key of the found element, else `undefined`.
|
|
* @example
|
|
*
|
|
* _.findKey({ 'a': 1, 'b': 2, 'c': 3, 'd': 4 }, function(num) {
|
|
* return num % 2 == 0;
|
|
* });
|
|
* // => 'b'
|
|
*/
|
|
function findKey(object, callback, thisArg) {
|
|
var result;
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
forOwn(object, function(value, key, object) {
|
|
if (callback(value, key, object)) {
|
|
result = key;
|
|
return false;
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Iterates over `object`'s own and inherited enumerable properties, executing
|
|
* the `callback` for each property. The `callback` is bound to `thisArg` and
|
|
* invoked with three arguments; (value, key, object). Callbacks may exit iteration
|
|
* early by explicitly returning `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @type Function
|
|
* @category Objects
|
|
* @param {Object} object The object to iterate over.
|
|
* @param {Function} [callback=identity] The function called per iteration.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Object} Returns `object`.
|
|
* @example
|
|
*
|
|
* function Dog(name) {
|
|
* this.name = name;
|
|
* }
|
|
*
|
|
* Dog.prototype.bark = function() {
|
|
* alert('Woof, woof!');
|
|
* };
|
|
*
|
|
* _.forIn(new Dog('Dagny'), function(value, key) {
|
|
* alert(key);
|
|
* });
|
|
* // => alerts 'name' and 'bark' (order is not guaranteed)
|
|
*/
|
|
var forIn = function (collection, callback, thisArg) {
|
|
var index, iterable = collection, result = iterable;
|
|
if (!iterable) return result;
|
|
if (!objectTypes[typeof iterable]) return result;
|
|
callback = callback && typeof thisArg == 'undefined' ? callback : lodash.createCallback(callback, thisArg);
|
|
for (index in iterable) {
|
|
if (callback(iterable[index], index, collection) === false) return result;
|
|
}
|
|
return result
|
|
};
|
|
|
|
/**
|
|
* Iterates over an object's own enumerable properties, executing the `callback`
|
|
* for each property. The `callback` is bound to `thisArg` and invoked with three
|
|
* arguments; (value, key, object). Callbacks may exit iteration early by explicitly
|
|
* returning `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @type Function
|
|
* @category Objects
|
|
* @param {Object} object The object to iterate over.
|
|
* @param {Function} [callback=identity] The function called per iteration.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Object} Returns `object`.
|
|
* @example
|
|
*
|
|
* _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
|
|
* alert(key);
|
|
* });
|
|
* // => alerts '0', '1', and 'length' (order is not guaranteed)
|
|
*/
|
|
var forOwn = function (collection, callback, thisArg) {
|
|
var index, iterable = collection, result = iterable;
|
|
if (!iterable) return result;
|
|
if (!objectTypes[typeof iterable]) return result;
|
|
callback = callback && typeof thisArg == 'undefined' ? callback : lodash.createCallback(callback, thisArg);
|
|
var ownIndex = -1,
|
|
ownProps = objectTypes[typeof iterable] && keys(iterable),
|
|
length = ownProps ? ownProps.length : 0;
|
|
|
|
while (++ownIndex < length) {
|
|
index = ownProps[ownIndex];
|
|
if (callback(iterable[index], index, collection) === false) return result;
|
|
}
|
|
return result
|
|
};
|
|
|
|
/**
|
|
* Creates a sorted array of all enumerable properties, own and inherited,
|
|
* of `object` that have function values.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias methods
|
|
* @category Objects
|
|
* @param {Object} object The object to inspect.
|
|
* @returns {Array} Returns a new array of property names that have function values.
|
|
* @example
|
|
*
|
|
* _.functions(_);
|
|
* // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...]
|
|
*/
|
|
function functions(object) {
|
|
var result = [];
|
|
forIn(object, function(value, key) {
|
|
if (isFunction(value)) {
|
|
result.push(key);
|
|
}
|
|
});
|
|
return result.sort();
|
|
}
|
|
|
|
/**
|
|
* Checks if the specified object `property` exists and is a direct property,
|
|
* instead of an inherited property.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Object} object The object to check.
|
|
* @param {String} property The property to check for.
|
|
* @returns {Boolean} Returns `true` if key is a direct property, else `false`.
|
|
* @example
|
|
*
|
|
* _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b');
|
|
* // => true
|
|
*/
|
|
function has(object, property) {
|
|
return object ? hasOwnProperty.call(object, property) : false;
|
|
}
|
|
|
|
/**
|
|
* Creates an object composed of the inverted keys and values of the given `object`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Object} object The object to invert.
|
|
* @returns {Object} Returns the created inverted object.
|
|
* @example
|
|
*
|
|
* _.invert({ 'first': 'moe', 'second': 'larry' });
|
|
* // => { 'moe': 'first', 'larry': 'second' }
|
|
*/
|
|
function invert(object) {
|
|
var index = -1,
|
|
props = keys(object),
|
|
length = props.length,
|
|
result = {};
|
|
|
|
while (++index < length) {
|
|
var key = props[index];
|
|
result[object[key]] = key;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is a boolean value.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is a boolean value, else `false`.
|
|
* @example
|
|
*
|
|
* _.isBoolean(null);
|
|
* // => false
|
|
*/
|
|
function isBoolean(value) {
|
|
return value === true || value === false || toString.call(value) == boolClass;
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is a date.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is a date, else `false`.
|
|
* @example
|
|
*
|
|
* _.isDate(new Date);
|
|
* // => true
|
|
*/
|
|
function isDate(value) {
|
|
return value ? (typeof value == 'object' && toString.call(value) == dateClass) : false;
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is a DOM element.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is a DOM element, else `false`.
|
|
* @example
|
|
*
|
|
* _.isElement(document.body);
|
|
* // => true
|
|
*/
|
|
function isElement(value) {
|
|
return value ? value.nodeType === 1 : false;
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is empty. Arrays, strings, or `arguments` objects with a
|
|
* length of `0` and objects with no own enumerable properties are considered
|
|
* "empty".
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Array|Object|String} value The value to inspect.
|
|
* @returns {Boolean} Returns `true`, if the `value` is empty, else `false`.
|
|
* @example
|
|
*
|
|
* _.isEmpty([1, 2, 3]);
|
|
* // => false
|
|
*
|
|
* _.isEmpty({});
|
|
* // => true
|
|
*
|
|
* _.isEmpty('');
|
|
* // => true
|
|
*/
|
|
function isEmpty(value) {
|
|
var result = true;
|
|
if (!value) {
|
|
return result;
|
|
}
|
|
var className = toString.call(value),
|
|
length = value.length;
|
|
|
|
if ((className == arrayClass || className == stringClass || className == argsClass ) ||
|
|
(className == objectClass && typeof length == 'number' && isFunction(value.splice))) {
|
|
return !length;
|
|
}
|
|
forOwn(value, function() {
|
|
return (result = false);
|
|
});
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Performs a deep comparison between two values to determine if they are
|
|
* equivalent to each other. If `callback` is passed, it will be executed to
|
|
* compare values. If `callback` returns `undefined`, comparisons will be handled
|
|
* by the method instead. The `callback` is bound to `thisArg` and invoked with
|
|
* two arguments; (a, b).
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} a The value to compare.
|
|
* @param {Mixed} b The other value to compare.
|
|
* @param {Function} [callback] The function to customize comparing values.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @param- {Array} [stackA=[]] Tracks traversed `a` objects.
|
|
* @param- {Array} [stackB=[]] Tracks traversed `b` objects.
|
|
* @returns {Boolean} Returns `true`, if the values are equivalent, else `false`.
|
|
* @example
|
|
*
|
|
* var moe = { 'name': 'moe', 'age': 40 };
|
|
* var copy = { 'name': 'moe', 'age': 40 };
|
|
*
|
|
* moe == copy;
|
|
* // => false
|
|
*
|
|
* _.isEqual(moe, copy);
|
|
* // => true
|
|
*
|
|
* var words = ['hello', 'goodbye'];
|
|
* var otherWords = ['hi', 'goodbye'];
|
|
*
|
|
* _.isEqual(words, otherWords, function(a, b) {
|
|
* var reGreet = /^(?:hello|hi)$/i,
|
|
* aGreet = _.isString(a) && reGreet.test(a),
|
|
* bGreet = _.isString(b) && reGreet.test(b);
|
|
*
|
|
* return (aGreet || bGreet) ? (aGreet == bGreet) : undefined;
|
|
* });
|
|
* // => true
|
|
*/
|
|
function isEqual(a, b, callback, thisArg, stackA, stackB) {
|
|
// used to indicate that when comparing objects, `a` has at least the properties of `b`
|
|
var whereIndicator = callback === indicatorObject;
|
|
if (typeof callback == 'function' && !whereIndicator) {
|
|
callback = lodash.createCallback(callback, thisArg, 2);
|
|
var result = callback(a, b);
|
|
if (typeof result != 'undefined') {
|
|
return !!result;
|
|
}
|
|
}
|
|
// exit early for identical values
|
|
if (a === b) {
|
|
// treat `+0` vs. `-0` as not equal
|
|
return a !== 0 || (1 / a == 1 / b);
|
|
}
|
|
var type = typeof a,
|
|
otherType = typeof b;
|
|
|
|
// exit early for unlike primitive values
|
|
if (a === a &&
|
|
(!a || (type != 'function' && type != 'object')) &&
|
|
(!b || (otherType != 'function' && otherType != 'object'))) {
|
|
return false;
|
|
}
|
|
// exit early for `null` and `undefined`, avoiding ES3's Function#call behavior
|
|
// http://es5.github.com/#x15.3.4.4
|
|
if (a == null || b == null) {
|
|
return a === b;
|
|
}
|
|
// compare [[Class]] names
|
|
var className = toString.call(a),
|
|
otherClass = toString.call(b);
|
|
|
|
if (className == argsClass) {
|
|
className = objectClass;
|
|
}
|
|
if (otherClass == argsClass) {
|
|
otherClass = objectClass;
|
|
}
|
|
if (className != otherClass) {
|
|
return false;
|
|
}
|
|
switch (className) {
|
|
case boolClass:
|
|
case dateClass:
|
|
// coerce dates and booleans to numbers, dates to milliseconds and booleans
|
|
// to `1` or `0`, treating invalid dates coerced to `NaN` as not equal
|
|
return +a == +b;
|
|
|
|
case numberClass:
|
|
// treat `NaN` vs. `NaN` as equal
|
|
return (a != +a)
|
|
? b != +b
|
|
// but treat `+0` vs. `-0` as not equal
|
|
: (a == 0 ? (1 / a == 1 / b) : a == +b);
|
|
|
|
case regexpClass:
|
|
case stringClass:
|
|
// coerce regexes to strings (http://es5.github.com/#x15.10.6.4)
|
|
// treat string primitives and their corresponding object instances as equal
|
|
return a == String(b);
|
|
}
|
|
var isArr = className == arrayClass;
|
|
if (!isArr) {
|
|
// unwrap any `lodash` wrapped values
|
|
if (hasOwnProperty.call(a, '__wrapped__ ') || hasOwnProperty.call(b, '__wrapped__')) {
|
|
return isEqual(a.__wrapped__ || a, b.__wrapped__ || b, callback, thisArg, stackA, stackB);
|
|
}
|
|
// exit for functions and DOM nodes
|
|
if (className != objectClass) {
|
|
return false;
|
|
}
|
|
// in older versions of Opera, `arguments` objects have `Array` constructors
|
|
var ctorA = a.constructor,
|
|
ctorB = b.constructor;
|
|
|
|
// non `Object` object instances with different constructors are not equal
|
|
if (ctorA != ctorB && !(
|
|
isFunction(ctorA) && ctorA instanceof ctorA &&
|
|
isFunction(ctorB) && ctorB instanceof ctorB
|
|
)) {
|
|
return false;
|
|
}
|
|
}
|
|
// assume cyclic structures are equal
|
|
// the algorithm for detecting cyclic structures is adapted from ES 5.1
|
|
// section 15.12.3, abstract operation `JO` (http://es5.github.com/#x15.12.3)
|
|
var initedStack = !stackA;
|
|
stackA || (stackA = getArray());
|
|
stackB || (stackB = getArray());
|
|
|
|
var length = stackA.length;
|
|
while (length--) {
|
|
if (stackA[length] == a) {
|
|
return stackB[length] == b;
|
|
}
|
|
}
|
|
var size = 0;
|
|
result = true;
|
|
|
|
// add `a` and `b` to the stack of traversed objects
|
|
stackA.push(a);
|
|
stackB.push(b);
|
|
|
|
// recursively compare objects and arrays (susceptible to call stack limits)
|
|
if (isArr) {
|
|
length = a.length;
|
|
size = b.length;
|
|
|
|
// compare lengths to determine if a deep comparison is necessary
|
|
result = size == a.length;
|
|
if (!result && !whereIndicator) {
|
|
return result;
|
|
}
|
|
// deep compare the contents, ignoring non-numeric properties
|
|
while (size--) {
|
|
var index = length,
|
|
value = b[size];
|
|
|
|
if (whereIndicator) {
|
|
while (index--) {
|
|
if ((result = isEqual(a[index], value, callback, thisArg, stackA, stackB))) {
|
|
break;
|
|
}
|
|
}
|
|
} else if (!(result = isEqual(a[size], value, callback, thisArg, stackA, stackB))) {
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
// deep compare objects using `forIn`, instead of `forOwn`, to avoid `Object.keys`
|
|
// which, in this case, is more costly
|
|
forIn(b, function(value, key, b) {
|
|
if (hasOwnProperty.call(b, key)) {
|
|
// count the number of properties.
|
|
size++;
|
|
// deep compare each property value.
|
|
return (result = hasOwnProperty.call(a, key) && isEqual(a[key], value, callback, thisArg, stackA, stackB));
|
|
}
|
|
});
|
|
|
|
if (result && !whereIndicator) {
|
|
// ensure both objects have the same number of properties
|
|
forIn(a, function(value, key, a) {
|
|
if (hasOwnProperty.call(a, key)) {
|
|
// `size` will be `-1` if `a` has more properties than `b`
|
|
return (result = --size > -1);
|
|
}
|
|
});
|
|
}
|
|
if (initedStack) {
|
|
releaseArray(stackA);
|
|
releaseArray(stackB);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is, or can be coerced to, a finite number.
|
|
*
|
|
* Note: This is not the same as native `isFinite`, which will return true for
|
|
* booleans and empty strings. See http://es5.github.com/#x15.1.2.5.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is finite, else `false`.
|
|
* @example
|
|
*
|
|
* _.isFinite(-101);
|
|
* // => true
|
|
*
|
|
* _.isFinite('10');
|
|
* // => true
|
|
*
|
|
* _.isFinite(true);
|
|
* // => false
|
|
*
|
|
* _.isFinite('');
|
|
* // => false
|
|
*
|
|
* _.isFinite(Infinity);
|
|
* // => false
|
|
*/
|
|
function isFinite(value) {
|
|
return nativeIsFinite(value) && !nativeIsNaN(parseFloat(value));
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is a function.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is a function, else `false`.
|
|
* @example
|
|
*
|
|
* _.isFunction(_);
|
|
* // => true
|
|
*/
|
|
function isFunction(value) {
|
|
return typeof value == 'function';
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is the language type of Object.
|
|
* (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is an object, else `false`.
|
|
* @example
|
|
*
|
|
* _.isObject({});
|
|
* // => true
|
|
*
|
|
* _.isObject([1, 2, 3]);
|
|
* // => true
|
|
*
|
|
* _.isObject(1);
|
|
* // => false
|
|
*/
|
|
function isObject(value) {
|
|
// check if the value is the ECMAScript language type of Object
|
|
// http://es5.github.com/#x8
|
|
// and avoid a V8 bug
|
|
// http://code.google.com/p/v8/issues/detail?id=2291
|
|
return !!(value && objectTypes[typeof value]);
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is `NaN`.
|
|
*
|
|
* Note: This is not the same as native `isNaN`, which will return `true` for
|
|
* `undefined` and other values. See http://es5.github.com/#x15.1.2.4.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is `NaN`, else `false`.
|
|
* @example
|
|
*
|
|
* _.isNaN(NaN);
|
|
* // => true
|
|
*
|
|
* _.isNaN(new Number(NaN));
|
|
* // => true
|
|
*
|
|
* isNaN(undefined);
|
|
* // => true
|
|
*
|
|
* _.isNaN(undefined);
|
|
* // => false
|
|
*/
|
|
function isNaN(value) {
|
|
// `NaN` as a primitive is the only value that is not equal to itself
|
|
// (perform the [[Class]] check first to avoid errors with some host objects in IE)
|
|
return isNumber(value) && value != +value
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is `null`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is `null`, else `false`.
|
|
* @example
|
|
*
|
|
* _.isNull(null);
|
|
* // => true
|
|
*
|
|
* _.isNull(undefined);
|
|
* // => false
|
|
*/
|
|
function isNull(value) {
|
|
return value === null;
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is a number.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is a number, else `false`.
|
|
* @example
|
|
*
|
|
* _.isNumber(8.4 * 5);
|
|
* // => true
|
|
*/
|
|
function isNumber(value) {
|
|
return typeof value == 'number' || toString.call(value) == numberClass;
|
|
}
|
|
|
|
/**
|
|
* Checks if a given `value` is an object created by the `Object` constructor.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if `value` is a plain object, else `false`.
|
|
* @example
|
|
*
|
|
* function Stooge(name, age) {
|
|
* this.name = name;
|
|
* this.age = age;
|
|
* }
|
|
*
|
|
* _.isPlainObject(new Stooge('moe', 40));
|
|
* // => false
|
|
*
|
|
* _.isPlainObject([1, 2, 3]);
|
|
* // => false
|
|
*
|
|
* _.isPlainObject({ 'name': 'moe', 'age': 40 });
|
|
* // => true
|
|
*/
|
|
var isPlainObject = function(value) {
|
|
if (!(value && toString.call(value) == objectClass)) {
|
|
return false;
|
|
}
|
|
var valueOf = value.valueOf,
|
|
objProto = typeof valueOf == 'function' && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto);
|
|
|
|
return objProto
|
|
? (value == objProto || getPrototypeOf(value) == objProto)
|
|
: shimIsPlainObject(value);
|
|
};
|
|
|
|
/**
|
|
* Checks if `value` is a regular expression.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is a regular expression, else `false`.
|
|
* @example
|
|
*
|
|
* _.isRegExp(/moe/);
|
|
* // => true
|
|
*/
|
|
function isRegExp(value) {
|
|
return value ? (typeof value == 'object' && toString.call(value) == regexpClass) : false;
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is a string.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is a string, else `false`.
|
|
* @example
|
|
*
|
|
* _.isString('moe');
|
|
* // => true
|
|
*/
|
|
function isString(value) {
|
|
return typeof value == 'string' || toString.call(value) == stringClass;
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is `undefined`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is `undefined`, else `false`.
|
|
* @example
|
|
*
|
|
* _.isUndefined(void 0);
|
|
* // => true
|
|
*/
|
|
function isUndefined(value) {
|
|
return typeof value == 'undefined';
|
|
}
|
|
|
|
/**
|
|
* Recursively merges own enumerable properties of the source object(s), that
|
|
* don't resolve to `undefined`, into the destination object. Subsequent sources
|
|
* will overwrite property assignments of previous sources. If a `callback` function
|
|
* is passed, it will be executed to produce the merged values of the destination
|
|
* and source properties. If `callback` returns `undefined`, merging will be
|
|
* handled by the method instead. The `callback` is bound to `thisArg` and
|
|
* invoked with two arguments; (objectValue, sourceValue).
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Object} object The destination object.
|
|
* @param {Object} [source1, source2, ...] The source objects.
|
|
* @param {Function} [callback] The function to customize merging properties.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @param- {Object} [deepIndicator] Indicates that `stackA` and `stackB` are
|
|
* arrays of traversed objects, instead of source objects.
|
|
* @param- {Array} [stackA=[]] Tracks traversed source objects.
|
|
* @param- {Array} [stackB=[]] Associates values with source counterparts.
|
|
* @returns {Object} Returns the destination object.
|
|
* @example
|
|
*
|
|
* var names = {
|
|
* 'stooges': [
|
|
* { 'name': 'moe' },
|
|
* { 'name': 'larry' }
|
|
* ]
|
|
* };
|
|
*
|
|
* var ages = {
|
|
* 'stooges': [
|
|
* { 'age': 40 },
|
|
* { 'age': 50 }
|
|
* ]
|
|
* };
|
|
*
|
|
* _.merge(names, ages);
|
|
* // => { 'stooges': [{ 'name': 'moe', 'age': 40 }, { 'name': 'larry', 'age': 50 }] }
|
|
*
|
|
* var food = {
|
|
* 'fruits': ['apple'],
|
|
* 'vegetables': ['beet']
|
|
* };
|
|
*
|
|
* var otherFood = {
|
|
* 'fruits': ['banana'],
|
|
* 'vegetables': ['carrot']
|
|
* };
|
|
*
|
|
* _.merge(food, otherFood, function(a, b) {
|
|
* return _.isArray(a) ? a.concat(b) : undefined;
|
|
* });
|
|
* // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot] }
|
|
*/
|
|
function merge(object, source, deepIndicator) {
|
|
var args = arguments,
|
|
index = 0,
|
|
length = 2;
|
|
|
|
if (!isObject(object)) {
|
|
return object;
|
|
}
|
|
if (deepIndicator === indicatorObject) {
|
|
var callback = args[3],
|
|
stackA = args[4],
|
|
stackB = args[5];
|
|
} else {
|
|
var initedStack = true;
|
|
stackA = getArray();
|
|
stackB = getArray();
|
|
|
|
// allows working with `_.reduce` and `_.reduceRight` without
|
|
// using their `callback` arguments, `index|key` and `collection`
|
|
if (typeof deepIndicator != 'number') {
|
|
length = args.length;
|
|
}
|
|
if (length > 3 && typeof args[length - 2] == 'function') {
|
|
callback = lodash.createCallback(args[--length - 1], args[length--], 2);
|
|
} else if (length > 2 && typeof args[length - 1] == 'function') {
|
|
callback = args[--length];
|
|
}
|
|
}
|
|
while (++index < length) {
|
|
(isArray(args[index]) ? forEach : forOwn)(args[index], function(source, key) {
|
|
var found,
|
|
isArr,
|
|
result = source,
|
|
value = object[key];
|
|
|
|
if (source && ((isArr = isArray(source)) || isPlainObject(source))) {
|
|
// avoid merging previously merged cyclic sources
|
|
var stackLength = stackA.length;
|
|
while (stackLength--) {
|
|
if ((found = stackA[stackLength] == source)) {
|
|
value = stackB[stackLength];
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
var isShallow;
|
|
if (callback) {
|
|
result = callback(value, source);
|
|
if ((isShallow = typeof result != 'undefined')) {
|
|
value = result;
|
|
}
|
|
}
|
|
if (!isShallow) {
|
|
value = isArr
|
|
? (isArray(value) ? value : [])
|
|
: (isPlainObject(value) ? value : {});
|
|
}
|
|
// add `source` and associated `value` to the stack of traversed objects
|
|
stackA.push(source);
|
|
stackB.push(value);
|
|
|
|
// recursively merge objects and arrays (susceptible to call stack limits)
|
|
if (!isShallow) {
|
|
value = merge(value, source, indicatorObject, callback, stackA, stackB);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (callback) {
|
|
result = callback(value, source);
|
|
if (typeof result == 'undefined') {
|
|
result = source;
|
|
}
|
|
}
|
|
if (typeof result != 'undefined') {
|
|
value = result;
|
|
}
|
|
}
|
|
object[key] = value;
|
|
});
|
|
}
|
|
|
|
if (initedStack) {
|
|
releaseArray(stackA);
|
|
releaseArray(stackB);
|
|
}
|
|
return object;
|
|
}
|
|
|
|
/**
|
|
* Creates a shallow clone of `object` excluding the specified properties.
|
|
* Property names may be specified as individual arguments or as arrays of
|
|
* property names. If a `callback` function is passed, it will be executed
|
|
* for each property in the `object`, omitting the properties `callback`
|
|
* returns truthy for. The `callback` is bound to `thisArg` and invoked
|
|
* with three arguments; (value, key, object).
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Object} object The source object.
|
|
* @param {Function|String} callback|[prop1, prop2, ...] The properties to omit
|
|
* or the function called per iteration.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Object} Returns an object without the omitted properties.
|
|
* @example
|
|
*
|
|
* _.omit({ 'name': 'moe', 'age': 40 }, 'age');
|
|
* // => { 'name': 'moe' }
|
|
*
|
|
* _.omit({ 'name': 'moe', 'age': 40 }, function(value) {
|
|
* return typeof value == 'number';
|
|
* });
|
|
* // => { 'name': 'moe' }
|
|
*/
|
|
function omit(object, callback, thisArg) {
|
|
var indexOf = getIndexOf(),
|
|
isFunc = typeof callback == 'function',
|
|
result = {};
|
|
|
|
if (isFunc) {
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
} else {
|
|
var props = concat.apply(arrayRef, nativeSlice.call(arguments, 1));
|
|
}
|
|
forIn(object, function(value, key, object) {
|
|
if (isFunc
|
|
? !callback(value, key, object)
|
|
: indexOf(props, key) < 0
|
|
) {
|
|
result[key] = value;
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Creates a two dimensional array of the given object's key-value pairs,
|
|
* i.e. `[[key1, value1], [key2, value2]]`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Object} object The object to inspect.
|
|
* @returns {Array} Returns new array of key-value pairs.
|
|
* @example
|
|
*
|
|
* _.pairs({ 'moe': 30, 'larry': 40 });
|
|
* // => [['moe', 30], ['larry', 40]] (order is not guaranteed)
|
|
*/
|
|
function pairs(object) {
|
|
var index = -1,
|
|
props = keys(object),
|
|
length = props.length,
|
|
result = Array(length);
|
|
|
|
while (++index < length) {
|
|
var key = props[index];
|
|
result[index] = [key, object[key]];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Creates a shallow clone of `object` composed of the specified properties.
|
|
* Property names may be specified as individual arguments or as arrays of property
|
|
* names. If `callback` is passed, it will be executed for each property in the
|
|
* `object`, picking the properties `callback` returns truthy for. The `callback`
|
|
* is bound to `thisArg` and invoked with three arguments; (value, key, object).
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Object} object The source object.
|
|
* @param {Array|Function|String} callback|[prop1, prop2, ...] The function called
|
|
* per iteration or properties to pick, either as individual arguments or arrays.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Object} Returns an object composed of the picked properties.
|
|
* @example
|
|
*
|
|
* _.pick({ 'name': 'moe', '_userid': 'moe1' }, 'name');
|
|
* // => { 'name': 'moe' }
|
|
*
|
|
* _.pick({ 'name': 'moe', '_userid': 'moe1' }, function(value, key) {
|
|
* return key.charAt(0) != '_';
|
|
* });
|
|
* // => { 'name': 'moe' }
|
|
*/
|
|
function pick(object, callback, thisArg) {
|
|
var result = {};
|
|
if (typeof callback != 'function') {
|
|
var index = -1,
|
|
props = concat.apply(arrayRef, nativeSlice.call(arguments, 1)),
|
|
length = isObject(object) ? props.length : 0;
|
|
|
|
while (++index < length) {
|
|
var key = props[index];
|
|
if (key in object) {
|
|
result[key] = object[key];
|
|
}
|
|
}
|
|
} else {
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
forIn(object, function(value, key, object) {
|
|
if (callback(value, key, object)) {
|
|
result[key] = value;
|
|
}
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* An alternative to `_.reduce`, this method transforms an `object` to a new
|
|
* `accumulator` object which is the result of running each of its elements
|
|
* through the `callback`, with each `callback` execution potentially mutating
|
|
* the `accumulator` object. The `callback` is bound to `thisArg` and invoked
|
|
* with four arguments; (accumulator, value, key, object). Callbacks may exit
|
|
* iteration early by explicitly returning `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Array|Object} collection The collection to iterate over.
|
|
* @param {Function} [callback=identity] The function called per iteration.
|
|
* @param {Mixed} [accumulator] The custom accumulator value.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Mixed} Returns the accumulated value.
|
|
* @example
|
|
*
|
|
* var squares = _.transform([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], function(result, num) {
|
|
* num *= num;
|
|
* if (num % 2) {
|
|
* return result.push(num) < 3;
|
|
* }
|
|
* });
|
|
* // => [1, 9, 25]
|
|
*
|
|
* var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
|
|
* result[key] = num * 3;
|
|
* });
|
|
* // => { 'a': 3, 'b': 6, 'c': 9 }
|
|
*/
|
|
function transform(object, callback, accumulator, thisArg) {
|
|
var isArr = isArray(object);
|
|
callback = lodash.createCallback(callback, thisArg, 4);
|
|
|
|
if (accumulator == null) {
|
|
if (isArr) {
|
|
accumulator = [];
|
|
} else {
|
|
var ctor = object && object.constructor,
|
|
proto = ctor && ctor.prototype;
|
|
|
|
accumulator = createObject(proto);
|
|
}
|
|
}
|
|
(isArr ? forEach : forOwn)(object, function(value, index, object) {
|
|
return callback(accumulator, value, index, object);
|
|
});
|
|
return accumulator;
|
|
}
|
|
|
|
/**
|
|
* Creates an array composed of the own enumerable property values of `object`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Object} object The object to inspect.
|
|
* @returns {Array} Returns a new array of property values.
|
|
* @example
|
|
*
|
|
* _.values({ 'one': 1, 'two': 2, 'three': 3 });
|
|
* // => [1, 2, 3] (order is not guaranteed)
|
|
*/
|
|
function values(object) {
|
|
var index = -1,
|
|
props = keys(object),
|
|
length = props.length,
|
|
result = Array(length);
|
|
|
|
while (++index < length) {
|
|
result[index] = object[props[index]];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Creates an array of elements from the specified indexes, or keys, of the
|
|
* `collection`. Indexes may be specified as individual arguments or as arrays
|
|
* of indexes.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Array|Number|String} [index1, index2, ...] The indexes of
|
|
* `collection` to retrieve, either as individual arguments or arrays.
|
|
* @returns {Array} Returns a new array of elements corresponding to the
|
|
* provided indexes.
|
|
* @example
|
|
*
|
|
* _.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]);
|
|
* // => ['a', 'c', 'e']
|
|
*
|
|
* _.at(['moe', 'larry', 'curly'], 0, 2);
|
|
* // => ['moe', 'curly']
|
|
*/
|
|
function at(collection) {
|
|
var index = -1,
|
|
props = concat.apply(arrayRef, nativeSlice.call(arguments, 1)),
|
|
length = props.length,
|
|
result = Array(length);
|
|
|
|
while(++index < length) {
|
|
result[index] = collection[props[index]];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Checks if a given `target` element is present in a `collection` using strict
|
|
* equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used
|
|
* as the offset from the end of the collection.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias include
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Mixed} target The value to check for.
|
|
* @param {Number} [fromIndex=0] The index to search from.
|
|
* @returns {Boolean} Returns `true` if the `target` element is found, else `false`.
|
|
* @example
|
|
*
|
|
* _.contains([1, 2, 3], 1);
|
|
* // => true
|
|
*
|
|
* _.contains([1, 2, 3], 1, 2);
|
|
* // => false
|
|
*
|
|
* _.contains({ 'name': 'moe', 'age': 40 }, 'moe');
|
|
* // => true
|
|
*
|
|
* _.contains('curly', 'ur');
|
|
* // => true
|
|
*/
|
|
function contains(collection, target, fromIndex) {
|
|
var index = -1,
|
|
indexOf = getIndexOf(),
|
|
length = collection ? collection.length : 0,
|
|
result = false;
|
|
|
|
fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) || 0;
|
|
if (length && typeof length == 'number') {
|
|
result = (isString(collection)
|
|
? collection.indexOf(target, fromIndex)
|
|
: indexOf(collection, target, fromIndex)
|
|
) > -1;
|
|
} else {
|
|
forOwn(collection, function(value) {
|
|
if (++index >= fromIndex) {
|
|
return !(result = value === target);
|
|
}
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Creates an object composed of keys returned from running each element of the
|
|
* `collection` through the given `callback`. The corresponding value of each key
|
|
* is the number of times the key was returned by the `callback`. The `callback`
|
|
* is bound to `thisArg` and invoked with three arguments; (value, index|key, collection).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Object} Returns the composed aggregate object.
|
|
* @example
|
|
*
|
|
* _.countBy([4.3, 6.1, 6.4], function(num) { return Math.floor(num); });
|
|
* // => { '4': 1, '6': 2 }
|
|
*
|
|
* _.countBy([4.3, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
|
|
* // => { '4': 1, '6': 2 }
|
|
*
|
|
* _.countBy(['one', 'two', 'three'], 'length');
|
|
* // => { '3': 2, '5': 1 }
|
|
*/
|
|
function countBy(collection, callback, thisArg) {
|
|
var result = {};
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
|
|
forEach(collection, function(value, key, collection) {
|
|
key = String(callback(value, key, collection));
|
|
(hasOwnProperty.call(result, key) ? result[key]++ : result[key] = 1);
|
|
});
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Checks if the `callback` returns a truthy value for **all** elements of a
|
|
* `collection`. The `callback` is bound to `thisArg` and invoked with three
|
|
* arguments; (value, index|key, collection).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias all
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Boolean} Returns `true` if all elements pass the callback check,
|
|
* else `false`.
|
|
* @example
|
|
*
|
|
* _.every([true, 1, null, 'yes'], Boolean);
|
|
* // => false
|
|
*
|
|
* var stooges = [
|
|
* { 'name': 'moe', 'age': 40 },
|
|
* { 'name': 'larry', 'age': 50 }
|
|
* ];
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.every(stooges, 'age');
|
|
* // => true
|
|
*
|
|
* // using "_.where" callback shorthand
|
|
* _.every(stooges, { 'age': 50 });
|
|
* // => false
|
|
*/
|
|
function every(collection, callback, thisArg) {
|
|
var result = true;
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
|
|
var index = -1,
|
|
length = collection ? collection.length : 0;
|
|
|
|
if (typeof length == 'number') {
|
|
while (++index < length) {
|
|
if (!(result = !!callback(collection[index], index, collection))) {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
forOwn(collection, function(value, index, collection) {
|
|
return (result = !!callback(value, index, collection));
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Examines each element in a `collection`, returning an array of all elements
|
|
* the `callback` returns truthy for. The `callback` is bound to `thisArg` and
|
|
* invoked with three arguments; (value, index|key, collection).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias select
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Array} Returns a new array of elements that passed the callback check.
|
|
* @example
|
|
*
|
|
* var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
|
|
* // => [2, 4, 6]
|
|
*
|
|
* var food = [
|
|
* { 'name': 'apple', 'organic': false, 'type': 'fruit' },
|
|
* { 'name': 'carrot', 'organic': true, 'type': 'vegetable' }
|
|
* ];
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.filter(food, 'organic');
|
|
* // => [{ 'name': 'carrot', 'organic': true, 'type': 'vegetable' }]
|
|
*
|
|
* // using "_.where" callback shorthand
|
|
* _.filter(food, { 'type': 'fruit' });
|
|
* // => [{ 'name': 'apple', 'organic': false, 'type': 'fruit' }]
|
|
*/
|
|
function filter(collection, callback, thisArg) {
|
|
var result = [];
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
|
|
var index = -1,
|
|
length = collection ? collection.length : 0;
|
|
|
|
if (typeof length == 'number') {
|
|
while (++index < length) {
|
|
var value = collection[index];
|
|
if (callback(value, index, collection)) {
|
|
result.push(value);
|
|
}
|
|
}
|
|
} else {
|
|
forOwn(collection, function(value, index, collection) {
|
|
if (callback(value, index, collection)) {
|
|
result.push(value);
|
|
}
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Examines each element in a `collection`, returning the first that the `callback`
|
|
* returns truthy for. The `callback` is bound to `thisArg` and invoked with three
|
|
* arguments; (value, index|key, collection).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias detect, findWhere
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Mixed} Returns the found element, else `undefined`.
|
|
* @example
|
|
*
|
|
* _.find([1, 2, 3, 4], function(num) {
|
|
* return num % 2 == 0;
|
|
* });
|
|
* // => 2
|
|
*
|
|
* var food = [
|
|
* { 'name': 'apple', 'organic': false, 'type': 'fruit' },
|
|
* { 'name': 'banana', 'organic': true, 'type': 'fruit' },
|
|
* { 'name': 'beet', 'organic': false, 'type': 'vegetable' }
|
|
* ];
|
|
*
|
|
* // using "_.where" callback shorthand
|
|
* _.find(food, { 'type': 'vegetable' });
|
|
* // => { 'name': 'beet', 'organic': false, 'type': 'vegetable' }
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.find(food, 'organic');
|
|
* // => { 'name': 'banana', 'organic': true, 'type': 'fruit' }
|
|
*/
|
|
function find(collection, callback, thisArg) {
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
|
|
var index = -1,
|
|
length = collection ? collection.length : 0;
|
|
|
|
if (typeof length == 'number') {
|
|
while (++index < length) {
|
|
var value = collection[index];
|
|
if (callback(value, index, collection)) {
|
|
return value;
|
|
}
|
|
}
|
|
} else {
|
|
var result;
|
|
forOwn(collection, function(value, index, collection) {
|
|
if (callback(value, index, collection)) {
|
|
result = value;
|
|
return false;
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Iterates over a `collection`, executing the `callback` for each element in
|
|
* the `collection`. The `callback` is bound to `thisArg` and invoked with three
|
|
* arguments; (value, index|key, collection). Callbacks may exit iteration early
|
|
* by explicitly returning `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias each
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function} [callback=identity] The function called per iteration.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Array|Object|String} Returns `collection`.
|
|
* @example
|
|
*
|
|
* _([1, 2, 3]).forEach(alert).join(',');
|
|
* // => alerts each number and returns '1,2,3'
|
|
*
|
|
* _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, alert);
|
|
* // => alerts each number value (order is not guaranteed)
|
|
*/
|
|
function forEach(collection, callback, thisArg) {
|
|
var index = -1,
|
|
length = collection ? collection.length : 0;
|
|
|
|
callback = callback && typeof thisArg == 'undefined' ? callback : lodash.createCallback(callback, thisArg);
|
|
if (typeof length == 'number') {
|
|
while (++index < length) {
|
|
if (callback(collection[index], index, collection) === false) {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
forOwn(collection, callback);
|
|
}
|
|
return collection;
|
|
}
|
|
|
|
/**
|
|
* Creates an object composed of keys returned from running each element of the
|
|
* `collection` through the `callback`. The corresponding value of each key is
|
|
* an array of elements passed to `callback` that returned the key. The `callback`
|
|
* is bound to `thisArg` and invoked with three arguments; (value, index|key, collection).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Object} Returns the composed aggregate object.
|
|
* @example
|
|
*
|
|
* _.groupBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num); });
|
|
* // => { '4': [4.2], '6': [6.1, 6.4] }
|
|
*
|
|
* _.groupBy([4.2, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
|
|
* // => { '4': [4.2], '6': [6.1, 6.4] }
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.groupBy(['one', 'two', 'three'], 'length');
|
|
* // => { '3': ['one', 'two'], '5': ['three'] }
|
|
*/
|
|
function groupBy(collection, callback, thisArg) {
|
|
var result = {};
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
|
|
forEach(collection, function(value, key, collection) {
|
|
key = String(callback(value, key, collection));
|
|
(hasOwnProperty.call(result, key) ? result[key] : result[key] = []).push(value);
|
|
});
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Invokes the method named by `methodName` on each element in the `collection`,
|
|
* returning an array of the results of each invoked method. Additional arguments
|
|
* will be passed to each invoked method. If `methodName` is a function, it will
|
|
* be invoked for, and `this` bound to, each element in the `collection`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|String} methodName The name of the method to invoke or
|
|
* the function invoked per iteration.
|
|
* @param {Mixed} [arg1, arg2, ...] Arguments to invoke the method with.
|
|
* @returns {Array} Returns a new array of the results of each invoked method.
|
|
* @example
|
|
*
|
|
* _.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
|
|
* // => [[1, 5, 7], [1, 2, 3]]
|
|
*
|
|
* _.invoke([123, 456], String.prototype.split, '');
|
|
* // => [['1', '2', '3'], ['4', '5', '6']]
|
|
*/
|
|
function invoke(collection, methodName) {
|
|
var args = nativeSlice.call(arguments, 2),
|
|
index = -1,
|
|
isFunc = typeof methodName == 'function',
|
|
length = collection ? collection.length : 0,
|
|
result = Array(typeof length == 'number' ? length : 0);
|
|
|
|
forEach(collection, function(value) {
|
|
result[++index] = (isFunc ? methodName : value[methodName]).apply(value, args);
|
|
});
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Creates an array of values by running each element in the `collection`
|
|
* through the `callback`. The `callback` is bound to `thisArg` and invoked with
|
|
* three arguments; (value, index|key, collection).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias collect
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Array} Returns a new array of the results of each `callback` execution.
|
|
* @example
|
|
*
|
|
* _.map([1, 2, 3], function(num) { return num * 3; });
|
|
* // => [3, 6, 9]
|
|
*
|
|
* _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; });
|
|
* // => [3, 6, 9] (order is not guaranteed)
|
|
*
|
|
* var stooges = [
|
|
* { 'name': 'moe', 'age': 40 },
|
|
* { 'name': 'larry', 'age': 50 }
|
|
* ];
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.map(stooges, 'name');
|
|
* // => ['moe', 'larry']
|
|
*/
|
|
function map(collection, callback, thisArg) {
|
|
var index = -1,
|
|
length = collection ? collection.length : 0;
|
|
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
if (typeof length == 'number') {
|
|
var result = Array(length);
|
|
while (++index < length) {
|
|
result[index] = callback(collection[index], index, collection);
|
|
}
|
|
} else {
|
|
result = [];
|
|
forOwn(collection, function(value, key, collection) {
|
|
result[++index] = callback(value, key, collection);
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Retrieves the maximum value of an `array`. If `callback` is passed,
|
|
* it will be executed for each value in the `array` to generate the
|
|
* criterion by which the value is ranked. The `callback` is bound to
|
|
* `thisArg` and invoked with three arguments; (value, index, collection).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Mixed} Returns the maximum value.
|
|
* @example
|
|
*
|
|
* _.max([4, 2, 8, 6]);
|
|
* // => 8
|
|
*
|
|
* var stooges = [
|
|
* { 'name': 'moe', 'age': 40 },
|
|
* { 'name': 'larry', 'age': 50 }
|
|
* ];
|
|
*
|
|
* _.max(stooges, function(stooge) { return stooge.age; });
|
|
* // => { 'name': 'larry', 'age': 50 };
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.max(stooges, 'age');
|
|
* // => { 'name': 'larry', 'age': 50 };
|
|
*/
|
|
function max(collection, callback, thisArg) {
|
|
var computed = -Infinity,
|
|
result = computed;
|
|
|
|
if (!callback && isArray(collection)) {
|
|
var index = -1,
|
|
length = collection.length;
|
|
|
|
while (++index < length) {
|
|
var value = collection[index];
|
|
if (value > result) {
|
|
result = value;
|
|
}
|
|
}
|
|
} else {
|
|
callback = (!callback && isString(collection))
|
|
? charAtCallback
|
|
: lodash.createCallback(callback, thisArg);
|
|
|
|
forEach(collection, function(value, index, collection) {
|
|
var current = callback(value, index, collection);
|
|
if (current > computed) {
|
|
computed = current;
|
|
result = value;
|
|
}
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Retrieves the minimum value of an `array`. If `callback` is passed,
|
|
* it will be executed for each value in the `array` to generate the
|
|
* criterion by which the value is ranked. The `callback` is bound to `thisArg`
|
|
* and invoked with three arguments; (value, index, collection).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Mixed} Returns the minimum value.
|
|
* @example
|
|
*
|
|
* _.min([4, 2, 8, 6]);
|
|
* // => 2
|
|
*
|
|
* var stooges = [
|
|
* { 'name': 'moe', 'age': 40 },
|
|
* { 'name': 'larry', 'age': 50 }
|
|
* ];
|
|
*
|
|
* _.min(stooges, function(stooge) { return stooge.age; });
|
|
* // => { 'name': 'moe', 'age': 40 };
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.min(stooges, 'age');
|
|
* // => { 'name': 'moe', 'age': 40 };
|
|
*/
|
|
function min(collection, callback, thisArg) {
|
|
var computed = Infinity,
|
|
result = computed;
|
|
|
|
if (!callback && isArray(collection)) {
|
|
var index = -1,
|
|
length = collection.length;
|
|
|
|
while (++index < length) {
|
|
var value = collection[index];
|
|
if (value < result) {
|
|
result = value;
|
|
}
|
|
}
|
|
} else {
|
|
callback = (!callback && isString(collection))
|
|
? charAtCallback
|
|
: lodash.createCallback(callback, thisArg);
|
|
|
|
forEach(collection, function(value, index, collection) {
|
|
var current = callback(value, index, collection);
|
|
if (current < computed) {
|
|
computed = current;
|
|
result = value;
|
|
}
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Retrieves the value of a specified property from all elements in the `collection`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @type Function
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {String} property The property to pluck.
|
|
* @returns {Array} Returns a new array of property values.
|
|
* @example
|
|
*
|
|
* var stooges = [
|
|
* { 'name': 'moe', 'age': 40 },
|
|
* { 'name': 'larry', 'age': 50 }
|
|
* ];
|
|
*
|
|
* _.pluck(stooges, 'name');
|
|
* // => ['moe', 'larry']
|
|
*/
|
|
function pluck(collection, property) {
|
|
var index = -1,
|
|
length = collection ? collection.length : 0;
|
|
|
|
if (typeof length == 'number') {
|
|
var result = Array(length);
|
|
while (++index < length) {
|
|
result[index] = collection[index][property];
|
|
}
|
|
}
|
|
return result || map(collection, property);
|
|
}
|
|
|
|
/**
|
|
* Reduces a `collection` to a value which is the accumulated result of running
|
|
* each element in the `collection` through the `callback`, where each successive
|
|
* `callback` execution consumes the return value of the previous execution.
|
|
* If `accumulator` is not passed, the first element of the `collection` will be
|
|
* used as the initial `accumulator` value. The `callback` is bound to `thisArg`
|
|
* and invoked with four arguments; (accumulator, value, index|key, collection).
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias foldl, inject
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function} [callback=identity] The function called per iteration.
|
|
* @param {Mixed} [accumulator] Initial value of the accumulator.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Mixed} Returns the accumulated value.
|
|
* @example
|
|
*
|
|
* var sum = _.reduce([1, 2, 3], function(sum, num) {
|
|
* return sum + num;
|
|
* });
|
|
* // => 6
|
|
*
|
|
* var mapped = _.reduce({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
|
|
* result[key] = num * 3;
|
|
* return result;
|
|
* }, {});
|
|
* // => { 'a': 3, 'b': 6, 'c': 9 }
|
|
*/
|
|
function reduce(collection, callback, accumulator, thisArg) {
|
|
if (!collection) return accumulator;
|
|
var noaccum = arguments.length < 3;
|
|
callback = lodash.createCallback(callback, thisArg, 4);
|
|
|
|
var index = -1,
|
|
length = collection.length;
|
|
|
|
if (typeof length == 'number') {
|
|
if (noaccum) {
|
|
accumulator = collection[++index];
|
|
}
|
|
while (++index < length) {
|
|
accumulator = callback(accumulator, collection[index], index, collection);
|
|
}
|
|
} else {
|
|
forOwn(collection, function(value, index, collection) {
|
|
accumulator = noaccum
|
|
? (noaccum = false, value)
|
|
: callback(accumulator, value, index, collection)
|
|
});
|
|
}
|
|
return accumulator;
|
|
}
|
|
|
|
/**
|
|
* This method is similar to `_.reduce`, except that it iterates over a
|
|
* `collection` from right to left.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias foldr
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function} [callback=identity] The function called per iteration.
|
|
* @param {Mixed} [accumulator] Initial value of the accumulator.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Mixed} Returns the accumulated value.
|
|
* @example
|
|
*
|
|
* var list = [[0, 1], [2, 3], [4, 5]];
|
|
* var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []);
|
|
* // => [4, 5, 2, 3, 0, 1]
|
|
*/
|
|
function reduceRight(collection, callback, accumulator, thisArg) {
|
|
var iterable = collection,
|
|
length = collection ? collection.length : 0,
|
|
noaccum = arguments.length < 3;
|
|
|
|
if (typeof length != 'number') {
|
|
var props = keys(collection);
|
|
length = props.length;
|
|
}
|
|
callback = lodash.createCallback(callback, thisArg, 4);
|
|
forEach(collection, function(value, index, collection) {
|
|
index = props ? props[--length] : --length;
|
|
accumulator = noaccum
|
|
? (noaccum = false, iterable[index])
|
|
: callback(accumulator, iterable[index], index, collection);
|
|
});
|
|
return accumulator;
|
|
}
|
|
|
|
/**
|
|
* The opposite of `_.filter`, this method returns the elements of a
|
|
* `collection` that `callback` does **not** return truthy for.
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Array} Returns a new array of elements that did **not** pass the
|
|
* callback check.
|
|
* @example
|
|
*
|
|
* var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
|
|
* // => [1, 3, 5]
|
|
*
|
|
* var food = [
|
|
* { 'name': 'apple', 'organic': false, 'type': 'fruit' },
|
|
* { 'name': 'carrot', 'organic': true, 'type': 'vegetable' }
|
|
* ];
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.reject(food, 'organic');
|
|
* // => [{ 'name': 'apple', 'organic': false, 'type': 'fruit' }]
|
|
*
|
|
* // using "_.where" callback shorthand
|
|
* _.reject(food, { 'type': 'fruit' });
|
|
* // => [{ 'name': 'carrot', 'organic': true, 'type': 'vegetable' }]
|
|
*/
|
|
function reject(collection, callback, thisArg) {
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
return filter(collection, function(value, index, collection) {
|
|
return !callback(value, index, collection);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Creates an array of shuffled `array` values, using a version of the
|
|
* Fisher-Yates shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to shuffle.
|
|
* @returns {Array} Returns a new shuffled collection.
|
|
* @example
|
|
*
|
|
* _.shuffle([1, 2, 3, 4, 5, 6]);
|
|
* // => [4, 1, 6, 3, 5, 2]
|
|
*/
|
|
function shuffle(collection) {
|
|
var index = -1,
|
|
length = collection ? collection.length : 0,
|
|
result = Array(typeof length == 'number' ? length : 0);
|
|
|
|
forEach(collection, function(value) {
|
|
var rand = floor(nativeRandom() * (++index + 1));
|
|
result[index] = result[rand];
|
|
result[rand] = value;
|
|
});
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Gets the size of the `collection` by returning `collection.length` for arrays
|
|
* and array-like objects or the number of own enumerable properties for objects.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to inspect.
|
|
* @returns {Number} Returns `collection.length` or number of own enumerable properties.
|
|
* @example
|
|
*
|
|
* _.size([1, 2]);
|
|
* // => 2
|
|
*
|
|
* _.size({ 'one': 1, 'two': 2, 'three': 3 });
|
|
* // => 3
|
|
*
|
|
* _.size('curly');
|
|
* // => 5
|
|
*/
|
|
function size(collection) {
|
|
var length = collection ? collection.length : 0;
|
|
return typeof length == 'number' ? length : keys(collection).length;
|
|
}
|
|
|
|
/**
|
|
* Checks if the `callback` returns a truthy value for **any** element of a
|
|
* `collection`. The function returns as soon as it finds passing value, and
|
|
* does not iterate over the entire `collection`. The `callback` is bound to
|
|
* `thisArg` and invoked with three arguments; (value, index|key, collection).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias any
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Boolean} Returns `true` if any element passes the callback check,
|
|
* else `false`.
|
|
* @example
|
|
*
|
|
* _.some([null, 0, 'yes', false], Boolean);
|
|
* // => true
|
|
*
|
|
* var food = [
|
|
* { 'name': 'apple', 'organic': false, 'type': 'fruit' },
|
|
* { 'name': 'carrot', 'organic': true, 'type': 'vegetable' }
|
|
* ];
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.some(food, 'organic');
|
|
* // => true
|
|
*
|
|
* // using "_.where" callback shorthand
|
|
* _.some(food, { 'type': 'meat' });
|
|
* // => false
|
|
*/
|
|
function some(collection, callback, thisArg) {
|
|
var result;
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
|
|
var index = -1,
|
|
length = collection ? collection.length : 0;
|
|
|
|
if (typeof length == 'number') {
|
|
while (++index < length) {
|
|
if ((result = callback(collection[index], index, collection))) {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
forOwn(collection, function(value, index, collection) {
|
|
return !(result = callback(value, index, collection));
|
|
});
|
|
}
|
|
return !!result;
|
|
}
|
|
|
|
/**
|
|
* Creates an array of elements, sorted in ascending order by the results of
|
|
* running each element in the `collection` through the `callback`. This method
|
|
* performs a stable sort, that is, it will preserve the original sort order of
|
|
* equal elements. The `callback` is bound to `thisArg` and invoked with three
|
|
* arguments; (value, index|key, collection).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Array} Returns a new array of sorted elements.
|
|
* @example
|
|
*
|
|
* _.sortBy([1, 2, 3], function(num) { return Math.sin(num); });
|
|
* // => [3, 1, 2]
|
|
*
|
|
* _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math);
|
|
* // => [3, 1, 2]
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.sortBy(['banana', 'strawberry', 'apple'], 'length');
|
|
* // => ['apple', 'banana', 'strawberry']
|
|
*/
|
|
function sortBy(collection, callback, thisArg) {
|
|
var index = -1,
|
|
length = collection ? collection.length : 0,
|
|
result = Array(typeof length == 'number' ? length : 0);
|
|
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
forEach(collection, function(value, key, collection) {
|
|
var object = result[++index] = getObject();
|
|
object.criteria = callback(value, key, collection);
|
|
object.index = index;
|
|
object.value = value;
|
|
});
|
|
|
|
length = result.length;
|
|
result.sort(compareAscending);
|
|
while (length--) {
|
|
var object = result[length];
|
|
result[length] = object.value;
|
|
releaseObject(object);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Converts the `collection` to an array.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to convert.
|
|
* @returns {Array} Returns the new converted array.
|
|
* @example
|
|
*
|
|
* (function() { return _.toArray(arguments).slice(1); })(1, 2, 3, 4);
|
|
* // => [2, 3, 4]
|
|
*/
|
|
function toArray(collection) {
|
|
if (collection && typeof collection.length == 'number') {
|
|
return slice(collection);
|
|
}
|
|
return values(collection);
|
|
}
|
|
|
|
/**
|
|
* Examines each element in a `collection`, returning an array of all elements
|
|
* that have the given `properties`. When checking `properties`, this method
|
|
* performs a deep comparison between values to determine if they are equivalent
|
|
* to each other.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @type Function
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Object} properties The object of property values to filter by.
|
|
* @returns {Array} Returns a new array of elements that have the given `properties`.
|
|
* @example
|
|
*
|
|
* var stooges = [
|
|
* { 'name': 'moe', 'age': 40 },
|
|
* { 'name': 'larry', 'age': 50 }
|
|
* ];
|
|
*
|
|
* _.where(stooges, { 'age': 40 });
|
|
* // => [{ 'name': 'moe', 'age': 40 }]
|
|
*/
|
|
var where = filter;
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Creates an array with all falsey values of `array` removed. The values
|
|
* `false`, `null`, `0`, `""`, `undefined` and `NaN` are all falsey.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} array The array to compact.
|
|
* @returns {Array} Returns a new filtered array.
|
|
* @example
|
|
*
|
|
* _.compact([0, 1, false, 2, '', 3]);
|
|
* // => [1, 2, 3]
|
|
*/
|
|
function compact(array) {
|
|
var index = -1,
|
|
length = array ? array.length : 0,
|
|
result = [];
|
|
|
|
while (++index < length) {
|
|
var value = array[index];
|
|
if (value) {
|
|
result.push(value);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Creates an array of `array` elements not present in the other arrays
|
|
* using strict equality for comparisons, i.e. `===`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} array The array to process.
|
|
* @param {Array} [array1, array2, ...] Arrays to check.
|
|
* @returns {Array} Returns a new array of `array` elements not present in the
|
|
* other arrays.
|
|
* @example
|
|
*
|
|
* _.difference([1, 2, 3, 4, 5], [5, 2, 10]);
|
|
* // => [1, 3, 4]
|
|
*/
|
|
function difference(array) {
|
|
var index = -1,
|
|
indexOf = getIndexOf(),
|
|
length = array ? array.length : 0,
|
|
seen = concat.apply(arrayRef, nativeSlice.call(arguments, 1)),
|
|
result = [];
|
|
|
|
var isLarge = length >= largeArraySize && indexOf === basicIndexOf;
|
|
|
|
if (isLarge) {
|
|
var cache = createCache(seen);
|
|
if (cache) {
|
|
indexOf = cacheIndexOf;
|
|
seen = cache;
|
|
} else {
|
|
isLarge = false;
|
|
}
|
|
}
|
|
while (++index < length) {
|
|
var value = array[index];
|
|
if (indexOf(seen, value) < 0) {
|
|
result.push(value);
|
|
}
|
|
}
|
|
if (isLarge) {
|
|
releaseObject(seen);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* This method is similar to `_.find`, except that it returns the index of
|
|
* the element that passes the callback check, instead of the element itself.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} array The array to search.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Mixed} Returns the index of the found element, else `-1`.
|
|
* @example
|
|
*
|
|
* _.findIndex(['apple', 'banana', 'beet'], function(food) {
|
|
* return /^b/.test(food);
|
|
* });
|
|
* // => 1
|
|
*/
|
|
function findIndex(array, callback, thisArg) {
|
|
var index = -1,
|
|
length = array ? array.length : 0;
|
|
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
while (++index < length) {
|
|
if (callback(array[index], index, array)) {
|
|
return index;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* Gets the first element of the `array`. If a number `n` is passed, the first
|
|
* `n` elements of the `array` are returned. If a `callback` function is passed,
|
|
* elements at the beginning of the array are returned as long as the `callback`
|
|
* returns truthy. The `callback` is bound to `thisArg` and invoked with three
|
|
* arguments; (value, index, array).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias head, take
|
|
* @category Arrays
|
|
* @param {Array} array The array to query.
|
|
* @param {Function|Object|Number|String} [callback|n] The function called
|
|
* per element or the number of elements to return. If a property name or
|
|
* object is passed, it will be used to create a "_.pluck" or "_.where"
|
|
* style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Mixed} Returns the first element(s) of `array`.
|
|
* @example
|
|
*
|
|
* _.first([1, 2, 3]);
|
|
* // => 1
|
|
*
|
|
* _.first([1, 2, 3], 2);
|
|
* // => [1, 2]
|
|
*
|
|
* _.first([1, 2, 3], function(num) {
|
|
* return num < 3;
|
|
* });
|
|
* // => [1, 2]
|
|
*
|
|
* var food = [
|
|
* { 'name': 'banana', 'organic': true },
|
|
* { 'name': 'beet', 'organic': false },
|
|
* ];
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.first(food, 'organic');
|
|
* // => [{ 'name': 'banana', 'organic': true }]
|
|
*
|
|
* var food = [
|
|
* { 'name': 'apple', 'type': 'fruit' },
|
|
* { 'name': 'banana', 'type': 'fruit' },
|
|
* { 'name': 'beet', 'type': 'vegetable' }
|
|
* ];
|
|
*
|
|
* // using "_.where" callback shorthand
|
|
* _.first(food, { 'type': 'fruit' });
|
|
* // => [{ 'name': 'apple', 'type': 'fruit' }, { 'name': 'banana', 'type': 'fruit' }]
|
|
*/
|
|
function first(array, callback, thisArg) {
|
|
if (array) {
|
|
var n = 0,
|
|
length = array.length;
|
|
|
|
if (typeof callback != 'number' && callback != null) {
|
|
var index = -1;
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
while (++index < length && callback(array[index], index, array)) {
|
|
n++;
|
|
}
|
|
} else {
|
|
n = callback;
|
|
if (n == null || thisArg) {
|
|
return array[0];
|
|
}
|
|
}
|
|
return slice(array, 0, nativeMin(nativeMax(0, n), length));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Flattens a nested array (the nesting can be to any depth). If `isShallow`
|
|
* is truthy, `array` will only be flattened a single level. If `callback`
|
|
* is passed, each element of `array` is passed through a `callback` before
|
|
* flattening. The `callback` is bound to `thisArg` and invoked with three
|
|
* arguments; (value, index, array).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} array The array to flatten.
|
|
* @param {Boolean} [isShallow=false] A flag to indicate only flattening a single level.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Array} Returns a new flattened array.
|
|
* @example
|
|
*
|
|
* _.flatten([1, [2], [3, [[4]]]]);
|
|
* // => [1, 2, 3, 4];
|
|
*
|
|
* _.flatten([1, [2], [3, [[4]]]], true);
|
|
* // => [1, 2, 3, [[4]]];
|
|
*
|
|
* var stooges = [
|
|
* { 'name': 'curly', 'quotes': ['Oh, a wise guy, eh?', 'Poifect!'] },
|
|
* { 'name': 'moe', 'quotes': ['Spread out!', 'You knucklehead!'] }
|
|
* ];
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.flatten(stooges, 'quotes');
|
|
* // => ['Oh, a wise guy, eh?', 'Poifect!', 'Spread out!', 'You knucklehead!']
|
|
*/
|
|
var flatten = overloadWrapper(function flatten(array, isShallow, callback) {
|
|
var index = -1,
|
|
length = array ? array.length : 0,
|
|
result = [];
|
|
|
|
while (++index < length) {
|
|
var value = array[index];
|
|
if (callback) {
|
|
value = callback(value, index, array);
|
|
}
|
|
// recursively flatten arrays (susceptible to call stack limits)
|
|
if (isArray(value)) {
|
|
push.apply(result, isShallow ? value : flatten(value));
|
|
} else {
|
|
result.push(value);
|
|
}
|
|
}
|
|
return result;
|
|
});
|
|
|
|
/**
|
|
* Gets the index at which the first occurrence of `value` is found using
|
|
* strict equality for comparisons, i.e. `===`. If the `array` is already
|
|
* sorted, passing `true` for `fromIndex` will run a faster binary search.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} array The array to search.
|
|
* @param {Mixed} value The value to search for.
|
|
* @param {Boolean|Number} [fromIndex=0] The index to search from or `true` to
|
|
* perform a binary search on a sorted `array`.
|
|
* @returns {Number} Returns the index of the matched value or `-1`.
|
|
* @example
|
|
*
|
|
* _.indexOf([1, 2, 3, 1, 2, 3], 2);
|
|
* // => 1
|
|
*
|
|
* _.indexOf([1, 2, 3, 1, 2, 3], 2, 3);
|
|
* // => 4
|
|
*
|
|
* _.indexOf([1, 1, 2, 2, 3, 3], 2, true);
|
|
* // => 2
|
|
*/
|
|
function indexOf(array, value, fromIndex) {
|
|
if (typeof fromIndex == 'number') {
|
|
var length = array ? array.length : 0;
|
|
fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0);
|
|
} else if (fromIndex) {
|
|
var index = sortedIndex(array, value);
|
|
return array[index] === value ? index : -1;
|
|
}
|
|
return array ? basicIndexOf(array, value, fromIndex) : -1;
|
|
}
|
|
|
|
/**
|
|
* Gets all but the last element of `array`. If a number `n` is passed, the
|
|
* last `n` elements are excluded from the result. If a `callback` function
|
|
* is passed, elements at the end of the array are excluded from the result
|
|
* as long as the `callback` returns truthy. The `callback` is bound to
|
|
* `thisArg` and invoked with three arguments; (value, index, array).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} array The array to query.
|
|
* @param {Function|Object|Number|String} [callback|n=1] The function called
|
|
* per element or the number of elements to exclude. If a property name or
|
|
* object is passed, it will be used to create a "_.pluck" or "_.where"
|
|
* style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Array} Returns a slice of `array`.
|
|
* @example
|
|
*
|
|
* _.initial([1, 2, 3]);
|
|
* // => [1, 2]
|
|
*
|
|
* _.initial([1, 2, 3], 2);
|
|
* // => [1]
|
|
*
|
|
* _.initial([1, 2, 3], function(num) {
|
|
* return num > 1;
|
|
* });
|
|
* // => [1]
|
|
*
|
|
* var food = [
|
|
* { 'name': 'beet', 'organic': false },
|
|
* { 'name': 'carrot', 'organic': true }
|
|
* ];
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.initial(food, 'organic');
|
|
* // => [{ 'name': 'beet', 'organic': false }]
|
|
*
|
|
* var food = [
|
|
* { 'name': 'banana', 'type': 'fruit' },
|
|
* { 'name': 'beet', 'type': 'vegetable' },
|
|
* { 'name': 'carrot', 'type': 'vegetable' }
|
|
* ];
|
|
*
|
|
* // using "_.where" callback shorthand
|
|
* _.initial(food, { 'type': 'vegetable' });
|
|
* // => [{ 'name': 'banana', 'type': 'fruit' }]
|
|
*/
|
|
function initial(array, callback, thisArg) {
|
|
if (!array) {
|
|
return [];
|
|
}
|
|
var n = 0,
|
|
length = array.length;
|
|
|
|
if (typeof callback != 'number' && callback != null) {
|
|
var index = length;
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
while (index-- && callback(array[index], index, array)) {
|
|
n++;
|
|
}
|
|
} else {
|
|
n = (callback == null || thisArg) ? 1 : callback || n;
|
|
}
|
|
return slice(array, 0, nativeMin(nativeMax(0, length - n), length));
|
|
}
|
|
|
|
/**
|
|
* Computes the intersection of all the passed-in arrays using strict equality
|
|
* for comparisons, i.e. `===`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} [array1, array2, ...] Arrays to process.
|
|
* @returns {Array} Returns a new array of unique elements that are present
|
|
* in **all** of the arrays.
|
|
* @example
|
|
*
|
|
* _.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]);
|
|
* // => [1, 2]
|
|
*/
|
|
function intersection(array) {
|
|
var args = arguments,
|
|
argsLength = args.length,
|
|
argsIndex = -1,
|
|
caches = getArray(),
|
|
index = -1,
|
|
indexOf = getIndexOf(),
|
|
length = array ? array.length : 0,
|
|
result = [],
|
|
seen = getArray();
|
|
|
|
while (++argsIndex < argsLength) {
|
|
var value = args[argsIndex];
|
|
caches[argsIndex] = indexOf === basicIndexOf &&
|
|
(value ? value.length : 0) >= largeArraySize &&
|
|
createCache(argsIndex ? args[argsIndex] : seen);
|
|
}
|
|
outer:
|
|
while (++index < length) {
|
|
var cache = caches[0];
|
|
value = array[index];
|
|
|
|
if ((cache ? cacheIndexOf(cache, value) : indexOf(seen, value)) < 0) {
|
|
argsIndex = argsLength;
|
|
(cache || seen).push(value);
|
|
while (--argsIndex) {
|
|
cache = caches[argsIndex];
|
|
if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value)) < 0) {
|
|
continue outer;
|
|
}
|
|
}
|
|
result.push(value);
|
|
}
|
|
}
|
|
while (argsLength--) {
|
|
cache = caches[argsLength];
|
|
if (cache) {
|
|
releaseObject(cache);
|
|
}
|
|
}
|
|
releaseArray(caches);
|
|
releaseArray(seen);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Gets the last element of the `array`. If a number `n` is passed, the
|
|
* last `n` elements of the `array` are returned. If a `callback` function
|
|
* is passed, elements at the end of the array are returned as long as the
|
|
* `callback` returns truthy. The `callback` is bound to `thisArg` and
|
|
* invoked with three arguments;(value, index, array).
|
|
*
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} array The array to query.
|
|
* @param {Function|Object|Number|String} [callback|n] The function called
|
|
* per element or the number of elements to return. If a property name or
|
|
* object is passed, it will be used to create a "_.pluck" or "_.where"
|
|
* style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Mixed} Returns the last element(s) of `array`.
|
|
* @example
|
|
*
|
|
* _.last([1, 2, 3]);
|
|
* // => 3
|
|
*
|
|
* _.last([1, 2, 3], 2);
|
|
* // => [2, 3]
|
|
*
|
|
* _.last([1, 2, 3], function(num) {
|
|
* return num > 1;
|
|
* });
|
|
* // => [2, 3]
|
|
*
|
|
* var food = [
|
|
* { 'name': 'beet', 'organic': false },
|
|
* { 'name': 'carrot', 'organic': true }
|
|
* ];
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.last(food, 'organic');
|
|
* // => [{ 'name': 'carrot', 'organic': true }]
|
|
*
|
|
* var food = [
|
|
* { 'name': 'banana', 'type': 'fruit' },
|
|
* { 'name': 'beet', 'type': 'vegetable' },
|
|
* { 'name': 'carrot', 'type': 'vegetable' }
|
|
* ];
|
|
*
|
|
* // using "_.where" callback shorthand
|
|
* _.last(food, { 'type': 'vegetable' });
|
|
* // => [{ 'name': 'beet', 'type': 'vegetable' }, { 'name': 'carrot', 'type': 'vegetable' }]
|
|
*/
|
|
function last(array, callback, thisArg) {
|
|
if (array) {
|
|
var n = 0,
|
|
length = array.length;
|
|
|
|
if (typeof callback != 'number' && callback != null) {
|
|
var index = length;
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
while (index-- && callback(array[index], index, array)) {
|
|
n++;
|
|
}
|
|
} else {
|
|
n = callback;
|
|
if (n == null || thisArg) {
|
|
return array[length - 1];
|
|
}
|
|
}
|
|
return slice(array, nativeMax(0, length - n));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets the index at which the last occurrence of `value` is found using strict
|
|
* equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used
|
|
* as the offset from the end of the collection.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} array The array to search.
|
|
* @param {Mixed} value The value to search for.
|
|
* @param {Number} [fromIndex=array.length-1] The index to search from.
|
|
* @returns {Number} Returns the index of the matched value or `-1`.
|
|
* @example
|
|
*
|
|
* _.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
|
|
* // => 4
|
|
*
|
|
* _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3);
|
|
* // => 1
|
|
*/
|
|
function lastIndexOf(array, value, fromIndex) {
|
|
var index = array ? array.length : 0;
|
|
if (typeof fromIndex == 'number') {
|
|
index = (fromIndex < 0 ? nativeMax(0, index + fromIndex) : nativeMin(fromIndex, index - 1)) + 1;
|
|
}
|
|
while (index--) {
|
|
if (array[index] === value) {
|
|
return index;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* Creates an array of numbers (positive and/or negative) progressing from
|
|
* `start` up to but not including `end`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Number} [start=0] The start of the range.
|
|
* @param {Number} end The end of the range.
|
|
* @param {Number} [step=1] The value to increment or decrement by.
|
|
* @returns {Array} Returns a new range array.
|
|
* @example
|
|
*
|
|
* _.range(10);
|
|
* // => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
*
|
|
* _.range(1, 11);
|
|
* // => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
|
*
|
|
* _.range(0, 30, 5);
|
|
* // => [0, 5, 10, 15, 20, 25]
|
|
*
|
|
* _.range(0, -10, -1);
|
|
* // => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
|
|
*
|
|
* _.range(0);
|
|
* // => []
|
|
*/
|
|
function range(start, end, step) {
|
|
start = +start || 0;
|
|
step = +step || 1;
|
|
|
|
if (end == null) {
|
|
end = start;
|
|
start = 0;
|
|
}
|
|
// use `Array(length)` so V8 will avoid the slower "dictionary" mode
|
|
// http://youtu.be/XAqIpGU8ZZk#t=17m25s
|
|
var index = -1,
|
|
length = nativeMax(0, ceil((end - start) / step)),
|
|
result = Array(length);
|
|
|
|
while (++index < length) {
|
|
result[index] = start;
|
|
start += step;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* The opposite of `_.initial`, this method gets all but the first value of
|
|
* `array`. If a number `n` is passed, the first `n` values are excluded from
|
|
* the result. If a `callback` function is passed, elements at the beginning
|
|
* of the array are excluded from the result as long as the `callback` returns
|
|
* truthy. The `callback` is bound to `thisArg` and invoked with three
|
|
* arguments; (value, index, array).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias drop, tail
|
|
* @category Arrays
|
|
* @param {Array} array The array to query.
|
|
* @param {Function|Object|Number|String} [callback|n=1] The function called
|
|
* per element or the number of elements to exclude. If a property name or
|
|
* object is passed, it will be used to create a "_.pluck" or "_.where"
|
|
* style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Array} Returns a slice of `array`.
|
|
* @example
|
|
*
|
|
* _.rest([1, 2, 3]);
|
|
* // => [2, 3]
|
|
*
|
|
* _.rest([1, 2, 3], 2);
|
|
* // => [3]
|
|
*
|
|
* _.rest([1, 2, 3], function(num) {
|
|
* return num < 3;
|
|
* });
|
|
* // => [3]
|
|
*
|
|
* var food = [
|
|
* { 'name': 'banana', 'organic': true },
|
|
* { 'name': 'beet', 'organic': false },
|
|
* ];
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.rest(food, 'organic');
|
|
* // => [{ 'name': 'beet', 'organic': false }]
|
|
*
|
|
* var food = [
|
|
* { 'name': 'apple', 'type': 'fruit' },
|
|
* { 'name': 'banana', 'type': 'fruit' },
|
|
* { 'name': 'beet', 'type': 'vegetable' }
|
|
* ];
|
|
*
|
|
* // using "_.where" callback shorthand
|
|
* _.rest(food, { 'type': 'fruit' });
|
|
* // => [{ 'name': 'beet', 'type': 'vegetable' }]
|
|
*/
|
|
function rest(array, callback, thisArg) {
|
|
if (typeof callback != 'number' && callback != null) {
|
|
var n = 0,
|
|
index = -1,
|
|
length = array ? array.length : 0;
|
|
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
while (++index < length && callback(array[index], index, array)) {
|
|
n++;
|
|
}
|
|
} else {
|
|
n = (callback == null || thisArg) ? 1 : nativeMax(0, callback);
|
|
}
|
|
return slice(array, n);
|
|
}
|
|
|
|
/**
|
|
* Uses a binary search to determine the smallest index at which the `value`
|
|
* should be inserted into `array` in order to maintain the sort order of the
|
|
* sorted `array`. If `callback` is passed, it will be executed for `value` and
|
|
* each element in `array` to compute their sort ranking. The `callback` is
|
|
* bound to `thisArg` and invoked with one argument; (value).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} array The array to inspect.
|
|
* @param {Mixed} value The value to evaluate.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Number} Returns the index at which the value should be inserted
|
|
* into `array`.
|
|
* @example
|
|
*
|
|
* _.sortedIndex([20, 30, 50], 40);
|
|
* // => 2
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.sortedIndex([{ 'x': 20 }, { 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x');
|
|
* // => 2
|
|
*
|
|
* var dict = {
|
|
* 'wordToNumber': { 'twenty': 20, 'thirty': 30, 'fourty': 40, 'fifty': 50 }
|
|
* };
|
|
*
|
|
* _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
|
|
* return dict.wordToNumber[word];
|
|
* });
|
|
* // => 2
|
|
*
|
|
* _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
|
|
* return this.wordToNumber[word];
|
|
* }, dict);
|
|
* // => 2
|
|
*/
|
|
function sortedIndex(array, value, callback, thisArg) {
|
|
var low = 0,
|
|
high = array ? array.length : low;
|
|
|
|
// explicitly reference `identity` for better inlining in Firefox
|
|
callback = callback ? lodash.createCallback(callback, thisArg, 1) : identity;
|
|
value = callback(value);
|
|
|
|
while (low < high) {
|
|
var mid = (low + high) >>> 1;
|
|
(callback(array[mid]) < value)
|
|
? low = mid + 1
|
|
: high = mid;
|
|
}
|
|
return low;
|
|
}
|
|
|
|
/**
|
|
* Computes the union of the passed-in arrays using strict equality for
|
|
* comparisons, i.e. `===`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} [array1, array2, ...] Arrays to process.
|
|
* @returns {Array} Returns a new array of unique values, in order, that are
|
|
* present in one or more of the arrays.
|
|
* @example
|
|
*
|
|
* _.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);
|
|
* // => [1, 2, 3, 101, 10]
|
|
*/
|
|
function union(array) {
|
|
if (!isArray(array)) {
|
|
arguments[0] = array ? nativeSlice.call(array) : arrayRef;
|
|
}
|
|
return uniq(concat.apply(arrayRef, arguments));
|
|
}
|
|
|
|
/**
|
|
* Creates a duplicate-value-free version of the `array` using strict equality
|
|
* for comparisons, i.e. `===`. If the `array` is already sorted, passing `true`
|
|
* for `isSorted` will run a faster algorithm. If `callback` is passed, each
|
|
* element of `array` is passed through the `callback` before uniqueness is computed.
|
|
* The `callback` is bound to `thisArg` and invoked with three arguments; (value, index, array).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias unique
|
|
* @category Arrays
|
|
* @param {Array} array The array to process.
|
|
* @param {Boolean} [isSorted=false] A flag to indicate that the `array` is already sorted.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Array} Returns a duplicate-value-free array.
|
|
* @example
|
|
*
|
|
* _.uniq([1, 2, 1, 3, 1]);
|
|
* // => [1, 2, 3]
|
|
*
|
|
* _.uniq([1, 1, 2, 2, 3], true);
|
|
* // => [1, 2, 3]
|
|
*
|
|
* _.uniq(['A', 'b', 'C', 'a', 'B', 'c'], function(letter) { return letter.toLowerCase(); });
|
|
* // => ['A', 'b', 'C']
|
|
*
|
|
* _.uniq([1, 2.5, 3, 1.5, 2, 3.5], function(num) { return this.floor(num); }, Math);
|
|
* // => [1, 2.5, 3]
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
|
|
* // => [{ 'x': 1 }, { 'x': 2 }]
|
|
*/
|
|
var uniq = overloadWrapper(function(array, isSorted, callback) {
|
|
var index = -1,
|
|
indexOf = getIndexOf(),
|
|
length = array ? array.length : 0,
|
|
result = [];
|
|
|
|
var isLarge = !isSorted && length >= largeArraySize && indexOf === basicIndexOf,
|
|
seen = (callback || isLarge) ? getArray() : result;
|
|
|
|
if (isLarge) {
|
|
var cache = createCache(seen);
|
|
if (cache) {
|
|
indexOf = cacheIndexOf;
|
|
seen = cache;
|
|
} else {
|
|
isLarge = false;
|
|
seen = callback ? seen : (releaseArray(seen), result);
|
|
}
|
|
}
|
|
while (++index < length) {
|
|
var value = array[index],
|
|
computed = callback ? callback(value, index, array) : value;
|
|
|
|
if (isSorted
|
|
? !index || seen[seen.length - 1] !== computed
|
|
: indexOf(seen, computed) < 0
|
|
) {
|
|
if (callback || isLarge) {
|
|
seen.push(computed);
|
|
}
|
|
result.push(value);
|
|
}
|
|
}
|
|
if (isLarge) {
|
|
releaseArray(seen.array);
|
|
releaseObject(seen);
|
|
} else if (callback) {
|
|
releaseArray(seen);
|
|
}
|
|
return result;
|
|
});
|
|
|
|
/**
|
|
* The inverse of `_.zip`, this method splits groups of elements into arrays
|
|
* composed of elements from each group at their corresponding indexes.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} array The array to process.
|
|
* @returns {Array} Returns a new array of the composed arrays.
|
|
* @example
|
|
*
|
|
* _.unzip([['moe', 30, true], ['larry', 40, false]]);
|
|
* // => [['moe', 'larry'], [30, 40], [true, false]];
|
|
*/
|
|
function unzip(array) {
|
|
var index = -1,
|
|
length = array ? max(pluck(array, 'length')) : 0,
|
|
result = Array(length < 0 ? 0 : length);
|
|
|
|
while (++index < length) {
|
|
result[index] = pluck(array, index);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Creates an array with all occurrences of the passed values removed using
|
|
* strict equality for comparisons, i.e. `===`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} array The array to filter.
|
|
* @param {Mixed} [value1, value2, ...] Values to remove.
|
|
* @returns {Array} Returns a new filtered array.
|
|
* @example
|
|
*
|
|
* _.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
|
|
* // => [2, 3, 4]
|
|
*/
|
|
function without(array) {
|
|
return difference(array, nativeSlice.call(arguments, 1));
|
|
}
|
|
|
|
/**
|
|
* Groups the elements of each array at their corresponding indexes. Useful for
|
|
* separate data sources that are coordinated through matching array indexes.
|
|
* For a matrix of nested arrays, `_.zip.apply(...)` can transpose the matrix
|
|
* in a similar fashion.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} [array1, array2, ...] Arrays to process.
|
|
* @returns {Array} Returns a new array of grouped elements.
|
|
* @example
|
|
*
|
|
* _.zip(['moe', 'larry'], [30, 40], [true, false]);
|
|
* // => [['moe', 30, true], ['larry', 40, false]]
|
|
*/
|
|
function zip(array) {
|
|
return array ? unzip(arguments) : [];
|
|
}
|
|
|
|
/**
|
|
* Creates an object composed from arrays of `keys` and `values`. Pass either
|
|
* a single two dimensional array, i.e. `[[key1, value1], [key2, value2]]`, or
|
|
* two arrays, one of `keys` and one of corresponding `values`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias object
|
|
* @category Arrays
|
|
* @param {Array} keys The array of keys.
|
|
* @param {Array} [values=[]] The array of values.
|
|
* @returns {Object} Returns an object composed of the given keys and
|
|
* corresponding values.
|
|
* @example
|
|
*
|
|
* _.zipObject(['moe', 'larry'], [30, 40]);
|
|
* // => { 'moe': 30, 'larry': 40 }
|
|
*/
|
|
function zipObject(keys, values) {
|
|
var index = -1,
|
|
length = keys ? keys.length : 0,
|
|
result = {};
|
|
|
|
while (++index < length) {
|
|
var key = keys[index];
|
|
if (values) {
|
|
result[key] = values[index];
|
|
} else {
|
|
result[key[0]] = key[1];
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* If `n` is greater than `0`, a function is created that is restricted to
|
|
* executing `func`, with the `this` binding and arguments of the created
|
|
* function, only after it is called `n` times. If `n` is less than `1`,
|
|
* `func` is executed immediately, without a `this` binding or additional
|
|
* arguments, and its result is returned.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Number} n The number of times the function must be called before
|
|
* it is executed.
|
|
* @param {Function} func The function to restrict.
|
|
* @returns {Function} Returns the new restricted function.
|
|
* @example
|
|
*
|
|
* var renderNotes = _.after(notes.length, render);
|
|
* _.forEach(notes, function(note) {
|
|
* note.asyncSave({ 'success': renderNotes });
|
|
* });
|
|
* // `renderNotes` is run once, after all notes have saved
|
|
*/
|
|
function after(n, func) {
|
|
if (n < 1) {
|
|
return func();
|
|
}
|
|
return function() {
|
|
if (--n < 1) {
|
|
return func.apply(this, arguments);
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Creates a function that, when called, invokes `func` with the `this`
|
|
* binding of `thisArg` and prepends any additional `bind` arguments to those
|
|
* passed to the bound function.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Function} func The function to bind.
|
|
* @param {Mixed} [thisArg] The `this` binding of `func`.
|
|
* @param {Mixed} [arg1, arg2, ...] Arguments to be partially applied.
|
|
* @returns {Function} Returns the new bound function.
|
|
* @example
|
|
*
|
|
* var func = function(greeting) {
|
|
* return greeting + ' ' + this.name;
|
|
* };
|
|
*
|
|
* func = _.bind(func, { 'name': 'moe' }, 'hi');
|
|
* func();
|
|
* // => 'hi moe'
|
|
*/
|
|
function bind(func, thisArg) {
|
|
// use `Function#bind` if it exists and is fast
|
|
// (in V8 `Function#bind` is slower except when partially applied)
|
|
return support.fastBind || (nativeBind && arguments.length > 2)
|
|
? nativeBind.call.apply(nativeBind, arguments)
|
|
: createBound(func, thisArg, nativeSlice.call(arguments, 2));
|
|
}
|
|
|
|
/**
|
|
* Binds methods on `object` to `object`, overwriting the existing method.
|
|
* Method names may be specified as individual arguments or as arrays of method
|
|
* names. If no method names are provided, all the function properties of `object`
|
|
* will be bound.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Object} object The object to bind and assign the bound methods to.
|
|
* @param {String} [methodName1, methodName2, ...] Method names on the object to bind.
|
|
* @returns {Object} Returns `object`.
|
|
* @example
|
|
*
|
|
* var view = {
|
|
* 'label': 'docs',
|
|
* 'onClick': function() { alert('clicked ' + this.label); }
|
|
* };
|
|
*
|
|
* _.bindAll(view);
|
|
* jQuery('#docs').on('click', view.onClick);
|
|
* // => alerts 'clicked docs', when the button is clicked
|
|
*/
|
|
function bindAll(object) {
|
|
var funcs = arguments.length > 1 ? concat.apply(arrayRef, nativeSlice.call(arguments, 1)) : functions(object),
|
|
index = -1,
|
|
length = funcs.length;
|
|
|
|
while (++index < length) {
|
|
var key = funcs[index];
|
|
object[key] = bind(object[key], object);
|
|
}
|
|
return object;
|
|
}
|
|
|
|
/**
|
|
* Creates a function that, when called, invokes the method at `object[key]`
|
|
* and prepends any additional `bindKey` arguments to those passed to the bound
|
|
* function. This method differs from `_.bind` by allowing bound functions to
|
|
* reference methods that will be redefined or don't yet exist.
|
|
* See http://michaux.ca/articles/lazy-function-definition-pattern.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Object} object The object the method belongs to.
|
|
* @param {String} key The key of the method.
|
|
* @param {Mixed} [arg1, arg2, ...] Arguments to be partially applied.
|
|
* @returns {Function} Returns the new bound function.
|
|
* @example
|
|
*
|
|
* var object = {
|
|
* 'name': 'moe',
|
|
* 'greet': function(greeting) {
|
|
* return greeting + ' ' + this.name;
|
|
* }
|
|
* };
|
|
*
|
|
* var func = _.bindKey(object, 'greet', 'hi');
|
|
* func();
|
|
* // => 'hi moe'
|
|
*
|
|
* object.greet = function(greeting) {
|
|
* return greeting + ', ' + this.name + '!';
|
|
* };
|
|
*
|
|
* func();
|
|
* // => 'hi, moe!'
|
|
*/
|
|
function bindKey(object, key) {
|
|
return createBound(object, key, nativeSlice.call(arguments, 2), indicatorObject);
|
|
}
|
|
|
|
/**
|
|
* Creates a function that is the composition of the passed functions,
|
|
* where each function consumes the return value of the function that follows.
|
|
* For example, composing the functions `f()`, `g()`, and `h()` produces `f(g(h()))`.
|
|
* Each function is executed with the `this` binding of the composed function.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Function} [func1, func2, ...] Functions to compose.
|
|
* @returns {Function} Returns the new composed function.
|
|
* @example
|
|
*
|
|
* var greet = function(name) { return 'hi ' + name; };
|
|
* var exclaim = function(statement) { return statement + '!'; };
|
|
* var welcome = _.compose(exclaim, greet);
|
|
* welcome('moe');
|
|
* // => 'hi moe!'
|
|
*/
|
|
function compose() {
|
|
var funcs = arguments;
|
|
return function() {
|
|
var args = arguments,
|
|
length = funcs.length;
|
|
|
|
while (length--) {
|
|
args = [funcs[length].apply(this, args)];
|
|
}
|
|
return args[0];
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Produces a callback bound to an optional `thisArg`. If `func` is a property
|
|
* name, the created callback will return the property value for a given element.
|
|
* If `func` is an object, the created callback will return `true` for elements
|
|
* that contain the equivalent object properties, otherwise it will return `false`.
|
|
*
|
|
* Note: All Lo-Dash methods, that accept a `callback` argument, use `_.createCallback`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Mixed} [func=identity] The value to convert to a callback.
|
|
* @param {Mixed} [thisArg] The `this` binding of the created callback.
|
|
* @param {Number} [argCount=3] The number of arguments the callback accepts.
|
|
* @returns {Function} Returns a callback function.
|
|
* @example
|
|
*
|
|
* var stooges = [
|
|
* { 'name': 'moe', 'age': 40 },
|
|
* { 'name': 'larry', 'age': 50 }
|
|
* ];
|
|
*
|
|
* // wrap to create custom callback shorthands
|
|
* _.createCallback = _.wrap(_.createCallback, function(func, callback, thisArg) {
|
|
* var match = /^(.+?)__([gl]t)(.+)$/.exec(callback);
|
|
* return !match ? func(callback, thisArg) : function(object) {
|
|
* return match[2] == 'gt' ? object[match[1]] > match[3] : object[match[1]] < match[3];
|
|
* };
|
|
* });
|
|
*
|
|
* _.filter(stooges, 'age__gt45');
|
|
* // => [{ 'name': 'larry', 'age': 50 }]
|
|
*
|
|
* // create mixins with support for "_.pluck" and "_.where" callback shorthands
|
|
* _.mixin({
|
|
* 'toLookup': function(collection, callback, thisArg) {
|
|
* callback = _.createCallback(callback, thisArg);
|
|
* return _.reduce(collection, function(result, value, index, collection) {
|
|
* return (result[callback(value, index, collection)] = value, result);
|
|
* }, {});
|
|
* }
|
|
* });
|
|
*
|
|
* _.toLookup(stooges, 'name');
|
|
* // => { 'moe': { 'name': 'moe', 'age': 40 }, 'larry': { 'name': 'larry', 'age': 50 } }
|
|
*/
|
|
function createCallback(func, thisArg, argCount) {
|
|
if (func == null) {
|
|
return identity;
|
|
}
|
|
var type = typeof func;
|
|
if (type != 'function') {
|
|
if (type != 'object') {
|
|
return function(object) {
|
|
return object[func];
|
|
};
|
|
}
|
|
var props = keys(func);
|
|
return function(object) {
|
|
var length = props.length,
|
|
result = false;
|
|
while (length--) {
|
|
if (!(result = isEqual(object[props[length]], func[props[length]], indicatorObject))) {
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
};
|
|
}
|
|
if (typeof thisArg == 'undefined' || (reThis && !reThis.test(fnToString.call(func)))) {
|
|
return func;
|
|
}
|
|
if (argCount === 1) {
|
|
return function(value) {
|
|
return func.call(thisArg, value);
|
|
};
|
|
}
|
|
if (argCount === 2) {
|
|
return function(a, b) {
|
|
return func.call(thisArg, a, b);
|
|
};
|
|
}
|
|
if (argCount === 4) {
|
|
return function(accumulator, value, index, collection) {
|
|
return func.call(thisArg, accumulator, value, index, collection);
|
|
};
|
|
}
|
|
return function(value, index, collection) {
|
|
return func.call(thisArg, value, index, collection);
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Creates a function that will delay the execution of `func` until after
|
|
* `wait` milliseconds have elapsed since the last time it was invoked. Pass
|
|
* an `options` object to indicate that `func` should be invoked on the leading
|
|
* and/or trailing edge of the `wait` timeout. Subsequent calls to the debounced
|
|
* function will return the result of the last `func` call.
|
|
*
|
|
* Note: If `leading` and `trailing` options are `true`, `func` will be called
|
|
* on the trailing edge of the timeout only if the the debounced function is
|
|
* invoked more than once during the `wait` timeout.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Function} func The function to debounce.
|
|
* @param {Number} wait The number of milliseconds to delay.
|
|
* @param {Object} options The options object.
|
|
* [leading=false] A boolean to specify execution on the leading edge of the timeout.
|
|
* [maxWait] The maximum time `func` is allowed to be delayed before it's called.
|
|
* [trailing=true] A boolean to specify execution on the trailing edge of the timeout.
|
|
* @returns {Function} Returns the new debounced function.
|
|
* @example
|
|
*
|
|
* var lazyLayout = _.debounce(calculateLayout, 300);
|
|
* jQuery(window).on('resize', lazyLayout);
|
|
*
|
|
* jQuery('#postbox').on('click', _.debounce(sendMail, 200, {
|
|
* 'leading': true,
|
|
* 'trailing': false
|
|
* });
|
|
*/
|
|
function debounce(func, wait, options) {
|
|
var args,
|
|
result,
|
|
thisArg,
|
|
callCount = 0,
|
|
lastCalled = 0,
|
|
maxWait = false,
|
|
maxTimeoutId = null,
|
|
timeoutId = null,
|
|
trailing = true;
|
|
|
|
function clear() {
|
|
clearTimeout(maxTimeoutId);
|
|
clearTimeout(timeoutId);
|
|
callCount = 0;
|
|
maxTimeoutId = timeoutId = null;
|
|
}
|
|
|
|
function delayed() {
|
|
var isCalled = trailing && (!leading || callCount > 1);
|
|
clear();
|
|
if (isCalled) {
|
|
if (maxWait !== false) {
|
|
lastCalled = new Date;
|
|
}
|
|
result = func.apply(thisArg, args);
|
|
}
|
|
}
|
|
|
|
function maxDelayed() {
|
|
clear();
|
|
if (trailing || (maxWait !== wait)) {
|
|
lastCalled = new Date;
|
|
result = func.apply(thisArg, args);
|
|
}
|
|
}
|
|
|
|
wait = nativeMax(0, wait || 0);
|
|
if (options === true) {
|
|
var leading = true;
|
|
trailing = false;
|
|
} else if (isObject(options)) {
|
|
leading = options.leading;
|
|
maxWait = 'maxWait' in options && nativeMax(wait, options.maxWait || 0);
|
|
trailing = 'trailing' in options ? options.trailing : trailing;
|
|
}
|
|
return function() {
|
|
args = arguments;
|
|
thisArg = this;
|
|
callCount++;
|
|
|
|
// avoid issues with Titanium and `undefined` timeout ids
|
|
// https://github.com/appcelerator/titanium_mobile/blob/3_1_0_GA/android/titanium/src/java/ti/modules/titanium/TitaniumModule.java#L185-L192
|
|
clearTimeout(timeoutId);
|
|
|
|
if (maxWait === false) {
|
|
if (leading && callCount < 2) {
|
|
result = func.apply(thisArg, args);
|
|
}
|
|
} else {
|
|
var now = new Date;
|
|
if (!maxTimeoutId && !leading) {
|
|
lastCalled = now;
|
|
}
|
|
var remaining = maxWait - (now - lastCalled);
|
|
if (remaining <= 0) {
|
|
clearTimeout(maxTimeoutId);
|
|
maxTimeoutId = null;
|
|
lastCalled = now;
|
|
result = func.apply(thisArg, args);
|
|
}
|
|
else if (!maxTimeoutId) {
|
|
maxTimeoutId = setTimeout(maxDelayed, remaining);
|
|
}
|
|
}
|
|
if (wait !== maxWait) {
|
|
timeoutId = setTimeout(delayed, wait);
|
|
}
|
|
return result;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Defers executing the `func` function until the current call stack has cleared.
|
|
* Additional arguments will be passed to `func` when it is invoked.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Function} func The function to defer.
|
|
* @param {Mixed} [arg1, arg2, ...] Arguments to invoke the function with.
|
|
* @returns {Number} Returns the timer id.
|
|
* @example
|
|
*
|
|
* _.defer(function() { alert('deferred'); });
|
|
* // returns from the function before `alert` is called
|
|
*/
|
|
function defer(func) {
|
|
var args = nativeSlice.call(arguments, 1);
|
|
return setTimeout(function() { func.apply(undefined, args); }, 1);
|
|
}
|
|
// use `setImmediate` if it's available in Node.js
|
|
if (isV8 && freeModule && typeof setImmediate == 'function') {
|
|
defer = bind(setImmediate, context);
|
|
}
|
|
|
|
/**
|
|
* Executes the `func` function after `wait` milliseconds. Additional arguments
|
|
* will be passed to `func` when it is invoked.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Function} func The function to delay.
|
|
* @param {Number} wait The number of milliseconds to delay execution.
|
|
* @param {Mixed} [arg1, arg2, ...] Arguments to invoke the function with.
|
|
* @returns {Number} Returns the timer id.
|
|
* @example
|
|
*
|
|
* var log = _.bind(console.log, console);
|
|
* _.delay(log, 1000, 'logged later');
|
|
* // => 'logged later' (Appears after one second.)
|
|
*/
|
|
function delay(func, wait) {
|
|
var args = nativeSlice.call(arguments, 2);
|
|
return setTimeout(function() { func.apply(undefined, args); }, wait);
|
|
}
|
|
|
|
/**
|
|
* Creates a function that memoizes the result of `func`. If `resolver` is
|
|
* passed, it will be used to determine the cache key for storing the result
|
|
* based on the arguments passed to the memoized function. By default, the first
|
|
* argument passed to the memoized function is used as the cache key. The `func`
|
|
* is executed with the `this` binding of the memoized function. The result
|
|
* cache is exposed as the `cache` property on the memoized function.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Function} func The function to have its output memoized.
|
|
* @param {Function} [resolver] A function used to resolve the cache key.
|
|
* @returns {Function} Returns the new memoizing function.
|
|
* @example
|
|
*
|
|
* var fibonacci = _.memoize(function(n) {
|
|
* return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
|
|
* });
|
|
*/
|
|
function memoize(func, resolver) {
|
|
function memoized() {
|
|
var cache = memoized.cache,
|
|
key = keyPrefix + (resolver ? resolver.apply(this, arguments) : arguments[0]);
|
|
|
|
return hasOwnProperty.call(cache, key)
|
|
? cache[key]
|
|
: (cache[key] = func.apply(this, arguments));
|
|
}
|
|
memoized.cache = {};
|
|
return memoized;
|
|
}
|
|
|
|
/**
|
|
* Creates a function that is restricted to execute `func` once. Repeat calls to
|
|
* the function will return the value of the first call. The `func` is executed
|
|
* with the `this` binding of the created function.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Function} func The function to restrict.
|
|
* @returns {Function} Returns the new restricted function.
|
|
* @example
|
|
*
|
|
* var initialize = _.once(createApplication);
|
|
* initialize();
|
|
* initialize();
|
|
* // `initialize` executes `createApplication` once
|
|
*/
|
|
function once(func) {
|
|
var ran,
|
|
result;
|
|
|
|
return function() {
|
|
if (ran) {
|
|
return result;
|
|
}
|
|
ran = true;
|
|
result = func.apply(this, arguments);
|
|
|
|
// clear the `func` variable so the function may be garbage collected
|
|
func = null;
|
|
return result;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Creates a function that, when called, invokes `func` with any additional
|
|
* `partial` arguments prepended to those passed to the new function. This
|
|
* method is similar to `_.bind`, except it does **not** alter the `this` binding.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Function} func The function to partially apply arguments to.
|
|
* @param {Mixed} [arg1, arg2, ...] Arguments to be partially applied.
|
|
* @returns {Function} Returns the new partially applied function.
|
|
* @example
|
|
*
|
|
* var greet = function(greeting, name) { return greeting + ' ' + name; };
|
|
* var hi = _.partial(greet, 'hi');
|
|
* hi('moe');
|
|
* // => 'hi moe'
|
|
*/
|
|
function partial(func) {
|
|
return createBound(func, nativeSlice.call(arguments, 1));
|
|
}
|
|
|
|
/**
|
|
* This method is similar to `_.partial`, except that `partial` arguments are
|
|
* appended to those passed to the new function.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Function} func The function to partially apply arguments to.
|
|
* @param {Mixed} [arg1, arg2, ...] Arguments to be partially applied.
|
|
* @returns {Function} Returns the new partially applied function.
|
|
* @example
|
|
*
|
|
* var defaultsDeep = _.partialRight(_.merge, _.defaults);
|
|
*
|
|
* var options = {
|
|
* 'variable': 'data',
|
|
* 'imports': { 'jq': $ }
|
|
* };
|
|
*
|
|
* defaultsDeep(options, _.templateSettings);
|
|
*
|
|
* options.variable
|
|
* // => 'data'
|
|
*
|
|
* options.imports
|
|
* // => { '_': _, 'jq': $ }
|
|
*/
|
|
function partialRight(func) {
|
|
return createBound(func, nativeSlice.call(arguments, 1), null, indicatorObject);
|
|
}
|
|
|
|
/**
|
|
* Creates a function that, when executed, will only call the `func` function
|
|
* at most once per every `wait` milliseconds. Pass an `options` object to
|
|
* indicate that `func` should be invoked on the leading and/or trailing edge
|
|
* of the `wait` timeout. Subsequent calls to the throttled function will
|
|
* return the result of the last `func` call.
|
|
*
|
|
* Note: If `leading` and `trailing` options are `true`, `func` will be called
|
|
* on the trailing edge of the timeout only if the the throttled function is
|
|
* invoked more than once during the `wait` timeout.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Function} func The function to throttle.
|
|
* @param {Number} wait The number of milliseconds to throttle executions to.
|
|
* @param {Object} options The options object.
|
|
* [leading=true] A boolean to specify execution on the leading edge of the timeout.
|
|
* [trailing=true] A boolean to specify execution on the trailing edge of the timeout.
|
|
* @returns {Function} Returns the new throttled function.
|
|
* @example
|
|
*
|
|
* var throttled = _.throttle(updatePosition, 100);
|
|
* jQuery(window).on('scroll', throttled);
|
|
*
|
|
* jQuery('.interactive').on('click', _.throttle(renewToken, 300000, {
|
|
* 'trailing': false
|
|
* }));
|
|
*/
|
|
function throttle(func, wait, options) {
|
|
var leading = true,
|
|
trailing = true;
|
|
|
|
if (options === false) {
|
|
leading = false;
|
|
} else if (isObject(options)) {
|
|
leading = 'leading' in options ? options.leading : leading;
|
|
trailing = 'trailing' in options ? options.trailing : trailing;
|
|
}
|
|
options = getObject();
|
|
options.leading = leading;
|
|
options.maxWait = wait;
|
|
options.trailing = trailing;
|
|
|
|
var result = debounce(func, wait, options);
|
|
releaseObject(options);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Creates a function that passes `value` to the `wrapper` function as its
|
|
* first argument. Additional arguments passed to the function are appended
|
|
* to those passed to the `wrapper` function. The `wrapper` is executed with
|
|
* the `this` binding of the created function.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Mixed} value The value to wrap.
|
|
* @param {Function} wrapper The wrapper function.
|
|
* @returns {Function} Returns the new function.
|
|
* @example
|
|
*
|
|
* var hello = function(name) { return 'hello ' + name; };
|
|
* hello = _.wrap(hello, function(func) {
|
|
* return 'before, ' + func('moe') + ', after';
|
|
* });
|
|
* hello();
|
|
* // => 'before, hello moe, after'
|
|
*/
|
|
function wrap(value, wrapper) {
|
|
return function() {
|
|
var args = [value];
|
|
push.apply(args, arguments);
|
|
return wrapper.apply(this, args);
|
|
};
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to their
|
|
* corresponding HTML entities.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @param {String} string The string to escape.
|
|
* @returns {String} Returns the escaped string.
|
|
* @example
|
|
*
|
|
* _.escape('Moe, Larry & Curly');
|
|
* // => 'Moe, Larry & Curly'
|
|
*/
|
|
function escape(string) {
|
|
return string == null ? '' : String(string).replace(reUnescapedHtml, escapeHtmlChar);
|
|
}
|
|
|
|
/**
|
|
* This method returns the first argument passed to it.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @param {Mixed} value Any value.
|
|
* @returns {Mixed} Returns `value`.
|
|
* @example
|
|
*
|
|
* var moe = { 'name': 'moe' };
|
|
* moe === _.identity(moe);
|
|
* // => true
|
|
*/
|
|
function identity(value) {
|
|
return value;
|
|
}
|
|
|
|
/**
|
|
* Adds functions properties of `object` to the `lodash` function and chainable
|
|
* wrapper.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @param {Object} object The object of function properties to add to `lodash`.
|
|
* @example
|
|
*
|
|
* _.mixin({
|
|
* 'capitalize': function(string) {
|
|
* return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
|
|
* }
|
|
* });
|
|
*
|
|
* _.capitalize('moe');
|
|
* // => 'Moe'
|
|
*
|
|
* _('moe').capitalize();
|
|
* // => 'Moe'
|
|
*/
|
|
function mixin(object) {
|
|
forEach(functions(object), function(methodName) {
|
|
var func = lodash[methodName] = object[methodName];
|
|
|
|
lodash.prototype[methodName] = function() {
|
|
var value = this.__wrapped__,
|
|
args = [value];
|
|
|
|
push.apply(args, arguments);
|
|
var result = func.apply(lodash, args);
|
|
return (value && typeof value == 'object' && value === result)
|
|
? this
|
|
: new lodashWrapper(result);
|
|
};
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Reverts the '_' variable to its previous value and returns a reference to
|
|
* the `lodash` function.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @returns {Function} Returns the `lodash` function.
|
|
* @example
|
|
*
|
|
* var lodash = _.noConflict();
|
|
*/
|
|
function noConflict() {
|
|
context._ = oldDash;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Converts the given `value` into an integer of the specified `radix`.
|
|
* If `radix` is `undefined` or `0`, a `radix` of `10` is used unless the
|
|
* `value` is a hexadecimal, in which case a `radix` of `16` is used.
|
|
*
|
|
* Note: This method avoids differences in native ES3 and ES5 `parseInt`
|
|
* implementations. See http://es5.github.com/#E.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @param {String} value The value to parse.
|
|
* @param {Number} [radix] The radix used to interpret the value to parse.
|
|
* @returns {Number} Returns the new integer value.
|
|
* @example
|
|
*
|
|
* _.parseInt('08');
|
|
* // => 8
|
|
*/
|
|
var parseInt = nativeParseInt(whitespace + '08') == 8 ? nativeParseInt : function(value, radix) {
|
|
// Firefox and Opera still follow the ES3 specified implementation of `parseInt`
|
|
return nativeParseInt(isString(value) ? value.replace(reLeadingSpacesAndZeros, '') : value, radix || 0);
|
|
};
|
|
|
|
/**
|
|
* Produces a random number between `min` and `max` (inclusive). If only one
|
|
* argument is passed, a number between `0` and the given number will be returned.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @param {Number} [min=0] The minimum possible value.
|
|
* @param {Number} [max=1] The maximum possible value.
|
|
* @returns {Number} Returns a random number.
|
|
* @example
|
|
*
|
|
* _.random(0, 5);
|
|
* // => a number between 0 and 5
|
|
*
|
|
* _.random(5);
|
|
* // => also a number between 0 and 5
|
|
*/
|
|
function random(min, max) {
|
|
if (min == null && max == null) {
|
|
max = 1;
|
|
}
|
|
min = +min || 0;
|
|
if (max == null) {
|
|
max = min;
|
|
min = 0;
|
|
} else {
|
|
max = +max || 0;
|
|
}
|
|
var rand = nativeRandom();
|
|
return (min % 1 || max % 1)
|
|
? min + nativeMin(rand * (max - min + parseFloat('1e-' + ((rand +'').length - 1))), max)
|
|
: min + floor(rand * (max - min + 1));
|
|
}
|
|
|
|
/**
|
|
* Resolves the value of `property` on `object`. If `property` is a function,
|
|
* it will be invoked with the `this` binding of `object` and its result returned,
|
|
* else the property value is returned. If `object` is falsey, then `undefined`
|
|
* is returned.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @param {Object} object The object to inspect.
|
|
* @param {String} property The property to get the value of.
|
|
* @returns {Mixed} Returns the resolved value.
|
|
* @example
|
|
*
|
|
* var object = {
|
|
* 'cheese': 'crumpets',
|
|
* 'stuff': function() {
|
|
* return 'nonsense';
|
|
* }
|
|
* };
|
|
*
|
|
* _.result(object, 'cheese');
|
|
* // => 'crumpets'
|
|
*
|
|
* _.result(object, 'stuff');
|
|
* // => 'nonsense'
|
|
*/
|
|
function result(object, property) {
|
|
var value = object ? object[property] : undefined;
|
|
return isFunction(value) ? object[property]() : value;
|
|
}
|
|
|
|
/**
|
|
* A micro-templating method that handles arbitrary delimiters, preserves
|
|
* whitespace, and correctly escapes quotes within interpolated code.
|
|
*
|
|
* Note: In the development build, `_.template` utilizes sourceURLs for easier
|
|
* debugging. See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
|
|
*
|
|
* For more information on precompiling templates see:
|
|
* http://lodash.com/#custom-builds
|
|
*
|
|
* For more information on Chrome extension sandboxes see:
|
|
* http://developer.chrome.com/stable/extensions/sandboxingEval.html
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @param {String} text The template text.
|
|
* @param {Object} data The data object used to populate the text.
|
|
* @param {Object} options The options object.
|
|
* escape - The "escape" delimiter regexp.
|
|
* evaluate - The "evaluate" delimiter regexp.
|
|
* interpolate - The "interpolate" delimiter regexp.
|
|
* sourceURL - The sourceURL of the template's compiled source.
|
|
* variable - The data object variable name.
|
|
* @returns {Function|String} Returns a compiled function when no `data` object
|
|
* is given, else it returns the interpolated text.
|
|
* @example
|
|
*
|
|
* // using a compiled template
|
|
* var compiled = _.template('hello <%= name %>');
|
|
* compiled({ 'name': 'moe' });
|
|
* // => 'hello moe'
|
|
*
|
|
* var list = '<% _.forEach(people, function(name) { %><li><%= name %></li><% }); %>';
|
|
* _.template(list, { 'people': ['moe', 'larry'] });
|
|
* // => '<li>moe</li><li>larry</li>'
|
|
*
|
|
* // using the "escape" delimiter to escape HTML in data property values
|
|
* _.template('<b><%- value %></b>', { 'value': '<script>' });
|
|
* // => '<b><script></b>'
|
|
*
|
|
* // using the ES6 delimiter as an alternative to the default "interpolate" delimiter
|
|
* _.template('hello ${ name }', { 'name': 'curly' });
|
|
* // => 'hello curly'
|
|
*
|
|
* // using the internal `print` function in "evaluate" delimiters
|
|
* _.template('<% print("hello " + epithet); %>!', { 'epithet': 'stooge' });
|
|
* // => 'hello stooge!'
|
|
*
|
|
* // using custom template delimiters
|
|
* _.templateSettings = {
|
|
* 'interpolate': /{{([\s\S]+?)}}/g
|
|
* };
|
|
*
|
|
* _.template('hello {{ name }}!', { 'name': 'mustache' });
|
|
* // => 'hello mustache!'
|
|
*
|
|
* // using the `sourceURL` option to specify a custom sourceURL for the template
|
|
* var compiled = _.template('hello <%= name %>', null, { 'sourceURL': '/basic/greeting.jst' });
|
|
* compiled(data);
|
|
* // => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector
|
|
*
|
|
* // using the `variable` option to ensure a with-statement isn't used in the compiled template
|
|
* var compiled = _.template('hi <%= data.name %>!', null, { 'variable': 'data' });
|
|
* compiled.source;
|
|
* // => function(data) {
|
|
* var __t, __p = '', __e = _.escape;
|
|
* __p += 'hi ' + ((__t = ( data.name )) == null ? '' : __t) + '!';
|
|
* return __p;
|
|
* }
|
|
*
|
|
* // using the `source` property to inline compiled templates for meaningful
|
|
* // line numbers in error messages and a stack trace
|
|
* fs.writeFileSync(path.join(cwd, 'jst.js'), '\
|
|
* var JST = {\
|
|
* "main": ' + _.template(mainText).source + '\
|
|
* };\
|
|
* ');
|
|
*/
|
|
function template(text, data, options) {
|
|
// based on John Resig's `tmpl` implementation
|
|
// http://ejohn.org/blog/javascript-micro-templating/
|
|
// and Laura Doktorova's doT.js
|
|
// https://github.com/olado/doT
|
|
var settings = lodash.templateSettings;
|
|
text || (text = '');
|
|
|
|
// avoid missing dependencies when `iteratorTemplate` is not defined
|
|
options = defaults({}, options, settings);
|
|
|
|
var imports = defaults({}, options.imports, settings.imports),
|
|
importsKeys = keys(imports),
|
|
importsValues = values(imports);
|
|
|
|
var isEvaluating,
|
|
index = 0,
|
|
interpolate = options.interpolate || reNoMatch,
|
|
source = "__p += '";
|
|
|
|
// compile the regexp to match each delimiter
|
|
var reDelimiters = RegExp(
|
|
(options.escape || reNoMatch).source + '|' +
|
|
interpolate.source + '|' +
|
|
(interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' +
|
|
(options.evaluate || reNoMatch).source + '|$'
|
|
, 'g');
|
|
|
|
text.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
|
|
interpolateValue || (interpolateValue = esTemplateValue);
|
|
|
|
// escape characters that cannot be included in string literals
|
|
source += text.slice(index, offset).replace(reUnescapedString, escapeStringChar);
|
|
|
|
// replace delimiters with snippets
|
|
if (escapeValue) {
|
|
source += "' +\n__e(" + escapeValue + ") +\n'";
|
|
}
|
|
if (evaluateValue) {
|
|
isEvaluating = true;
|
|
source += "';\n" + evaluateValue + ";\n__p += '";
|
|
}
|
|
if (interpolateValue) {
|
|
source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'";
|
|
}
|
|
index = offset + match.length;
|
|
|
|
// the JS engine embedded in Adobe products requires returning the `match`
|
|
// string in order to produce the correct `offset` value
|
|
return match;
|
|
});
|
|
|
|
source += "';\n";
|
|
|
|
// if `variable` is not specified, wrap a with-statement around the generated
|
|
// code to add the data object to the top of the scope chain
|
|
var variable = options.variable,
|
|
hasVariable = variable;
|
|
|
|
if (!hasVariable) {
|
|
variable = 'obj';
|
|
source = 'with (' + variable + ') {\n' + source + '\n}\n';
|
|
}
|
|
// cleanup code by stripping empty strings
|
|
source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
|
|
.replace(reEmptyStringMiddle, '$1')
|
|
.replace(reEmptyStringTrailing, '$1;');
|
|
|
|
// frame code as the function body
|
|
source = 'function(' + variable + ') {\n' +
|
|
(hasVariable ? '' : variable + ' || (' + variable + ' = {});\n') +
|
|
"var __t, __p = '', __e = _.escape" +
|
|
(isEvaluating
|
|
? ', __j = Array.prototype.join;\n' +
|
|
"function print() { __p += __j.call(arguments, '') }\n"
|
|
: ';\n'
|
|
) +
|
|
source +
|
|
'return __p\n}';
|
|
|
|
// Use a sourceURL for easier debugging and wrap in a multi-line comment to
|
|
// avoid issues with Narwhal, IE conditional compilation, and the JS engine
|
|
// embedded in Adobe products.
|
|
// http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
|
|
var sourceURL = '\n/*\n//@ sourceURL=' + (options.sourceURL || '/lodash/template/source[' + (templateCounter++) + ']') + '\n*/';
|
|
|
|
try {
|
|
var result = Function(importsKeys, 'return ' + source + sourceURL).apply(undefined, importsValues);
|
|
} catch(e) {
|
|
e.source = source;
|
|
throw e;
|
|
}
|
|
if (data) {
|
|
return result(data);
|
|
}
|
|
// provide the compiled function's source via its `toString` method, in
|
|
// supported environments, or the `source` property as a convenience for
|
|
// inlining compiled templates during the build process
|
|
result.source = source;
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Executes the `callback` function `n` times, returning an array of the results
|
|
* of each `callback` execution. The `callback` is bound to `thisArg` and invoked
|
|
* with one argument; (index).
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @param {Number} n The number of times to execute the callback.
|
|
* @param {Function} callback The function called per iteration.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Array} Returns a new array of the results of each `callback` execution.
|
|
* @example
|
|
*
|
|
* var diceRolls = _.times(3, _.partial(_.random, 1, 6));
|
|
* // => [3, 6, 4]
|
|
*
|
|
* _.times(3, function(n) { mage.castSpell(n); });
|
|
* // => calls `mage.castSpell(n)` three times, passing `n` of `0`, `1`, and `2` respectively
|
|
*
|
|
* _.times(3, function(n) { this.cast(n); }, mage);
|
|
* // => also calls `mage.castSpell(n)` three times
|
|
*/
|
|
function times(n, callback, thisArg) {
|
|
n = (n = +n) > -1 ? n : 0;
|
|
var index = -1,
|
|
result = Array(n);
|
|
|
|
callback = lodash.createCallback(callback, thisArg, 1);
|
|
while (++index < n) {
|
|
result[index] = callback(index);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* The inverse of `_.escape`, this method converts the HTML entities
|
|
* `&`, `<`, `>`, `"`, and `'` in `string` to their
|
|
* corresponding characters.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @param {String} string The string to unescape.
|
|
* @returns {String} Returns the unescaped string.
|
|
* @example
|
|
*
|
|
* _.unescape('Moe, Larry & Curly');
|
|
* // => 'Moe, Larry & Curly'
|
|
*/
|
|
function unescape(string) {
|
|
return string == null ? '' : String(string).replace(reEscapedHtml, unescapeHtmlChar);
|
|
}
|
|
|
|
/**
|
|
* Generates a unique ID. If `prefix` is passed, the ID will be appended to it.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @param {String} [prefix] The value to prefix the ID with.
|
|
* @returns {String} Returns the unique ID.
|
|
* @example
|
|
*
|
|
* _.uniqueId('contact_');
|
|
* // => 'contact_104'
|
|
*
|
|
* _.uniqueId();
|
|
* // => '105'
|
|
*/
|
|
function uniqueId(prefix) {
|
|
var id = ++idCounter;
|
|
return String(prefix == null ? '' : prefix) + id;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Invokes `interceptor` with the `value` as the first argument, and then
|
|
* returns `value`. The purpose of this method is to "tap into" a method chain,
|
|
* in order to perform operations on intermediate results within the chain.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Chaining
|
|
* @param {Mixed} value The value to pass to `interceptor`.
|
|
* @param {Function} interceptor The function to invoke.
|
|
* @returns {Mixed} Returns `value`.
|
|
* @example
|
|
*
|
|
* _([1, 2, 3, 4])
|
|
* .filter(function(num) { return num % 2 == 0; })
|
|
* .tap(alert)
|
|
* .map(function(num) { return num * num; })
|
|
* .value();
|
|
* // => // [2, 4] (alerted)
|
|
* // => [4, 16]
|
|
*/
|
|
function tap(value, interceptor) {
|
|
interceptor(value);
|
|
return value;
|
|
}
|
|
|
|
/**
|
|
* Produces the `toString` result of the wrapped value.
|
|
*
|
|
* @name toString
|
|
* @memberOf _
|
|
* @category Chaining
|
|
* @returns {String} Returns the string result.
|
|
* @example
|
|
*
|
|
* _([1, 2, 3]).toString();
|
|
* // => '1,2,3'
|
|
*/
|
|
function wrapperToString() {
|
|
return String(this.__wrapped__);
|
|
}
|
|
|
|
/**
|
|
* Extracts the wrapped value.
|
|
*
|
|
* @name valueOf
|
|
* @memberOf _
|
|
* @alias value
|
|
* @category Chaining
|
|
* @returns {Mixed} Returns the wrapped value.
|
|
* @example
|
|
*
|
|
* _([1, 2, 3]).valueOf();
|
|
* // => [1, 2, 3]
|
|
*/
|
|
function wrapperValueOf() {
|
|
return this.__wrapped__;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
// add functions that return wrapped values when chaining
|
|
lodash.after = after;
|
|
lodash.assign = assign;
|
|
lodash.at = at;
|
|
lodash.bind = bind;
|
|
lodash.bindAll = bindAll;
|
|
lodash.bindKey = bindKey;
|
|
lodash.compact = compact;
|
|
lodash.compose = compose;
|
|
lodash.countBy = countBy;
|
|
lodash.createCallback = createCallback;
|
|
lodash.debounce = debounce;
|
|
lodash.defaults = defaults;
|
|
lodash.defer = defer;
|
|
lodash.delay = delay;
|
|
lodash.difference = difference;
|
|
lodash.filter = filter;
|
|
lodash.flatten = flatten;
|
|
lodash.forEach = forEach;
|
|
lodash.forIn = forIn;
|
|
lodash.forOwn = forOwn;
|
|
lodash.functions = functions;
|
|
lodash.groupBy = groupBy;
|
|
lodash.initial = initial;
|
|
lodash.intersection = intersection;
|
|
lodash.invert = invert;
|
|
lodash.invoke = invoke;
|
|
lodash.keys = keys;
|
|
lodash.map = map;
|
|
lodash.max = max;
|
|
lodash.memoize = memoize;
|
|
lodash.merge = merge;
|
|
lodash.min = min;
|
|
lodash.omit = omit;
|
|
lodash.once = once;
|
|
lodash.pairs = pairs;
|
|
lodash.partial = partial;
|
|
lodash.partialRight = partialRight;
|
|
lodash.pick = pick;
|
|
lodash.pluck = pluck;
|
|
lodash.range = range;
|
|
lodash.reject = reject;
|
|
lodash.rest = rest;
|
|
lodash.shuffle = shuffle;
|
|
lodash.sortBy = sortBy;
|
|
lodash.tap = tap;
|
|
lodash.throttle = throttle;
|
|
lodash.times = times;
|
|
lodash.toArray = toArray;
|
|
lodash.transform = transform;
|
|
lodash.union = union;
|
|
lodash.uniq = uniq;
|
|
lodash.unzip = unzip;
|
|
lodash.values = values;
|
|
lodash.where = where;
|
|
lodash.without = without;
|
|
lodash.wrap = wrap;
|
|
lodash.zip = zip;
|
|
lodash.zipObject = zipObject;
|
|
|
|
// add aliases
|
|
lodash.collect = map;
|
|
lodash.drop = rest;
|
|
lodash.each = forEach;
|
|
lodash.extend = assign;
|
|
lodash.methods = functions;
|
|
lodash.object = zipObject;
|
|
lodash.select = filter;
|
|
lodash.tail = rest;
|
|
lodash.unique = uniq;
|
|
|
|
// add functions to `lodash.prototype`
|
|
mixin(lodash);
|
|
|
|
// add Underscore compat
|
|
lodash.chain = lodash;
|
|
lodash.prototype.chain = function() { return this; };
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
// add functions that return unwrapped values when chaining
|
|
lodash.clone = clone;
|
|
lodash.cloneDeep = cloneDeep;
|
|
lodash.contains = contains;
|
|
lodash.escape = escape;
|
|
lodash.every = every;
|
|
lodash.find = find;
|
|
lodash.findIndex = findIndex;
|
|
lodash.findKey = findKey;
|
|
lodash.has = has;
|
|
lodash.identity = identity;
|
|
lodash.indexOf = indexOf;
|
|
lodash.isArguments = isArguments;
|
|
lodash.isArray = isArray;
|
|
lodash.isBoolean = isBoolean;
|
|
lodash.isDate = isDate;
|
|
lodash.isElement = isElement;
|
|
lodash.isEmpty = isEmpty;
|
|
lodash.isEqual = isEqual;
|
|
lodash.isFinite = isFinite;
|
|
lodash.isFunction = isFunction;
|
|
lodash.isNaN = isNaN;
|
|
lodash.isNull = isNull;
|
|
lodash.isNumber = isNumber;
|
|
lodash.isObject = isObject;
|
|
lodash.isPlainObject = isPlainObject;
|
|
lodash.isRegExp = isRegExp;
|
|
lodash.isString = isString;
|
|
lodash.isUndefined = isUndefined;
|
|
lodash.lastIndexOf = lastIndexOf;
|
|
lodash.mixin = mixin;
|
|
lodash.noConflict = noConflict;
|
|
lodash.parseInt = parseInt;
|
|
lodash.random = random;
|
|
lodash.reduce = reduce;
|
|
lodash.reduceRight = reduceRight;
|
|
lodash.result = result;
|
|
lodash.runInContext = runInContext;
|
|
lodash.size = size;
|
|
lodash.some = some;
|
|
lodash.sortedIndex = sortedIndex;
|
|
lodash.template = template;
|
|
lodash.unescape = unescape;
|
|
lodash.uniqueId = uniqueId;
|
|
|
|
// add aliases
|
|
lodash.all = every;
|
|
lodash.any = some;
|
|
lodash.detect = find;
|
|
lodash.findWhere = find;
|
|
lodash.foldl = reduce;
|
|
lodash.foldr = reduceRight;
|
|
lodash.include = contains;
|
|
lodash.inject = reduce;
|
|
|
|
forOwn(lodash, function(func, methodName) {
|
|
if (!lodash.prototype[methodName]) {
|
|
lodash.prototype[methodName] = function() {
|
|
var args = [this.__wrapped__];
|
|
push.apply(args, arguments);
|
|
return func.apply(lodash, args);
|
|
};
|
|
}
|
|
});
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
// add functions capable of returning wrapped and unwrapped values when chaining
|
|
lodash.first = first;
|
|
lodash.last = last;
|
|
|
|
// add aliases
|
|
lodash.take = first;
|
|
lodash.head = first;
|
|
|
|
forOwn(lodash, function(func, methodName) {
|
|
if (!lodash.prototype[methodName]) {
|
|
lodash.prototype[methodName]= function(callback, thisArg) {
|
|
var result = func(this.__wrapped__, callback, thisArg);
|
|
return callback == null || (thisArg && typeof callback != 'function')
|
|
? result
|
|
: new lodashWrapper(result);
|
|
};
|
|
}
|
|
});
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* The semantic version number.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @type String
|
|
*/
|
|
lodash.VERSION = '1.3.1';
|
|
|
|
// add "Chaining" functions to the wrapper
|
|
lodash.prototype.toString = wrapperToString;
|
|
lodash.prototype.value = wrapperValueOf;
|
|
lodash.prototype.valueOf = wrapperValueOf;
|
|
|
|
// add `Array` functions that return unwrapped values
|
|
forEach(['join', 'pop', 'shift'], function(methodName) {
|
|
var func = arrayRef[methodName];
|
|
lodash.prototype[methodName] = function() {
|
|
return func.apply(this.__wrapped__, arguments);
|
|
};
|
|
});
|
|
|
|
// add `Array` functions that return the wrapped value
|
|
forEach(['push', 'reverse', 'sort', 'unshift'], function(methodName) {
|
|
var func = arrayRef[methodName];
|
|
lodash.prototype[methodName] = function() {
|
|
func.apply(this.__wrapped__, arguments);
|
|
return this;
|
|
};
|
|
});
|
|
|
|
// add `Array` functions that return new wrapped values
|
|
forEach(['concat', 'slice', 'splice'], function(methodName) {
|
|
var func = arrayRef[methodName];
|
|
lodash.prototype[methodName] = function() {
|
|
return new lodashWrapper(func.apply(this.__wrapped__, arguments));
|
|
};
|
|
});
|
|
|
|
return lodash;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
// expose Lo-Dash
|
|
var _ = runInContext();
|
|
|
|
// some AMD build optimizers, like r.js, check for specific condition patterns like the following:
|
|
if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
|
|
// Expose Lo-Dash to the global object even when an AMD loader is present in
|
|
// case Lo-Dash was injected by a third-party script and not intended to be
|
|
// loaded as a module. The global assignment can be reverted in the Lo-Dash
|
|
// module via its `noConflict()` method.
|
|
window._ = _;
|
|
|
|
// define as an anonymous module so, through path mapping, it can be
|
|
// referenced as the "underscore" module
|
|
define(function() {
|
|
return _;
|
|
});
|
|
}
|
|
// check for `exports` after `define` in case a build optimizer adds an `exports` object
|
|
else if (freeExports && !freeExports.nodeType) {
|
|
// in Node.js or RingoJS v0.8.0+
|
|
if (freeModule) {
|
|
(freeModule.exports = _)._ = _;
|
|
}
|
|
// in Narwhal or RingoJS v0.7.0-
|
|
else {
|
|
freeExports._ = _;
|
|
}
|
|
}
|
|
else {
|
|
// in a browser or Rhino
|
|
window._ = _;
|
|
}
|
|
}(this));
|
|
|
|
},{}],3:[function(require,module,exports){
|
|
// moment.js
|
|
// version : 2.1.0
|
|
// author : Tim Wood
|
|
// license : MIT
|
|
// momentjs.com
|
|
|
|
(function (undefined) {
|
|
|
|
/************************************
|
|
Constants
|
|
************************************/
|
|
|
|
var moment,
|
|
VERSION = "2.1.0",
|
|
round = Math.round, i,
|
|
// internal storage for language config files
|
|
languages = {},
|
|
|
|
// check for nodeJS
|
|
hasModule = (typeof module !== 'undefined' && module.exports),
|
|
|
|
// ASP.NET json date format regex
|
|
aspNetJsonRegex = /^\/?Date\((\-?\d+)/i,
|
|
aspNetTimeSpanJsonRegex = /(\-)?(\d*)?\.?(\d+)\:(\d+)\:(\d+)\.?(\d{3})?/,
|
|
|
|
// format tokens
|
|
formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|SS?S?|X|zz?|ZZ?|.)/g,
|
|
localFormattingTokens = /(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,
|
|
|
|
// parsing token regexes
|
|
parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99
|
|
parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999
|
|
parseTokenThreeDigits = /\d{3}/, // 000 - 999
|
|
parseTokenFourDigits = /\d{1,4}/, // 0 - 9999
|
|
parseTokenSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999
|
|
parseTokenWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i, // any word (or two) characters or numbers including two/three word month in arabic.
|
|
parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/i, // +00:00 -00:00 +0000 -0000 or Z
|
|
parseTokenT = /T/i, // T (ISO seperator)
|
|
parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123
|
|
|
|
// preliminary iso regex
|
|
// 0000-00-00 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000
|
|
isoRegex = /^\s*\d{4}-\d\d-\d\d((T| )(\d\d(:\d\d(:\d\d(\.\d\d?\d?)?)?)?)?([\+\-]\d\d:?\d\d)?)?/,
|
|
isoFormat = 'YYYY-MM-DDTHH:mm:ssZ',
|
|
|
|
// iso time formats and regexes
|
|
isoTimes = [
|
|
['HH:mm:ss.S', /(T| )\d\d:\d\d:\d\d\.\d{1,3}/],
|
|
['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/],
|
|
['HH:mm', /(T| )\d\d:\d\d/],
|
|
['HH', /(T| )\d\d/]
|
|
],
|
|
|
|
// timezone chunker "+10:00" > ["10", "00"] or "-1530" > ["-15", "30"]
|
|
parseTimezoneChunker = /([\+\-]|\d\d)/gi,
|
|
|
|
// getter and setter names
|
|
proxyGettersAndSetters = 'Date|Hours|Minutes|Seconds|Milliseconds'.split('|'),
|
|
unitMillisecondFactors = {
|
|
'Milliseconds' : 1,
|
|
'Seconds' : 1e3,
|
|
'Minutes' : 6e4,
|
|
'Hours' : 36e5,
|
|
'Days' : 864e5,
|
|
'Months' : 2592e6,
|
|
'Years' : 31536e6
|
|
},
|
|
|
|
unitAliases = {
|
|
ms : 'millisecond',
|
|
s : 'second',
|
|
m : 'minute',
|
|
h : 'hour',
|
|
d : 'day',
|
|
w : 'week',
|
|
M : 'month',
|
|
y : 'year'
|
|
},
|
|
|
|
// format function strings
|
|
formatFunctions = {},
|
|
|
|
// tokens to ordinalize and pad
|
|
ordinalizeTokens = 'DDD w W M D d'.split(' '),
|
|
paddedTokens = 'M D H h m s w W'.split(' '),
|
|
|
|
formatTokenFunctions = {
|
|
M : function () {
|
|
return this.month() + 1;
|
|
},
|
|
MMM : function (format) {
|
|
return this.lang().monthsShort(this, format);
|
|
},
|
|
MMMM : function (format) {
|
|
return this.lang().months(this, format);
|
|
},
|
|
D : function () {
|
|
return this.date();
|
|
},
|
|
DDD : function () {
|
|
return this.dayOfYear();
|
|
},
|
|
d : function () {
|
|
return this.day();
|
|
},
|
|
dd : function (format) {
|
|
return this.lang().weekdaysMin(this, format);
|
|
},
|
|
ddd : function (format) {
|
|
return this.lang().weekdaysShort(this, format);
|
|
},
|
|
dddd : function (format) {
|
|
return this.lang().weekdays(this, format);
|
|
},
|
|
w : function () {
|
|
return this.week();
|
|
},
|
|
W : function () {
|
|
return this.isoWeek();
|
|
},
|
|
YY : function () {
|
|
return leftZeroFill(this.year() % 100, 2);
|
|
},
|
|
YYYY : function () {
|
|
return leftZeroFill(this.year(), 4);
|
|
},
|
|
YYYYY : function () {
|
|
return leftZeroFill(this.year(), 5);
|
|
},
|
|
gg : function () {
|
|
return leftZeroFill(this.weekYear() % 100, 2);
|
|
},
|
|
gggg : function () {
|
|
return this.weekYear();
|
|
},
|
|
ggggg : function () {
|
|
return leftZeroFill(this.weekYear(), 5);
|
|
},
|
|
GG : function () {
|
|
return leftZeroFill(this.isoWeekYear() % 100, 2);
|
|
},
|
|
GGGG : function () {
|
|
return this.isoWeekYear();
|
|
},
|
|
GGGGG : function () {
|
|
return leftZeroFill(this.isoWeekYear(), 5);
|
|
},
|
|
e : function () {
|
|
return this.weekday();
|
|
},
|
|
E : function () {
|
|
return this.isoWeekday();
|
|
},
|
|
a : function () {
|
|
return this.lang().meridiem(this.hours(), this.minutes(), true);
|
|
},
|
|
A : function () {
|
|
return this.lang().meridiem(this.hours(), this.minutes(), false);
|
|
},
|
|
H : function () {
|
|
return this.hours();
|
|
},
|
|
h : function () {
|
|
return this.hours() % 12 || 12;
|
|
},
|
|
m : function () {
|
|
return this.minutes();
|
|
},
|
|
s : function () {
|
|
return this.seconds();
|
|
},
|
|
S : function () {
|
|
return ~~(this.milliseconds() / 100);
|
|
},
|
|
SS : function () {
|
|
return leftZeroFill(~~(this.milliseconds() / 10), 2);
|
|
},
|
|
SSS : function () {
|
|
return leftZeroFill(this.milliseconds(), 3);
|
|
},
|
|
Z : function () {
|
|
var a = -this.zone(),
|
|
b = "+";
|
|
if (a < 0) {
|
|
a = -a;
|
|
b = "-";
|
|
}
|
|
return b + leftZeroFill(~~(a / 60), 2) + ":" + leftZeroFill(~~a % 60, 2);
|
|
},
|
|
ZZ : function () {
|
|
var a = -this.zone(),
|
|
b = "+";
|
|
if (a < 0) {
|
|
a = -a;
|
|
b = "-";
|
|
}
|
|
return b + leftZeroFill(~~(10 * a / 6), 4);
|
|
},
|
|
z : function () {
|
|
return this.zoneAbbr();
|
|
},
|
|
zz : function () {
|
|
return this.zoneName();
|
|
},
|
|
X : function () {
|
|
return this.unix();
|
|
}
|
|
};
|
|
|
|
function padToken(func, count) {
|
|
return function (a) {
|
|
return leftZeroFill(func.call(this, a), count);
|
|
};
|
|
}
|
|
function ordinalizeToken(func, period) {
|
|
return function (a) {
|
|
return this.lang().ordinal(func.call(this, a), period);
|
|
};
|
|
}
|
|
|
|
while (ordinalizeTokens.length) {
|
|
i = ordinalizeTokens.pop();
|
|
formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i], i);
|
|
}
|
|
while (paddedTokens.length) {
|
|
i = paddedTokens.pop();
|
|
formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2);
|
|
}
|
|
formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3);
|
|
|
|
|
|
/************************************
|
|
Constructors
|
|
************************************/
|
|
|
|
function Language() {
|
|
|
|
}
|
|
|
|
// Moment prototype object
|
|
function Moment(config) {
|
|
extend(this, config);
|
|
}
|
|
|
|
// Duration Constructor
|
|
function Duration(duration) {
|
|
var years = duration.years || duration.year || duration.y || 0,
|
|
months = duration.months || duration.month || duration.M || 0,
|
|
weeks = duration.weeks || duration.week || duration.w || 0,
|
|
days = duration.days || duration.day || duration.d || 0,
|
|
hours = duration.hours || duration.hour || duration.h || 0,
|
|
minutes = duration.minutes || duration.minute || duration.m || 0,
|
|
seconds = duration.seconds || duration.second || duration.s || 0,
|
|
milliseconds = duration.milliseconds || duration.millisecond || duration.ms || 0;
|
|
|
|
// store reference to input for deterministic cloning
|
|
this._input = duration;
|
|
|
|
// representation for dateAddRemove
|
|
this._milliseconds = milliseconds +
|
|
seconds * 1e3 + // 1000
|
|
minutes * 6e4 + // 1000 * 60
|
|
hours * 36e5; // 1000 * 60 * 60
|
|
// Because of dateAddRemove treats 24 hours as different from a
|
|
// day when working around DST, we need to store them separately
|
|
this._days = days +
|
|
weeks * 7;
|
|
// It is impossible translate months into days without knowing
|
|
// which months you are are talking about, so we have to store
|
|
// it separately.
|
|
this._months = months +
|
|
years * 12;
|
|
|
|
this._data = {};
|
|
|
|
this._bubble();
|
|
}
|
|
|
|
|
|
/************************************
|
|
Helpers
|
|
************************************/
|
|
|
|
|
|
function extend(a, b) {
|
|
for (var i in b) {
|
|
if (b.hasOwnProperty(i)) {
|
|
a[i] = b[i];
|
|
}
|
|
}
|
|
return a;
|
|
}
|
|
|
|
function absRound(number) {
|
|
if (number < 0) {
|
|
return Math.ceil(number);
|
|
} else {
|
|
return Math.floor(number);
|
|
}
|
|
}
|
|
|
|
// left zero fill a number
|
|
// see http://jsperf.com/left-zero-filling for performance comparison
|
|
function leftZeroFill(number, targetLength) {
|
|
var output = number + '';
|
|
while (output.length < targetLength) {
|
|
output = '0' + output;
|
|
}
|
|
return output;
|
|
}
|
|
|
|
// helper function for _.addTime and _.subtractTime
|
|
function addOrSubtractDurationFromMoment(mom, duration, isAdding, ignoreUpdateOffset) {
|
|
var milliseconds = duration._milliseconds,
|
|
days = duration._days,
|
|
months = duration._months,
|
|
minutes,
|
|
hours,
|
|
currentDate;
|
|
|
|
if (milliseconds) {
|
|
mom._d.setTime(+mom._d + milliseconds * isAdding);
|
|
}
|
|
// store the minutes and hours so we can restore them
|
|
if (days || months) {
|
|
minutes = mom.minute();
|
|
hours = mom.hour();
|
|
}
|
|
if (days) {
|
|
mom.date(mom.date() + days * isAdding);
|
|
}
|
|
if (months) {
|
|
mom.month(mom.month() + months * isAdding);
|
|
}
|
|
if (milliseconds && !ignoreUpdateOffset) {
|
|
moment.updateOffset(mom);
|
|
}
|
|
// restore the minutes and hours after possibly changing dst
|
|
if (days || months) {
|
|
mom.minute(minutes);
|
|
mom.hour(hours);
|
|
}
|
|
}
|
|
|
|
// check if is an array
|
|
function isArray(input) {
|
|
return Object.prototype.toString.call(input) === '[object Array]';
|
|
}
|
|
|
|
// compare two arrays, return the number of differences
|
|
function compareArrays(array1, array2) {
|
|
var len = Math.min(array1.length, array2.length),
|
|
lengthDiff = Math.abs(array1.length - array2.length),
|
|
diffs = 0,
|
|
i;
|
|
for (i = 0; i < len; i++) {
|
|
if (~~array1[i] !== ~~array2[i]) {
|
|
diffs++;
|
|
}
|
|
}
|
|
return diffs + lengthDiff;
|
|
}
|
|
|
|
function normalizeUnits(units) {
|
|
return units ? unitAliases[units] || units.toLowerCase().replace(/(.)s$/, '$1') : units;
|
|
}
|
|
|
|
|
|
/************************************
|
|
Languages
|
|
************************************/
|
|
|
|
|
|
Language.prototype = {
|
|
set : function (config) {
|
|
var prop, i;
|
|
for (i in config) {
|
|
prop = config[i];
|
|
if (typeof prop === 'function') {
|
|
this[i] = prop;
|
|
} else {
|
|
this['_' + i] = prop;
|
|
}
|
|
}
|
|
},
|
|
|
|
_months : "January_February_March_April_May_June_July_August_September_October_November_December".split("_"),
|
|
months : function (m) {
|
|
return this._months[m.month()];
|
|
},
|
|
|
|
_monthsShort : "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),
|
|
monthsShort : function (m) {
|
|
return this._monthsShort[m.month()];
|
|
},
|
|
|
|
monthsParse : function (monthName) {
|
|
var i, mom, regex;
|
|
|
|
if (!this._monthsParse) {
|
|
this._monthsParse = [];
|
|
}
|
|
|
|
for (i = 0; i < 12; i++) {
|
|
// make the regex if we don't have it already
|
|
if (!this._monthsParse[i]) {
|
|
mom = moment([2000, i]);
|
|
regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
|
|
this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
|
|
}
|
|
// test the regex
|
|
if (this._monthsParse[i].test(monthName)) {
|
|
return i;
|
|
}
|
|
}
|
|
},
|
|
|
|
_weekdays : "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),
|
|
weekdays : function (m) {
|
|
return this._weekdays[m.day()];
|
|
},
|
|
|
|
_weekdaysShort : "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),
|
|
weekdaysShort : function (m) {
|
|
return this._weekdaysShort[m.day()];
|
|
},
|
|
|
|
_weekdaysMin : "Su_Mo_Tu_We_Th_Fr_Sa".split("_"),
|
|
weekdaysMin : function (m) {
|
|
return this._weekdaysMin[m.day()];
|
|
},
|
|
|
|
weekdaysParse : function (weekdayName) {
|
|
var i, mom, regex;
|
|
|
|
if (!this._weekdaysParse) {
|
|
this._weekdaysParse = [];
|
|
}
|
|
|
|
for (i = 0; i < 7; i++) {
|
|
// make the regex if we don't have it already
|
|
if (!this._weekdaysParse[i]) {
|
|
mom = moment([2000, 1]).day(i);
|
|
regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');
|
|
this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');
|
|
}
|
|
// test the regex
|
|
if (this._weekdaysParse[i].test(weekdayName)) {
|
|
return i;
|
|
}
|
|
}
|
|
},
|
|
|
|
_longDateFormat : {
|
|
LT : "h:mm A",
|
|
L : "MM/DD/YYYY",
|
|
LL : "MMMM D YYYY",
|
|
LLL : "MMMM D YYYY LT",
|
|
LLLL : "dddd, MMMM D YYYY LT"
|
|
},
|
|
longDateFormat : function (key) {
|
|
var output = this._longDateFormat[key];
|
|
if (!output && this._longDateFormat[key.toUpperCase()]) {
|
|
output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) {
|
|
return val.slice(1);
|
|
});
|
|
this._longDateFormat[key] = output;
|
|
}
|
|
return output;
|
|
},
|
|
|
|
isPM : function (input) {
|
|
return ((input + '').toLowerCase()[0] === 'p');
|
|
},
|
|
|
|
_meridiemParse : /[ap]\.?m?\.?/i,
|
|
meridiem : function (hours, minutes, isLower) {
|
|
if (hours > 11) {
|
|
return isLower ? 'pm' : 'PM';
|
|
} else {
|
|
return isLower ? 'am' : 'AM';
|
|
}
|
|
},
|
|
|
|
_calendar : {
|
|
sameDay : '[Today at] LT',
|
|
nextDay : '[Tomorrow at] LT',
|
|
nextWeek : 'dddd [at] LT',
|
|
lastDay : '[Yesterday at] LT',
|
|
lastWeek : '[Last] dddd [at] LT',
|
|
sameElse : 'L'
|
|
},
|
|
calendar : function (key, mom) {
|
|
var output = this._calendar[key];
|
|
return typeof output === 'function' ? output.apply(mom) : output;
|
|
},
|
|
|
|
_relativeTime : {
|
|
future : "in %s",
|
|
past : "%s ago",
|
|
s : "a few seconds",
|
|
m : "a minute",
|
|
mm : "%d minutes",
|
|
h : "an hour",
|
|
hh : "%d hours",
|
|
d : "a day",
|
|
dd : "%d days",
|
|
M : "a month",
|
|
MM : "%d months",
|
|
y : "a year",
|
|
yy : "%d years"
|
|
},
|
|
relativeTime : function (number, withoutSuffix, string, isFuture) {
|
|
var output = this._relativeTime[string];
|
|
return (typeof output === 'function') ?
|
|
output(number, withoutSuffix, string, isFuture) :
|
|
output.replace(/%d/i, number);
|
|
},
|
|
pastFuture : function (diff, output) {
|
|
var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
|
|
return typeof format === 'function' ? format(output) : format.replace(/%s/i, output);
|
|
},
|
|
|
|
ordinal : function (number) {
|
|
return this._ordinal.replace("%d", number);
|
|
},
|
|
_ordinal : "%d",
|
|
|
|
preparse : function (string) {
|
|
return string;
|
|
},
|
|
|
|
postformat : function (string) {
|
|
return string;
|
|
},
|
|
|
|
week : function (mom) {
|
|
return weekOfYear(mom, this._week.dow, this._week.doy).week;
|
|
},
|
|
_week : {
|
|
dow : 0, // Sunday is the first day of the week.
|
|
doy : 6 // The week that contains Jan 1st is the first week of the year.
|
|
}
|
|
};
|
|
|
|
// Loads a language definition into the `languages` cache. The function
|
|
// takes a key and optionally values. If not in the browser and no values
|
|
// are provided, it will load the language file module. As a convenience,
|
|
// this function also returns the language values.
|
|
function loadLang(key, values) {
|
|
values.abbr = key;
|
|
if (!languages[key]) {
|
|
languages[key] = new Language();
|
|
}
|
|
languages[key].set(values);
|
|
return languages[key];
|
|
}
|
|
|
|
// Determines which language definition to use and returns it.
|
|
//
|
|
// With no parameters, it will return the global language. If you
|
|
// pass in a language key, such as 'en', it will return the
|
|
// definition for 'en', so long as 'en' has already been loaded using
|
|
// moment.lang.
|
|
function getLangDefinition(key) {
|
|
if (!key) {
|
|
return moment.fn._lang;
|
|
}
|
|
if (!languages[key] && hasModule) {
|
|
try {
|
|
require('./lang/' + key);
|
|
} catch (e) {
|
|
// call with no params to set to default
|
|
return moment.fn._lang;
|
|
}
|
|
}
|
|
return languages[key];
|
|
}
|
|
|
|
|
|
/************************************
|
|
Formatting
|
|
************************************/
|
|
|
|
|
|
function removeFormattingTokens(input) {
|
|
if (input.match(/\[.*\]/)) {
|
|
return input.replace(/^\[|\]$/g, "");
|
|
}
|
|
return input.replace(/\\/g, "");
|
|
}
|
|
|
|
function makeFormatFunction(format) {
|
|
var array = format.match(formattingTokens), i, length;
|
|
|
|
for (i = 0, length = array.length; i < length; i++) {
|
|
if (formatTokenFunctions[array[i]]) {
|
|
array[i] = formatTokenFunctions[array[i]];
|
|
} else {
|
|
array[i] = removeFormattingTokens(array[i]);
|
|
}
|
|
}
|
|
|
|
return function (mom) {
|
|
var output = "";
|
|
for (i = 0; i < length; i++) {
|
|
output += array[i] instanceof Function ? array[i].call(mom, format) : array[i];
|
|
}
|
|
return output;
|
|
};
|
|
}
|
|
|
|
// format date using native date object
|
|
function formatMoment(m, format) {
|
|
var i = 5;
|
|
|
|
function replaceLongDateFormatTokens(input) {
|
|
return m.lang().longDateFormat(input) || input;
|
|
}
|
|
|
|
while (i-- && localFormattingTokens.test(format)) {
|
|
format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
|
|
}
|
|
|
|
if (!formatFunctions[format]) {
|
|
formatFunctions[format] = makeFormatFunction(format);
|
|
}
|
|
|
|
return formatFunctions[format](m);
|
|
}
|
|
|
|
|
|
/************************************
|
|
Parsing
|
|
************************************/
|
|
|
|
|
|
// get the regex to find the next token
|
|
function getParseRegexForToken(token, config) {
|
|
switch (token) {
|
|
case 'DDDD':
|
|
return parseTokenThreeDigits;
|
|
case 'YYYY':
|
|
return parseTokenFourDigits;
|
|
case 'YYYYY':
|
|
return parseTokenSixDigits;
|
|
case 'S':
|
|
case 'SS':
|
|
case 'SSS':
|
|
case 'DDD':
|
|
return parseTokenOneToThreeDigits;
|
|
case 'MMM':
|
|
case 'MMMM':
|
|
case 'dd':
|
|
case 'ddd':
|
|
case 'dddd':
|
|
return parseTokenWord;
|
|
case 'a':
|
|
case 'A':
|
|
return getLangDefinition(config._l)._meridiemParse;
|
|
case 'X':
|
|
return parseTokenTimestampMs;
|
|
case 'Z':
|
|
case 'ZZ':
|
|
return parseTokenTimezone;
|
|
case 'T':
|
|
return parseTokenT;
|
|
case 'MM':
|
|
case 'DD':
|
|
case 'YY':
|
|
case 'HH':
|
|
case 'hh':
|
|
case 'mm':
|
|
case 'ss':
|
|
case 'M':
|
|
case 'D':
|
|
case 'd':
|
|
case 'H':
|
|
case 'h':
|
|
case 'm':
|
|
case 's':
|
|
return parseTokenOneOrTwoDigits;
|
|
default :
|
|
return new RegExp(token.replace('\\', ''));
|
|
}
|
|
}
|
|
|
|
function timezoneMinutesFromString(string) {
|
|
var tzchunk = (parseTokenTimezone.exec(string) || [])[0],
|
|
parts = (tzchunk + '').match(parseTimezoneChunker) || ['-', 0, 0],
|
|
minutes = +(parts[1] * 60) + ~~parts[2];
|
|
|
|
return parts[0] === '+' ? -minutes : minutes;
|
|
}
|
|
|
|
// function to convert string input to date
|
|
function addTimeToArrayFromToken(token, input, config) {
|
|
var a, datePartArray = config._a;
|
|
|
|
switch (token) {
|
|
// MONTH
|
|
case 'M' : // fall through to MM
|
|
case 'MM' :
|
|
datePartArray[1] = (input == null) ? 0 : ~~input - 1;
|
|
break;
|
|
case 'MMM' : // fall through to MMMM
|
|
case 'MMMM' :
|
|
a = getLangDefinition(config._l).monthsParse(input);
|
|
// if we didn't find a month name, mark the date as invalid.
|
|
if (a != null) {
|
|
datePartArray[1] = a;
|
|
} else {
|
|
config._isValid = false;
|
|
}
|
|
break;
|
|
// DAY OF MONTH
|
|
case 'D' : // fall through to DDDD
|
|
case 'DD' : // fall through to DDDD
|
|
case 'DDD' : // fall through to DDDD
|
|
case 'DDDD' :
|
|
if (input != null) {
|
|
datePartArray[2] = ~~input;
|
|
}
|
|
break;
|
|
// YEAR
|
|
case 'YY' :
|
|
datePartArray[0] = ~~input + (~~input > 68 ? 1900 : 2000);
|
|
break;
|
|
case 'YYYY' :
|
|
case 'YYYYY' :
|
|
datePartArray[0] = ~~input;
|
|
break;
|
|
// AM / PM
|
|
case 'a' : // fall through to A
|
|
case 'A' :
|
|
config._isPm = getLangDefinition(config._l).isPM(input);
|
|
break;
|
|
// 24 HOUR
|
|
case 'H' : // fall through to hh
|
|
case 'HH' : // fall through to hh
|
|
case 'h' : // fall through to hh
|
|
case 'hh' :
|
|
datePartArray[3] = ~~input;
|
|
break;
|
|
// MINUTE
|
|
case 'm' : // fall through to mm
|
|
case 'mm' :
|
|
datePartArray[4] = ~~input;
|
|
break;
|
|
// SECOND
|
|
case 's' : // fall through to ss
|
|
case 'ss' :
|
|
datePartArray[5] = ~~input;
|
|
break;
|
|
// MILLISECOND
|
|
case 'S' :
|
|
case 'SS' :
|
|
case 'SSS' :
|
|
datePartArray[6] = ~~ (('0.' + input) * 1000);
|
|
break;
|
|
// UNIX TIMESTAMP WITH MS
|
|
case 'X':
|
|
config._d = new Date(parseFloat(input) * 1000);
|
|
break;
|
|
// TIMEZONE
|
|
case 'Z' : // fall through to ZZ
|
|
case 'ZZ' :
|
|
config._useUTC = true;
|
|
config._tzm = timezoneMinutesFromString(input);
|
|
break;
|
|
}
|
|
|
|
// if the input is null, the date is not valid
|
|
if (input == null) {
|
|
config._isValid = false;
|
|
}
|
|
}
|
|
|
|
// convert an array to a date.
|
|
// the array should mirror the parameters below
|
|
// note: all values past the year are optional and will default to the lowest possible value.
|
|
// [year, month, day , hour, minute, second, millisecond]
|
|
function dateFromArray(config) {
|
|
var i, date, input = [];
|
|
|
|
if (config._d) {
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < 7; i++) {
|
|
config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];
|
|
}
|
|
|
|
// add the offsets to the time to be parsed so that we can have a clean array for checking isValid
|
|
input[3] += ~~((config._tzm || 0) / 60);
|
|
input[4] += ~~((config._tzm || 0) % 60);
|
|
|
|
date = new Date(0);
|
|
|
|
if (config._useUTC) {
|
|
date.setUTCFullYear(input[0], input[1], input[2]);
|
|
date.setUTCHours(input[3], input[4], input[5], input[6]);
|
|
} else {
|
|
date.setFullYear(input[0], input[1], input[2]);
|
|
date.setHours(input[3], input[4], input[5], input[6]);
|
|
}
|
|
|
|
config._d = date;
|
|
}
|
|
|
|
// date from string and format string
|
|
function makeDateFromStringAndFormat(config) {
|
|
// This array is used to make a Date, either with `new Date` or `Date.UTC`
|
|
var tokens = config._f.match(formattingTokens),
|
|
string = config._i,
|
|
i, parsedInput;
|
|
|
|
config._a = [];
|
|
|
|
for (i = 0; i < tokens.length; i++) {
|
|
parsedInput = (getParseRegexForToken(tokens[i], config).exec(string) || [])[0];
|
|
if (parsedInput) {
|
|
string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
|
|
}
|
|
// don't parse if its not a known token
|
|
if (formatTokenFunctions[tokens[i]]) {
|
|
addTimeToArrayFromToken(tokens[i], parsedInput, config);
|
|
}
|
|
}
|
|
|
|
// add remaining unparsed input to the string
|
|
if (string) {
|
|
config._il = string;
|
|
}
|
|
|
|
// handle am pm
|
|
if (config._isPm && config._a[3] < 12) {
|
|
config._a[3] += 12;
|
|
}
|
|
// if is 12 am, change hours to 0
|
|
if (config._isPm === false && config._a[3] === 12) {
|
|
config._a[3] = 0;
|
|
}
|
|
// return
|
|
dateFromArray(config);
|
|
}
|
|
|
|
// date from string and array of format strings
|
|
function makeDateFromStringAndArray(config) {
|
|
var tempConfig,
|
|
tempMoment,
|
|
bestMoment,
|
|
|
|
scoreToBeat = 99,
|
|
i,
|
|
currentScore;
|
|
|
|
for (i = 0; i < config._f.length; i++) {
|
|
tempConfig = extend({}, config);
|
|
tempConfig._f = config._f[i];
|
|
makeDateFromStringAndFormat(tempConfig);
|
|
tempMoment = new Moment(tempConfig);
|
|
|
|
currentScore = compareArrays(tempConfig._a, tempMoment.toArray());
|
|
|
|
// if there is any input that was not parsed
|
|
// add a penalty for that format
|
|
if (tempMoment._il) {
|
|
currentScore += tempMoment._il.length;
|
|
}
|
|
|
|
if (currentScore < scoreToBeat) {
|
|
scoreToBeat = currentScore;
|
|
bestMoment = tempMoment;
|
|
}
|
|
}
|
|
|
|
extend(config, bestMoment);
|
|
}
|
|
|
|
// date from iso format
|
|
function makeDateFromString(config) {
|
|
var i,
|
|
string = config._i,
|
|
match = isoRegex.exec(string);
|
|
|
|
if (match) {
|
|
// match[2] should be "T" or undefined
|
|
config._f = 'YYYY-MM-DD' + (match[2] || " ");
|
|
for (i = 0; i < 4; i++) {
|
|
if (isoTimes[i][1].exec(string)) {
|
|
config._f += isoTimes[i][0];
|
|
break;
|
|
}
|
|
}
|
|
if (parseTokenTimezone.exec(string)) {
|
|
config._f += " Z";
|
|
}
|
|
makeDateFromStringAndFormat(config);
|
|
} else {
|
|
config._d = new Date(string);
|
|
}
|
|
}
|
|
|
|
function makeDateFromInput(config) {
|
|
var input = config._i,
|
|
matched = aspNetJsonRegex.exec(input);
|
|
|
|
if (input === undefined) {
|
|
config._d = new Date();
|
|
} else if (matched) {
|
|
config._d = new Date(+matched[1]);
|
|
} else if (typeof input === 'string') {
|
|
makeDateFromString(config);
|
|
} else if (isArray(input)) {
|
|
config._a = input.slice(0);
|
|
dateFromArray(config);
|
|
} else {
|
|
config._d = input instanceof Date ? new Date(+input) : new Date(input);
|
|
}
|
|
}
|
|
|
|
|
|
/************************************
|
|
Relative Time
|
|
************************************/
|
|
|
|
|
|
// helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
|
|
function substituteTimeAgo(string, number, withoutSuffix, isFuture, lang) {
|
|
return lang.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
|
|
}
|
|
|
|
function relativeTime(milliseconds, withoutSuffix, lang) {
|
|
var seconds = round(Math.abs(milliseconds) / 1000),
|
|
minutes = round(seconds / 60),
|
|
hours = round(minutes / 60),
|
|
days = round(hours / 24),
|
|
years = round(days / 365),
|
|
args = seconds < 45 && ['s', seconds] ||
|
|
minutes === 1 && ['m'] ||
|
|
minutes < 45 && ['mm', minutes] ||
|
|
hours === 1 && ['h'] ||
|
|
hours < 22 && ['hh', hours] ||
|
|
days === 1 && ['d'] ||
|
|
days <= 25 && ['dd', days] ||
|
|
days <= 45 && ['M'] ||
|
|
days < 345 && ['MM', round(days / 30)] ||
|
|
years === 1 && ['y'] || ['yy', years];
|
|
args[2] = withoutSuffix;
|
|
args[3] = milliseconds > 0;
|
|
args[4] = lang;
|
|
return substituteTimeAgo.apply({}, args);
|
|
}
|
|
|
|
|
|
/************************************
|
|
Week of Year
|
|
************************************/
|
|
|
|
|
|
// firstDayOfWeek 0 = sun, 6 = sat
|
|
// the day of the week that starts the week
|
|
// (usually sunday or monday)
|
|
// firstDayOfWeekOfYear 0 = sun, 6 = sat
|
|
// the first week is the week that contains the first
|
|
// of this day of the week
|
|
// (eg. ISO weeks use thursday (4))
|
|
function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) {
|
|
var end = firstDayOfWeekOfYear - firstDayOfWeek,
|
|
daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(),
|
|
adjustedMoment;
|
|
|
|
|
|
if (daysToDayOfWeek > end) {
|
|
daysToDayOfWeek -= 7;
|
|
}
|
|
|
|
if (daysToDayOfWeek < end - 7) {
|
|
daysToDayOfWeek += 7;
|
|
}
|
|
|
|
adjustedMoment = moment(mom).add('d', daysToDayOfWeek);
|
|
return {
|
|
week: Math.ceil(adjustedMoment.dayOfYear() / 7),
|
|
year: adjustedMoment.year()
|
|
};
|
|
}
|
|
|
|
|
|
/************************************
|
|
Top Level Functions
|
|
************************************/
|
|
|
|
function makeMoment(config) {
|
|
var input = config._i,
|
|
format = config._f;
|
|
|
|
if (input === null || input === '') {
|
|
return null;
|
|
}
|
|
|
|
if (typeof input === 'string') {
|
|
config._i = input = getLangDefinition().preparse(input);
|
|
}
|
|
|
|
if (moment.isMoment(input)) {
|
|
config = extend({}, input);
|
|
config._d = new Date(+input._d);
|
|
} else if (format) {
|
|
if (isArray(format)) {
|
|
makeDateFromStringAndArray(config);
|
|
} else {
|
|
makeDateFromStringAndFormat(config);
|
|
}
|
|
} else {
|
|
makeDateFromInput(config);
|
|
}
|
|
|
|
return new Moment(config);
|
|
}
|
|
|
|
moment = function (input, format, lang) {
|
|
return makeMoment({
|
|
_i : input,
|
|
_f : format,
|
|
_l : lang,
|
|
_isUTC : false
|
|
});
|
|
};
|
|
|
|
// creating with utc
|
|
moment.utc = function (input, format, lang) {
|
|
return makeMoment({
|
|
_useUTC : true,
|
|
_isUTC : true,
|
|
_l : lang,
|
|
_i : input,
|
|
_f : format
|
|
});
|
|
};
|
|
|
|
// creating with unix timestamp (in seconds)
|
|
moment.unix = function (input) {
|
|
return moment(input * 1000);
|
|
};
|
|
|
|
// duration
|
|
moment.duration = function (input, key) {
|
|
var isDuration = moment.isDuration(input),
|
|
isNumber = (typeof input === 'number'),
|
|
duration = (isDuration ? input._input : (isNumber ? {} : input)),
|
|
matched = aspNetTimeSpanJsonRegex.exec(input),
|
|
sign,
|
|
ret;
|
|
|
|
if (isNumber) {
|
|
if (key) {
|
|
duration[key] = input;
|
|
} else {
|
|
duration.milliseconds = input;
|
|
}
|
|
} else if (matched) {
|
|
sign = (matched[1] === "-") ? -1 : 1;
|
|
duration = {
|
|
y: 0,
|
|
d: ~~matched[2] * sign,
|
|
h: ~~matched[3] * sign,
|
|
m: ~~matched[4] * sign,
|
|
s: ~~matched[5] * sign,
|
|
ms: ~~matched[6] * sign
|
|
};
|
|
}
|
|
|
|
ret = new Duration(duration);
|
|
|
|
if (isDuration && input.hasOwnProperty('_lang')) {
|
|
ret._lang = input._lang;
|
|
}
|
|
|
|
return ret;
|
|
};
|
|
|
|
// version number
|
|
moment.version = VERSION;
|
|
|
|
// default format
|
|
moment.defaultFormat = isoFormat;
|
|
|
|
// This function will be called whenever a moment is mutated.
|
|
// It is intended to keep the offset in sync with the timezone.
|
|
moment.updateOffset = function () {};
|
|
|
|
// This function will load languages and then set the global language. If
|
|
// no arguments are passed in, it will simply return the current global
|
|
// language key.
|
|
moment.lang = function (key, values) {
|
|
if (!key) {
|
|
return moment.fn._lang._abbr;
|
|
}
|
|
if (values) {
|
|
loadLang(key, values);
|
|
} else if (!languages[key]) {
|
|
getLangDefinition(key);
|
|
}
|
|
moment.duration.fn._lang = moment.fn._lang = getLangDefinition(key);
|
|
};
|
|
|
|
// returns language data
|
|
moment.langData = function (key) {
|
|
if (key && key._lang && key._lang._abbr) {
|
|
key = key._lang._abbr;
|
|
}
|
|
return getLangDefinition(key);
|
|
};
|
|
|
|
// compare moment object
|
|
moment.isMoment = function (obj) {
|
|
return obj instanceof Moment;
|
|
};
|
|
|
|
// for typechecking Duration objects
|
|
moment.isDuration = function (obj) {
|
|
return obj instanceof Duration;
|
|
};
|
|
|
|
|
|
/************************************
|
|
Moment Prototype
|
|
************************************/
|
|
|
|
|
|
moment.fn = Moment.prototype = {
|
|
|
|
clone : function () {
|
|
return moment(this);
|
|
},
|
|
|
|
valueOf : function () {
|
|
return +this._d + ((this._offset || 0) * 60000);
|
|
},
|
|
|
|
unix : function () {
|
|
return Math.floor(+this / 1000);
|
|
},
|
|
|
|
toString : function () {
|
|
return this.format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ");
|
|
},
|
|
|
|
toDate : function () {
|
|
return this._offset ? new Date(+this) : this._d;
|
|
},
|
|
|
|
toISOString : function () {
|
|
return formatMoment(moment(this).utc(), 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
|
|
},
|
|
|
|
toArray : function () {
|
|
var m = this;
|
|
return [
|
|
m.year(),
|
|
m.month(),
|
|
m.date(),
|
|
m.hours(),
|
|
m.minutes(),
|
|
m.seconds(),
|
|
m.milliseconds()
|
|
];
|
|
},
|
|
|
|
isValid : function () {
|
|
if (this._isValid == null) {
|
|
if (this._a) {
|
|
this._isValid = !compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray());
|
|
} else {
|
|
this._isValid = !isNaN(this._d.getTime());
|
|
}
|
|
}
|
|
return !!this._isValid;
|
|
},
|
|
|
|
utc : function () {
|
|
return this.zone(0);
|
|
},
|
|
|
|
local : function () {
|
|
this.zone(0);
|
|
this._isUTC = false;
|
|
return this;
|
|
},
|
|
|
|
format : function (inputString) {
|
|
var output = formatMoment(this, inputString || moment.defaultFormat);
|
|
return this.lang().postformat(output);
|
|
},
|
|
|
|
add : function (input, val) {
|
|
var dur;
|
|
// switch args to support add('s', 1) and add(1, 's')
|
|
if (typeof input === 'string') {
|
|
dur = moment.duration(+val, input);
|
|
} else {
|
|
dur = moment.duration(input, val);
|
|
}
|
|
addOrSubtractDurationFromMoment(this, dur, 1);
|
|
return this;
|
|
},
|
|
|
|
subtract : function (input, val) {
|
|
var dur;
|
|
// switch args to support subtract('s', 1) and subtract(1, 's')
|
|
if (typeof input === 'string') {
|
|
dur = moment.duration(+val, input);
|
|
} else {
|
|
dur = moment.duration(input, val);
|
|
}
|
|
addOrSubtractDurationFromMoment(this, dur, -1);
|
|
return this;
|
|
},
|
|
|
|
diff : function (input, units, asFloat) {
|
|
var that = this._isUTC ? moment(input).zone(this._offset || 0) : moment(input).local(),
|
|
zoneDiff = (this.zone() - that.zone()) * 6e4,
|
|
diff, output;
|
|
|
|
units = normalizeUnits(units);
|
|
|
|
if (units === 'year' || units === 'month') {
|
|
// average number of days in the months in the given dates
|
|
diff = (this.daysInMonth() + that.daysInMonth()) * 432e5; // 24 * 60 * 60 * 1000 / 2
|
|
// difference in months
|
|
output = ((this.year() - that.year()) * 12) + (this.month() - that.month());
|
|
// adjust by taking difference in days, average number of days
|
|
// and dst in the given months.
|
|
output += ((this - moment(this).startOf('month')) -
|
|
(that - moment(that).startOf('month'))) / diff;
|
|
// same as above but with zones, to negate all dst
|
|
output -= ((this.zone() - moment(this).startOf('month').zone()) -
|
|
(that.zone() - moment(that).startOf('month').zone())) * 6e4 / diff;
|
|
if (units === 'year') {
|
|
output = output / 12;
|
|
}
|
|
} else {
|
|
diff = (this - that);
|
|
output = units === 'second' ? diff / 1e3 : // 1000
|
|
units === 'minute' ? diff / 6e4 : // 1000 * 60
|
|
units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60
|
|
units === 'day' ? (diff - zoneDiff) / 864e5 : // 1000 * 60 * 60 * 24, negate dst
|
|
units === 'week' ? (diff - zoneDiff) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst
|
|
diff;
|
|
}
|
|
return asFloat ? output : absRound(output);
|
|
},
|
|
|
|
from : function (time, withoutSuffix) {
|
|
return moment.duration(this.diff(time)).lang(this.lang()._abbr).humanize(!withoutSuffix);
|
|
},
|
|
|
|
fromNow : function (withoutSuffix) {
|
|
return this.from(moment(), withoutSuffix);
|
|
},
|
|
|
|
calendar : function () {
|
|
var diff = this.diff(moment().startOf('day'), 'days', true),
|
|
format = diff < -6 ? 'sameElse' :
|
|
diff < -1 ? 'lastWeek' :
|
|
diff < 0 ? 'lastDay' :
|
|
diff < 1 ? 'sameDay' :
|
|
diff < 2 ? 'nextDay' :
|
|
diff < 7 ? 'nextWeek' : 'sameElse';
|
|
return this.format(this.lang().calendar(format, this));
|
|
},
|
|
|
|
isLeapYear : function () {
|
|
var year = this.year();
|
|
return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
|
|
},
|
|
|
|
isDST : function () {
|
|
return (this.zone() < this.clone().month(0).zone() ||
|
|
this.zone() < this.clone().month(5).zone());
|
|
},
|
|
|
|
day : function (input) {
|
|
var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
|
|
if (input != null) {
|
|
if (typeof input === 'string') {
|
|
input = this.lang().weekdaysParse(input);
|
|
if (typeof input !== 'number') {
|
|
return this;
|
|
}
|
|
}
|
|
return this.add({ d : input - day });
|
|
} else {
|
|
return day;
|
|
}
|
|
},
|
|
|
|
month : function (input) {
|
|
var utc = this._isUTC ? 'UTC' : '',
|
|
dayOfMonth,
|
|
daysInMonth;
|
|
|
|
if (input != null) {
|
|
if (typeof input === 'string') {
|
|
input = this.lang().monthsParse(input);
|
|
if (typeof input !== 'number') {
|
|
return this;
|
|
}
|
|
}
|
|
|
|
dayOfMonth = this.date();
|
|
this.date(1);
|
|
this._d['set' + utc + 'Month'](input);
|
|
this.date(Math.min(dayOfMonth, this.daysInMonth()));
|
|
|
|
moment.updateOffset(this);
|
|
return this;
|
|
} else {
|
|
return this._d['get' + utc + 'Month']();
|
|
}
|
|
},
|
|
|
|
startOf: function (units) {
|
|
units = normalizeUnits(units);
|
|
// the following switch intentionally omits break keywords
|
|
// to utilize falling through the cases.
|
|
switch (units) {
|
|
case 'year':
|
|
this.month(0);
|
|
/* falls through */
|
|
case 'month':
|
|
this.date(1);
|
|
/* falls through */
|
|
case 'week':
|
|
case 'day':
|
|
this.hours(0);
|
|
/* falls through */
|
|
case 'hour':
|
|
this.minutes(0);
|
|
/* falls through */
|
|
case 'minute':
|
|
this.seconds(0);
|
|
/* falls through */
|
|
case 'second':
|
|
this.milliseconds(0);
|
|
/* falls through */
|
|
}
|
|
|
|
// weeks are a special case
|
|
if (units === 'week') {
|
|
this.weekday(0);
|
|
}
|
|
|
|
return this;
|
|
},
|
|
|
|
endOf: function (units) {
|
|
return this.startOf(units).add(units, 1).subtract('ms', 1);
|
|
},
|
|
|
|
isAfter: function (input, units) {
|
|
units = typeof units !== 'undefined' ? units : 'millisecond';
|
|
return +this.clone().startOf(units) > +moment(input).startOf(units);
|
|
},
|
|
|
|
isBefore: function (input, units) {
|
|
units = typeof units !== 'undefined' ? units : 'millisecond';
|
|
return +this.clone().startOf(units) < +moment(input).startOf(units);
|
|
},
|
|
|
|
isSame: function (input, units) {
|
|
units = typeof units !== 'undefined' ? units : 'millisecond';
|
|
return +this.clone().startOf(units) === +moment(input).startOf(units);
|
|
},
|
|
|
|
min: function (other) {
|
|
other = moment.apply(null, arguments);
|
|
return other < this ? this : other;
|
|
},
|
|
|
|
max: function (other) {
|
|
other = moment.apply(null, arguments);
|
|
return other > this ? this : other;
|
|
},
|
|
|
|
zone : function (input) {
|
|
var offset = this._offset || 0;
|
|
if (input != null) {
|
|
if (typeof input === "string") {
|
|
input = timezoneMinutesFromString(input);
|
|
}
|
|
if (Math.abs(input) < 16) {
|
|
input = input * 60;
|
|
}
|
|
this._offset = input;
|
|
this._isUTC = true;
|
|
if (offset !== input) {
|
|
addOrSubtractDurationFromMoment(this, moment.duration(offset - input, 'm'), 1, true);
|
|
}
|
|
} else {
|
|
return this._isUTC ? offset : this._d.getTimezoneOffset();
|
|
}
|
|
return this;
|
|
},
|
|
|
|
zoneAbbr : function () {
|
|
return this._isUTC ? "UTC" : "";
|
|
},
|
|
|
|
zoneName : function () {
|
|
return this._isUTC ? "Coordinated Universal Time" : "";
|
|
},
|
|
|
|
daysInMonth : function () {
|
|
return moment.utc([this.year(), this.month() + 1, 0]).date();
|
|
},
|
|
|
|
dayOfYear : function (input) {
|
|
var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1;
|
|
return input == null ? dayOfYear : this.add("d", (input - dayOfYear));
|
|
},
|
|
|
|
weekYear : function (input) {
|
|
var year = weekOfYear(this, this.lang()._week.dow, this.lang()._week.doy).year;
|
|
return input == null ? year : this.add("y", (input - year));
|
|
},
|
|
|
|
isoWeekYear : function (input) {
|
|
var year = weekOfYear(this, 1, 4).year;
|
|
return input == null ? year : this.add("y", (input - year));
|
|
},
|
|
|
|
week : function (input) {
|
|
var week = this.lang().week(this);
|
|
return input == null ? week : this.add("d", (input - week) * 7);
|
|
},
|
|
|
|
isoWeek : function (input) {
|
|
var week = weekOfYear(this, 1, 4).week;
|
|
return input == null ? week : this.add("d", (input - week) * 7);
|
|
},
|
|
|
|
weekday : function (input) {
|
|
var weekday = (this._d.getDay() + 7 - this.lang()._week.dow) % 7;
|
|
return input == null ? weekday : this.add("d", input - weekday);
|
|
},
|
|
|
|
isoWeekday : function (input) {
|
|
// behaves the same as moment#day except
|
|
// as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
|
|
// as a setter, sunday should belong to the previous week.
|
|
return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7);
|
|
},
|
|
|
|
// If passed a language key, it will set the language for this
|
|
// instance. Otherwise, it will return the language configuration
|
|
// variables for this instance.
|
|
lang : function (key) {
|
|
if (key === undefined) {
|
|
return this._lang;
|
|
} else {
|
|
this._lang = getLangDefinition(key);
|
|
return this;
|
|
}
|
|
}
|
|
};
|
|
|
|
// helper for adding shortcuts
|
|
function makeGetterAndSetter(name, key) {
|
|
moment.fn[name] = moment.fn[name + 's'] = function (input) {
|
|
var utc = this._isUTC ? 'UTC' : '';
|
|
if (input != null) {
|
|
this._d['set' + utc + key](input);
|
|
moment.updateOffset(this);
|
|
return this;
|
|
} else {
|
|
return this._d['get' + utc + key]();
|
|
}
|
|
};
|
|
}
|
|
|
|
// loop through and add shortcuts (Month, Date, Hours, Minutes, Seconds, Milliseconds)
|
|
for (i = 0; i < proxyGettersAndSetters.length; i ++) {
|
|
makeGetterAndSetter(proxyGettersAndSetters[i].toLowerCase().replace(/s$/, ''), proxyGettersAndSetters[i]);
|
|
}
|
|
|
|
// add shortcut for year (uses different syntax than the getter/setter 'year' == 'FullYear')
|
|
makeGetterAndSetter('year', 'FullYear');
|
|
|
|
// add plural methods
|
|
moment.fn.days = moment.fn.day;
|
|
moment.fn.months = moment.fn.month;
|
|
moment.fn.weeks = moment.fn.week;
|
|
moment.fn.isoWeeks = moment.fn.isoWeek;
|
|
|
|
// add aliased format methods
|
|
moment.fn.toJSON = moment.fn.toISOString;
|
|
|
|
/************************************
|
|
Duration Prototype
|
|
************************************/
|
|
|
|
|
|
moment.duration.fn = Duration.prototype = {
|
|
_bubble : function () {
|
|
var milliseconds = this._milliseconds,
|
|
days = this._days,
|
|
months = this._months,
|
|
data = this._data,
|
|
seconds, minutes, hours, years;
|
|
|
|
// The following code bubbles up values, see the tests for
|
|
// examples of what that means.
|
|
data.milliseconds = milliseconds % 1000;
|
|
|
|
seconds = absRound(milliseconds / 1000);
|
|
data.seconds = seconds % 60;
|
|
|
|
minutes = absRound(seconds / 60);
|
|
data.minutes = minutes % 60;
|
|
|
|
hours = absRound(minutes / 60);
|
|
data.hours = hours % 24;
|
|
|
|
days += absRound(hours / 24);
|
|
data.days = days % 30;
|
|
|
|
months += absRound(days / 30);
|
|
data.months = months % 12;
|
|
|
|
years = absRound(months / 12);
|
|
data.years = years;
|
|
},
|
|
|
|
weeks : function () {
|
|
return absRound(this.days() / 7);
|
|
},
|
|
|
|
valueOf : function () {
|
|
return this._milliseconds +
|
|
this._days * 864e5 +
|
|
(this._months % 12) * 2592e6 +
|
|
~~(this._months / 12) * 31536e6;
|
|
},
|
|
|
|
humanize : function (withSuffix) {
|
|
var difference = +this,
|
|
output = relativeTime(difference, !withSuffix, this.lang());
|
|
|
|
if (withSuffix) {
|
|
output = this.lang().pastFuture(difference, output);
|
|
}
|
|
|
|
return this.lang().postformat(output);
|
|
},
|
|
|
|
add : function (input, val) {
|
|
// supports only 2.0-style add(1, 's') or add(moment)
|
|
var dur = moment.duration(input, val);
|
|
|
|
this._milliseconds += dur._milliseconds;
|
|
this._days += dur._days;
|
|
this._months += dur._months;
|
|
|
|
this._bubble();
|
|
|
|
return this;
|
|
},
|
|
|
|
subtract : function (input, val) {
|
|
var dur = moment.duration(input, val);
|
|
|
|
this._milliseconds -= dur._milliseconds;
|
|
this._days -= dur._days;
|
|
this._months -= dur._months;
|
|
|
|
this._bubble();
|
|
|
|
return this;
|
|
},
|
|
|
|
get : function (units) {
|
|
units = normalizeUnits(units);
|
|
return this[units.toLowerCase() + 's']();
|
|
},
|
|
|
|
as : function (units) {
|
|
units = normalizeUnits(units);
|
|
return this['as' + units.charAt(0).toUpperCase() + units.slice(1) + 's']();
|
|
},
|
|
|
|
lang : moment.fn.lang
|
|
};
|
|
|
|
function makeDurationGetter(name) {
|
|
moment.duration.fn[name] = function () {
|
|
return this._data[name];
|
|
};
|
|
}
|
|
|
|
function makeDurationAsGetter(name, factor) {
|
|
moment.duration.fn['as' + name] = function () {
|
|
return +this / factor;
|
|
};
|
|
}
|
|
|
|
for (i in unitMillisecondFactors) {
|
|
if (unitMillisecondFactors.hasOwnProperty(i)) {
|
|
makeDurationAsGetter(i, unitMillisecondFactors[i]);
|
|
makeDurationGetter(i.toLowerCase());
|
|
}
|
|
}
|
|
|
|
makeDurationAsGetter('Weeks', 6048e5);
|
|
moment.duration.fn.asMonths = function () {
|
|
return (+this - this.years() * 31536e6) / 2592e6 + this.years() * 12;
|
|
};
|
|
|
|
|
|
/************************************
|
|
Default Lang
|
|
************************************/
|
|
|
|
|
|
// Set default language, other languages will inherit from English.
|
|
moment.lang('en', {
|
|
ordinal : function (number) {
|
|
var b = number % 10,
|
|
output = (~~ (number % 100 / 10) === 1) ? 'th' :
|
|
(b === 1) ? 'st' :
|
|
(b === 2) ? 'nd' :
|
|
(b === 3) ? 'rd' : 'th';
|
|
return number + output;
|
|
}
|
|
});
|
|
|
|
|
|
/************************************
|
|
Exposing Moment
|
|
************************************/
|
|
|
|
|
|
// CommonJS module is defined
|
|
if (hasModule) {
|
|
module.exports = moment;
|
|
}
|
|
/*global ender:false */
|
|
if (typeof ender === 'undefined') {
|
|
// here, `this` means `window` in the browser, or `global` on the server
|
|
// add `moment` as a global object via a string identifier,
|
|
// for Closure Compiler "advanced" mode
|
|
this['moment'] = moment;
|
|
}
|
|
/*global define:false */
|
|
if (typeof define === "function" && define.amd) {
|
|
define("moment", [], function () {
|
|
return moment;
|
|
});
|
|
}
|
|
}).call(this);
|
|
|
|
},{}],4:[function(require,module,exports){
|
|
var relativeDate = (function(undefined){
|
|
|
|
var SECOND = 1000,
|
|
MINUTE = 60 * SECOND,
|
|
HOUR = 60 * MINUTE,
|
|
DAY = 24 * HOUR,
|
|
WEEK = 7 * DAY,
|
|
YEAR = DAY * 365,
|
|
MONTH = YEAR / 12;
|
|
|
|
var formats = [
|
|
[ 0.7 * MINUTE, 'just now' ],
|
|
[ 1.5 * MINUTE, 'a minute ago' ],
|
|
[ 60 * MINUTE, 'minutes ago', MINUTE ],
|
|
[ 1.5 * HOUR, 'an hour ago' ],
|
|
[ DAY, 'hours ago', HOUR ],
|
|
[ 2 * DAY, 'yesterday' ],
|
|
[ 7 * DAY, 'days ago', DAY ],
|
|
[ 1.5 * WEEK, 'a week ago'],
|
|
[ MONTH, 'weeks ago', WEEK ],
|
|
[ 1.5 * MONTH, 'a month ago' ],
|
|
[ YEAR, 'months ago', MONTH ],
|
|
[ 1.5 * YEAR, 'a year ago' ],
|
|
[ Number.MAX_VALUE, 'years ago', YEAR ]
|
|
];
|
|
|
|
function relativeDate(input,reference){
|
|
!reference && ( reference = (new Date).getTime() );
|
|
reference instanceof Date && ( reference = reference.getTime() );
|
|
input instanceof Date && ( input = input.getTime() );
|
|
|
|
var delta = reference - input,
|
|
format, i, len;
|
|
|
|
for(i = -1, len=formats.length; ++i < len; ){
|
|
format = formats[i];
|
|
if(delta < format[0]){
|
|
return format[2] == undefined ? format[1] : Math.round(delta/format[2]) + ' ' + format[1];
|
|
}
|
|
};
|
|
}
|
|
|
|
return relativeDate;
|
|
|
|
})();
|
|
|
|
if(typeof module != 'undefined' && module.exports){
|
|
module.exports = relativeDate;
|
|
}
|
|
|
|
},{}],5:[function(require,module,exports){
|
|
(function() {
|
|
var HP, XP, hatchingPotions, helpers, items, moment, obj, pets, randomDrop, updateStats, _, _ref,
|
|
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
|
|
|
|
moment = require('moment');
|
|
|
|
_ = require('lodash');
|
|
|
|
helpers = require('./helpers.coffee');
|
|
|
|
items = require('./items.coffee');
|
|
|
|
_ref = items.items, pets = _ref.pets, hatchingPotions = _ref.hatchingPotions;
|
|
|
|
XP = 15;
|
|
|
|
HP = 2;
|
|
|
|
obj = module.exports = {};
|
|
|
|
obj.revive = function(user, options) {
|
|
var candidate, loseThisItem, owned, paths;
|
|
|
|
if (options == null) {
|
|
options = {};
|
|
}
|
|
paths = options.paths || {};
|
|
user.stats.hp = 50;
|
|
user.stats.exp = 0;
|
|
user.stats.gp = 0;
|
|
if (user.stats.lvl > 1) {
|
|
user.stats.lvl--;
|
|
}
|
|
loseThisItem = false;
|
|
owned = user.items;
|
|
if (~~owned.armor > 0 || ~~owned.head > 0 || ~~owned.shield > 0 || ~~owned.weapon > 0) {
|
|
while (!loseThisItem) {
|
|
candidate = {
|
|
0: 'armor',
|
|
1: 'head',
|
|
2: 'shield',
|
|
3: 'weapon'
|
|
}[Math.random() * 4 | 0];
|
|
if (owned[candidate] > 0) {
|
|
loseThisItem = candidate;
|
|
}
|
|
}
|
|
user.items[loseThisItem] = 0;
|
|
}
|
|
return ("stats.hp stats.exp stats.gp stats.lvl items." + loseThisItem).split(' ').forEach(function(path) {
|
|
return paths[path] = 1;
|
|
});
|
|
};
|
|
|
|
obj.priorityValue = function(priority) {
|
|
if (priority == null) {
|
|
priority = '!';
|
|
}
|
|
switch (priority) {
|
|
case '!':
|
|
return 1;
|
|
case '!!':
|
|
return 1.5;
|
|
case '!!!':
|
|
return 2;
|
|
default:
|
|
return 1;
|
|
}
|
|
};
|
|
|
|
obj.tnl = function(level) {
|
|
var value;
|
|
|
|
if (level >= 100) {
|
|
value = 0;
|
|
} else {
|
|
value = Math.round(((Math.pow(level, 2) * 0.25) + (10 * level) + 139.75) / 10) * 10;
|
|
}
|
|
return value;
|
|
};
|
|
|
|
/*
|
|
Calculates Exp modificaiton based on level and weapon strength
|
|
{value} task.value for exp gain
|
|
{weaponStrength) weapon strength
|
|
{level} current user level
|
|
{priority} user-defined priority multiplier
|
|
*/
|
|
|
|
|
|
obj.expModifier = function(value, weaponStr, level, priority) {
|
|
var exp, str, strMod, totalStr;
|
|
|
|
if (priority == null) {
|
|
priority = '!';
|
|
}
|
|
str = (level - 1) / 2;
|
|
totalStr = (str + weaponStr) / 100;
|
|
strMod = 1 + totalStr;
|
|
exp = value * XP * strMod * obj.priorityValue(priority);
|
|
return Math.round(exp);
|
|
};
|
|
|
|
/*
|
|
Calculates HP modification based on level and armor defence
|
|
{value} task.value for hp loss
|
|
{armorDefense} defense from armor
|
|
{helmDefense} defense from helm
|
|
{level} current user level
|
|
{priority} user-defined priority multiplier
|
|
*/
|
|
|
|
|
|
obj.hpModifier = function(value, armorDef, helmDef, shieldDef, level, priority) {
|
|
var def, defMod, hp, totalDef;
|
|
|
|
if (priority == null) {
|
|
priority = '!';
|
|
}
|
|
def = (level - 1) / 2;
|
|
totalDef = (def + armorDef + helmDef + shieldDef) / 100;
|
|
defMod = 1 - totalDef;
|
|
hp = value * HP * defMod * obj.priorityValue(priority);
|
|
return Math.round(hp * 10) / 10;
|
|
};
|
|
|
|
/*
|
|
Future use
|
|
{priority} user-defined priority multiplier
|
|
*/
|
|
|
|
|
|
obj.gpModifier = function(value, modifier, priority, streak, user) {
|
|
var afterStreak, streakBonus, val, _ref1;
|
|
|
|
if (priority == null) {
|
|
priority = '!';
|
|
}
|
|
val = value * modifier * obj.priorityValue(priority);
|
|
if (streak && user) {
|
|
streakBonus = streak / 100 + 1;
|
|
afterStreak = val * streakBonus;
|
|
if (val > 0) {
|
|
((_ref1 = user._tmp) != null ? _ref1 : user._tmp = {}).streakBonus = afterStreak - val;
|
|
}
|
|
return afterStreak;
|
|
} else {
|
|
return val;
|
|
}
|
|
};
|
|
|
|
/*
|
|
Calculates the next task.value based on direction
|
|
Uses a capped inverse log y=.95^x, y>= -5
|
|
{currentValue} the current value of the task
|
|
{direction} up or down
|
|
*/
|
|
|
|
|
|
obj.taskDeltaFormula = function(currentValue, direction) {
|
|
var delta;
|
|
|
|
if (currentValue < -47.27) {
|
|
currentValue = -47.27;
|
|
} else if (currentValue > 21.27) {
|
|
currentValue = 21.27;
|
|
}
|
|
delta = Math.pow(0.9747, currentValue);
|
|
if (direction === 'up') {
|
|
return delta;
|
|
}
|
|
return -delta;
|
|
};
|
|
|
|
/*
|
|
Drop System
|
|
*/
|
|
|
|
|
|
randomDrop = function(user, delta, priority, streak, options) {
|
|
var acceptableDrops, chanceMultiplier, drop, paths, rarity, reachedDropLimit, _base, _base1, _base2, _ref1, _ref2, _ref3, _ref4, _ref5;
|
|
|
|
if (streak == null) {
|
|
streak = 0;
|
|
}
|
|
if (options == null) {
|
|
options = {};
|
|
}
|
|
paths = options.paths || {};
|
|
if ((_ref1 = (_base = user.items).lastDrop) == null) {
|
|
_base.lastDrop = {
|
|
date: +moment().subtract('d', 1),
|
|
count: 0
|
|
};
|
|
}
|
|
paths['items.lastDrop'] = true;
|
|
reachedDropLimit = (helpers.daysSince(user.items.lastDrop.date, user.preferences) === 0) && (user.items.lastDrop.count >= 2);
|
|
if (reachedDropLimit) {
|
|
return;
|
|
}
|
|
chanceMultiplier = Math.abs(delta);
|
|
chanceMultiplier *= obj.priorityValue(priority);
|
|
chanceMultiplier += streak;
|
|
if (((_ref2 = user.flags) != null ? _ref2.dropsEnabled : void 0) && Math.random() < (.05 * chanceMultiplier)) {
|
|
rarity = Math.random();
|
|
if (rarity > .5) {
|
|
drop = helpers.randomVal(pets);
|
|
((_ref3 = (_base1 = user.items).eggs) != null ? _ref3 : _base1.eggs = []).push(drop);
|
|
paths['items.eggs'] = true;
|
|
drop.type = 'Egg';
|
|
drop.dialog = "You've found a " + drop.text + " Egg! " + drop.notes;
|
|
} else {
|
|
acceptableDrops = [];
|
|
if (rarity < .1) {
|
|
acceptableDrops = ['Base', 'White', 'Desert', 'Red', 'Shade', 'Skeleton', 'Zombie', 'CottonCandyPink', 'CottonCandyBlue', 'Golden'];
|
|
} else if (rarity < .2) {
|
|
acceptableDrops = ['Base', 'White', 'Desert', 'Red', 'Shade', 'Skeleton', 'Zombie', 'CottonCandyPink', 'CottonCandyBlue'];
|
|
} else if (rarity < .3) {
|
|
acceptableDrops = ['Base', 'White', 'Desert', 'Red', 'Shade', 'Skeleton'];
|
|
} else {
|
|
acceptableDrops = ['Base', 'White', 'Desert'];
|
|
}
|
|
acceptableDrops = hatchingPotions.filter(function(hatchingPotion) {
|
|
var _ref4;
|
|
|
|
return _ref4 = hatchingPotion.name, __indexOf.call(acceptableDrops, _ref4) >= 0;
|
|
});
|
|
drop = helpers.randomVal(acceptableDrops);
|
|
((_ref4 = (_base2 = user.items).hatchingPotions) != null ? _ref4 : _base2.hatchingPotions = []).push(drop.name);
|
|
paths['items.hatchingPotions'] = true;
|
|
drop.type = 'HatchingPotion';
|
|
drop.dialog = "You've found a " + drop.text + " Hatching Potion! " + drop.notes;
|
|
}
|
|
((_ref5 = user._tmp) != null ? _ref5 : user._tmp = {}).drop = drop;
|
|
user.items.lastDrop.date = +(new Date);
|
|
user.items.lastDrop.count++;
|
|
return paths['items.lastDrop'] = true;
|
|
}
|
|
};
|
|
|
|
obj.score = function(user, task, direction, options) {
|
|
var addPoints, calculateDelta, cron, delta, exp, gp, hp, lvl, num, paths, priority, streak, subtractPoints, times, type, value, _ref1, _ref2, _ref3, _ref4;
|
|
|
|
if (options == null) {
|
|
options = {};
|
|
}
|
|
_ref1 = [+user.stats.gp, +user.stats.hp, +user.stats.exp, ~~user.stats.lvl], gp = _ref1[0], hp = _ref1[1], exp = _ref1[2], lvl = _ref1[3];
|
|
_ref2 = [task.type, +task.value, ~~task.streak, task.priority || '!'], type = _ref2[0], value = _ref2[1], streak = _ref2[2], priority = _ref2[3];
|
|
_ref3 = [options.paths || {}, options.times || 1, options.cron || false], paths = _ref3[0], times = _ref3[1], cron = _ref3[2];
|
|
if (!task.id) {
|
|
return 0;
|
|
}
|
|
if (!_.isNumber(value) || _.isNaN(value)) {
|
|
task.value = value = 0;
|
|
paths["tasks." + task.id + ".value"] = true;
|
|
}
|
|
_.each(user.stats, function(v, k) {
|
|
if (!_.isNumber(v) || _.isNaN(v)) {
|
|
user.stats[k] = 0;
|
|
return paths["stats." + k] = true;
|
|
}
|
|
});
|
|
if (task.value > user.stats.gp && task.type === 'reward') {
|
|
return;
|
|
}
|
|
delta = 0;
|
|
calculateDelta = function(adjustvalue) {
|
|
if (adjustvalue == null) {
|
|
adjustvalue = true;
|
|
}
|
|
return _.times(times, function() {
|
|
var nextDelta;
|
|
|
|
nextDelta = obj.taskDeltaFormula(value, direction);
|
|
if (adjustvalue) {
|
|
value += nextDelta;
|
|
}
|
|
return delta += nextDelta;
|
|
});
|
|
};
|
|
addPoints = function() {
|
|
var weaponStr;
|
|
|
|
weaponStr = items.getItem('weapon', user.items.weapon).strength;
|
|
exp += obj.expModifier(delta, weaponStr, user.stats.lvl, priority) / 2;
|
|
if (streak) {
|
|
return gp += obj.gpModifier(delta, 1, priority, streak, user);
|
|
} else {
|
|
return gp += obj.gpModifier(delta, 1, priority);
|
|
}
|
|
};
|
|
subtractPoints = function() {
|
|
var armorDef, headDef, shieldDef;
|
|
|
|
armorDef = items.getItem('armor', user.items.armor).defense;
|
|
headDef = items.getItem('head', user.items.head).defense;
|
|
shieldDef = items.getItem('shield', user.items.shield).defense;
|
|
return hp += obj.hpModifier(delta, armorDef, headDef, shieldDef, user.stats.lvl, priority);
|
|
};
|
|
switch (type) {
|
|
case 'habit':
|
|
calculateDelta();
|
|
if (delta > 0) {
|
|
addPoints();
|
|
} else {
|
|
subtractPoints();
|
|
}
|
|
if (task.value !== value) {
|
|
((_ref4 = task.history) != null ? _ref4 : task.history = []).push({
|
|
date: +(new Date),
|
|
value: value
|
|
});
|
|
paths["tasks." + task.id + ".history"] = true;
|
|
}
|
|
break;
|
|
case 'daily':
|
|
if (cron) {
|
|
calculateDelta();
|
|
subtractPoints();
|
|
task.streak = 0;
|
|
} else {
|
|
calculateDelta();
|
|
addPoints();
|
|
if (direction === 'up') {
|
|
streak = streak ? streak + 1 : 1;
|
|
} else {
|
|
streak = streak ? streak - 1 : 0;
|
|
}
|
|
task.streak = streak;
|
|
}
|
|
paths["tasks." + task.id + ".streak"] = true;
|
|
break;
|
|
case 'todo':
|
|
if (cron) {
|
|
calculateDelta();
|
|
} else {
|
|
calculateDelta();
|
|
addPoints();
|
|
}
|
|
break;
|
|
case 'reward':
|
|
calculateDelta(false);
|
|
gp -= Math.abs(task.value);
|
|
num = parseFloat(task.value).toFixed(2);
|
|
if (gp < 0) {
|
|
hp += gp;
|
|
gp = 0;
|
|
}
|
|
}
|
|
task.value = value;
|
|
paths["tasks." + task.id + ".value"] = true;
|
|
updateStats(user, {
|
|
hp: hp,
|
|
exp: exp,
|
|
gp: gp
|
|
}, {
|
|
paths: paths
|
|
});
|
|
if (direction === 'up') {
|
|
randomDrop(user, delta, priority, streak, {
|
|
paths: paths
|
|
});
|
|
}
|
|
return delta;
|
|
};
|
|
|
|
/*
|
|
Updates user stats with new stats. Handles death, leveling up, etc
|
|
{stats} new stats
|
|
{update} if aggregated changes, pass in userObj as update. otherwise commits will be made immediately
|
|
*/
|
|
|
|
|
|
updateStats = function(user, newStats, options) {
|
|
var gp, paths, tnl, _ref1;
|
|
|
|
if (options == null) {
|
|
options = {};
|
|
}
|
|
paths = options.paths || {};
|
|
if (user.stats.hp <= 0) {
|
|
return;
|
|
}
|
|
if (newStats.hp != null) {
|
|
if (newStats.hp <= 0) {
|
|
user.stats.hp = 0;
|
|
paths['stats.hp'] = true;
|
|
return;
|
|
} else {
|
|
user.stats.hp = newStats.hp;
|
|
paths['stats.hp'] = true;
|
|
}
|
|
}
|
|
if (newStats.exp != null) {
|
|
tnl = obj.tnl(user.stats.lvl);
|
|
if (user.stats.lvl >= 100) {
|
|
newStats.gp += newStats.exp / 15;
|
|
newStats.exp = 0;
|
|
user.stats.lvl = 100;
|
|
} else {
|
|
if (newStats.exp >= tnl) {
|
|
user.stats.exp = newStats.exp;
|
|
while (newStats.exp >= tnl && user.stats.lvl < 100) {
|
|
newStats.exp -= tnl;
|
|
user.stats.lvl++;
|
|
tnl = obj.tnl(user.stats.lvl);
|
|
}
|
|
if (user.stats.lvl === 100) {
|
|
newStats.exp = 0;
|
|
}
|
|
user.stats.hp = 50;
|
|
}
|
|
}
|
|
user.stats.exp = newStats.exp;
|
|
paths["stats.exp"] = true;
|
|
paths['stats.lvl'] = true;
|
|
paths['stats.gp'] = true;
|
|
paths['stats.hp'] = true;
|
|
if ((_ref1 = user.flags) == null) {
|
|
user.flags = {};
|
|
}
|
|
if (!user.flags.customizationsNotification && (user.stats.exp > 10 || user.stats.lvl > 1)) {
|
|
user.flags.customizationsNotification = true;
|
|
paths['flags.customizationsNotification'] = true;
|
|
}
|
|
if (!user.flags.itemsEnabled && user.stats.lvl >= 2) {
|
|
user.flags.itemsEnabled = true;
|
|
paths['flags.itemsEnabled'] = true;
|
|
}
|
|
if (!user.flags.partyEnabled && user.stats.lvl >= 3) {
|
|
user.flags.partyEnabled = true;
|
|
paths['flags.partyEnabled'] = true;
|
|
}
|
|
if (!user.flags.dropsEnabled && user.stats.lvl >= 4) {
|
|
user.flags.dropsEnabled = true;
|
|
paths['flags.dropsEnabled'] = true;
|
|
}
|
|
}
|
|
if (newStats.gp != null) {
|
|
if ((typeof gp === "undefined" || gp === null) || gp < 0) {
|
|
gp = 0.0;
|
|
}
|
|
return user.stats.gp = newStats.gp;
|
|
}
|
|
};
|
|
|
|
/*
|
|
At end of day, add value to all incomplete Daily & Todo tasks (further incentive)
|
|
For incomplete Dailys, deduct experience
|
|
Make sure to run this function once in a while as server will not take care of overnight calculations.
|
|
And you have to run it every time client connects.
|
|
{user}
|
|
*/
|
|
|
|
|
|
obj.cron = function(user, options) {
|
|
var daysMissed, expTally, lvl, now, paths, todoTally, _base, _base1, _ref1, _ref2, _ref3, _ref4;
|
|
|
|
if (options == null) {
|
|
options = {};
|
|
}
|
|
_ref1 = [options.paths || {}, +options.now || +(new Date)], paths = _ref1[0], now = _ref1[1];
|
|
if ((user.lastCron == null) || user.lastCron === 'new' || moment(user.lastCron).isAfter(now)) {
|
|
user.lastCron = now;
|
|
paths['lastCron'] = true;
|
|
return;
|
|
}
|
|
daysMissed = helpers.daysSince(user.lastCron, _.defaults({
|
|
now: now
|
|
}, user.preferences));
|
|
if (!(daysMissed > 0)) {
|
|
return;
|
|
}
|
|
user.lastCron = now;
|
|
paths['lastCron'] = true;
|
|
if (user.flags.rest === true) {
|
|
return;
|
|
}
|
|
todoTally = 0;
|
|
user.todos.concat(user.dailys).forEach(function(task) {
|
|
var absVal, completed, id, repeat, scheduleMisses, type, _ref2;
|
|
|
|
if (!task) {
|
|
return;
|
|
}
|
|
id = task.id, type = task.type, completed = task.completed, repeat = task.repeat;
|
|
if (!completed) {
|
|
scheduleMisses = daysMissed;
|
|
if ((type === 'daily') && repeat) {
|
|
scheduleMisses = 0;
|
|
_.times(daysMissed, function(n) {
|
|
var thatDay;
|
|
|
|
thatDay = moment(now).subtract('days', n + 1);
|
|
if (helpers.shouldDo(thatDay, repeat, user.preferences)) {
|
|
return scheduleMisses++;
|
|
}
|
|
});
|
|
}
|
|
if (scheduleMisses > 0) {
|
|
obj.score(user, task, 'down', {
|
|
times: scheduleMisses,
|
|
cron: true,
|
|
paths: paths
|
|
});
|
|
}
|
|
}
|
|
switch (type) {
|
|
case 'daily':
|
|
((_ref2 = task.history) != null ? _ref2 : task.history = []).push({
|
|
date: +(new Date),
|
|
value: task.value
|
|
});
|
|
paths["tasks." + task.id + ".history"] = true;
|
|
task.completed = false;
|
|
return paths["tasks." + task.id + ".completed"] = true;
|
|
case 'todo':
|
|
absVal = completed ? Math.abs(task.value) : task.value;
|
|
return todoTally += absVal;
|
|
}
|
|
});
|
|
user.habits.forEach(function(task) {
|
|
if (task.up === false || task.down === false) {
|
|
if (Math.abs(task.value) < 0.1) {
|
|
task.value = 0;
|
|
} else {
|
|
task.value = task.value / 2;
|
|
}
|
|
return paths["tasks." + task.id + ".value"] = true;
|
|
}
|
|
});
|
|
((_ref2 = (_base = ((_ref3 = user.history) != null ? _ref3 : user.history = {})).todos) != null ? _ref2 : _base.todos = []).push({
|
|
date: now,
|
|
value: todoTally
|
|
});
|
|
expTally = user.stats.exp;
|
|
lvl = 0;
|
|
while (lvl < (user.stats.lvl - 1)) {
|
|
lvl++;
|
|
expTally += obj.tnl(lvl);
|
|
}
|
|
((_ref4 = (_base1 = user.history).exp) != null ? _ref4 : _base1.exp = []).push({
|
|
date: now,
|
|
value: expTally
|
|
});
|
|
paths["history"] = true;
|
|
return user;
|
|
};
|
|
|
|
}).call(this);
|
|
|
|
|
|
},{"./helpers.coffee":6,"./items.coffee":8,"lodash":2,"moment":3}],6:[function(require,module,exports){
|
|
var process=require("__browserify_process");(function() {
|
|
var dayMapping, daysSince, items, moment, sanitizeOptions, shouldDo, startOfDay, startOfWeek, uuid, _;
|
|
|
|
moment = require('moment');
|
|
|
|
_ = require('lodash');
|
|
|
|
items = require('./items.coffee');
|
|
|
|
/*
|
|
Each time we're performing date math (cron, task-due-days, etc), we need to take user preferences into consideration.
|
|
Specifically {dayStart} (custom day start) and {timezoneOffset}. This function sanitizes / defaults those values.
|
|
{now} is also passed in for various purposes, one example being the test scripts scripts testing different "now" times
|
|
*/
|
|
|
|
|
|
sanitizeOptions = function(o) {
|
|
var dayStart, now, timezoneOffset, _ref;
|
|
|
|
dayStart = o.dayStart && (0 <= (_ref = +o.dayStart) && _ref <= 24) ? +o.dayStart : 0;
|
|
timezoneOffset = o.timezoneOffset ? +o.timezoneOffset : +moment().zone();
|
|
now = o.now ? moment(o.now).zone(timezoneOffset) : moment(+(new Date)).zone(timezoneOffset);
|
|
return {
|
|
dayStart: dayStart,
|
|
timezoneOffset: timezoneOffset,
|
|
now: now
|
|
};
|
|
};
|
|
|
|
startOfWeek = function(options) {
|
|
var o;
|
|
|
|
if (options == null) {
|
|
options = {};
|
|
}
|
|
o = sanitizeOptions(options);
|
|
return moment(o.now).startOf('week');
|
|
};
|
|
|
|
startOfDay = function(options) {
|
|
var o;
|
|
|
|
if (options == null) {
|
|
options = {};
|
|
}
|
|
o = sanitizeOptions(options);
|
|
return moment(o.now).startOf('day').add('h', options.dayStart);
|
|
};
|
|
|
|
dayMapping = {
|
|
0: 'su',
|
|
1: 'm',
|
|
2: 't',
|
|
3: 'w',
|
|
4: 'th',
|
|
5: 'f',
|
|
6: 's'
|
|
};
|
|
|
|
/*
|
|
Absolute diff from "yesterday" till now
|
|
*/
|
|
|
|
|
|
daysSince = function(yesterday, options) {
|
|
var o;
|
|
|
|
if (options == null) {
|
|
options = {};
|
|
}
|
|
o = sanitizeOptions(options);
|
|
return Math.abs(startOfDay(_.defaults({
|
|
now: yesterday
|
|
}, o)).diff(o.now, 'days'));
|
|
};
|
|
|
|
/*
|
|
Should the user do this taks on this date, given the task's repeat options and user.preferences.dayStart?
|
|
*/
|
|
|
|
|
|
shouldDo = function(day, repeat, options) {
|
|
var o, selected, yesterday;
|
|
|
|
if (options == null) {
|
|
options = {};
|
|
}
|
|
if (!repeat) {
|
|
return false;
|
|
}
|
|
o = sanitizeOptions(options);
|
|
selected = repeat[dayMapping[startOfDay(_.defaults({
|
|
now: day
|
|
}, o)).day()]];
|
|
if (!moment(day).zone(o.timezoneOffset).isSame(o.now, 'd')) {
|
|
return selected;
|
|
}
|
|
if (options.dayStart <= o.now.hour()) {
|
|
return selected;
|
|
} else {
|
|
yesterday = moment(o.now).subtract(1, 'd').day();
|
|
return repeat[dayMapping[yesterday]];
|
|
}
|
|
};
|
|
|
|
uuid = function() {
|
|
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
|
|
var r, v;
|
|
|
|
r = Math.random() * 16 | 0;
|
|
v = (c === "x" ? r : r & 0x3 | 0x8);
|
|
return v.toString(16);
|
|
});
|
|
};
|
|
|
|
module.exports = {
|
|
uuid: uuid,
|
|
taskDefaults: function(task, filters) {
|
|
var defaults, self, _ref;
|
|
|
|
if (filters == null) {
|
|
filters = {};
|
|
}
|
|
self = this;
|
|
defaults = {
|
|
id: self.uuid(),
|
|
text: '',
|
|
up: true,
|
|
down: true,
|
|
type: 'habit',
|
|
completed: false,
|
|
repeat: {
|
|
su: true,
|
|
m: true,
|
|
t: true,
|
|
w: true,
|
|
th: true,
|
|
f: true,
|
|
s: true
|
|
},
|
|
notes: '',
|
|
tags: _.transform(filters, function(m, v, k) {
|
|
if (v) {
|
|
return m[k] = v;
|
|
}
|
|
})
|
|
};
|
|
_.defaults(task, defaults);
|
|
if ((_ref = task.value) == null) {
|
|
task.value = task.type === 'reward' ? 10 : 0;
|
|
}
|
|
return task;
|
|
},
|
|
newUser: function(isDerby) {
|
|
var defaultTags, defaultTasks, guid, newUser, repeat, tag, task, userSchema, _i, _j, _len, _len1;
|
|
|
|
if (isDerby == null) {
|
|
isDerby = false;
|
|
}
|
|
userSchema = {
|
|
stats: {
|
|
gp: 0,
|
|
exp: 0,
|
|
lvl: 1,
|
|
hp: 50
|
|
},
|
|
invitations: {
|
|
party: null,
|
|
guilds: []
|
|
},
|
|
items: {
|
|
weapon: 0,
|
|
armor: 0,
|
|
head: 0,
|
|
shield: 0
|
|
},
|
|
preferences: {
|
|
gender: 'm',
|
|
skin: 'white',
|
|
hair: 'blond',
|
|
armorSet: 'v1',
|
|
dayStart: 0,
|
|
showHelm: true
|
|
},
|
|
apiToken: uuid(),
|
|
lastCron: +(new Date),
|
|
balance: 0,
|
|
flags: {
|
|
partyEnabled: false,
|
|
itemsEnabled: false,
|
|
ads: 'show'
|
|
},
|
|
tags: []
|
|
};
|
|
if (isDerby) {
|
|
userSchema.habitIds = [];
|
|
userSchema.dailyIds = [];
|
|
userSchema.todoIds = [];
|
|
userSchema.rewardIds = [];
|
|
userSchema.tasks = {};
|
|
} else {
|
|
userSchema.habits = [];
|
|
userSchema.dailys = [];
|
|
userSchema.todos = [];
|
|
userSchema.rewards = [];
|
|
}
|
|
newUser = _.cloneDeep(userSchema);
|
|
repeat = {
|
|
m: true,
|
|
t: true,
|
|
w: true,
|
|
th: true,
|
|
f: true,
|
|
s: true,
|
|
su: true
|
|
};
|
|
defaultTasks = [
|
|
{
|
|
type: 'habit',
|
|
text: '1h Productive Work',
|
|
notes: '-- Habits: Constantly Track --\nFor some habits, it only makes sense to *gain* points (like this one).',
|
|
value: 0,
|
|
up: true,
|
|
down: false
|
|
}, {
|
|
type: 'habit',
|
|
text: 'Eat Junk Food',
|
|
notes: 'For others, it only makes sense to *lose* points',
|
|
value: 0,
|
|
up: false,
|
|
down: true
|
|
}, {
|
|
type: 'habit',
|
|
text: 'Take The Stairs',
|
|
notes: 'For the rest, both + and - make sense (stairs = gain, elevator = lose)',
|
|
value: 0,
|
|
up: true,
|
|
down: true
|
|
}, {
|
|
type: 'daily',
|
|
text: '1h Personal Project',
|
|
notes: '-- Dailies: Complete Once a Day --\nAt the end of each day, non-completed Dailies dock you points.',
|
|
value: 0,
|
|
completed: false,
|
|
repeat: repeat
|
|
}, {
|
|
type: 'daily',
|
|
text: 'Exercise',
|
|
notes: "If you are doing well, they turn green and are less valuable (experience, gold) and less damaging (HP). This means you can ease up on them for a bit.",
|
|
value: 3,
|
|
completed: false,
|
|
repeat: repeat
|
|
}, {
|
|
type: 'daily',
|
|
text: '45m Reading',
|
|
notes: 'But if you are doing poorly, they turn red. The worse you do, the more valuable (exp, gold) and more damaging (HP) these goals become. This encourages you to focus on your shortcomings, the reds.',
|
|
value: -10,
|
|
completed: false,
|
|
repeat: repeat
|
|
}, {
|
|
type: 'todo',
|
|
text: 'Call Mom',
|
|
notes: "-- Todos: Complete Eventually --\nNon-completed Todos won't hurt you, but they will become more valuable over time. This will encourage you to wrap up stale Todos.",
|
|
value: -3,
|
|
completed: false
|
|
}, {
|
|
type: 'reward',
|
|
text: '1 Episode of Game of Thrones',
|
|
notes: '-- Rewards: Treat Yourself! --\nAs you complete goals, you earn gold to buy rewards. Buy them liberally - rewards are integral in forming good habits.',
|
|
value: 20
|
|
}, {
|
|
type: 'reward',
|
|
text: 'Cake',
|
|
notes: 'But only buy if you have enough gold - you lose HP otherwise.',
|
|
value: 10
|
|
}
|
|
];
|
|
defaultTags = [
|
|
{
|
|
name: 'morning'
|
|
}, {
|
|
name: 'afternoon'
|
|
}, {
|
|
name: 'evening'
|
|
}
|
|
];
|
|
for (_i = 0, _len = defaultTasks.length; _i < _len; _i++) {
|
|
task = defaultTasks[_i];
|
|
guid = task.id = uuid();
|
|
if (isDerby) {
|
|
newUser.tasks[guid] = task;
|
|
newUser["" + task.type + "Ids"].push(guid);
|
|
} else {
|
|
newUser["" + task.type + "s"].push(task);
|
|
}
|
|
}
|
|
for (_j = 0, _len1 = defaultTags.length; _j < _len1; _j++) {
|
|
tag = defaultTags[_j];
|
|
tag.id = uuid();
|
|
newUser.tags.push(tag);
|
|
}
|
|
return newUser;
|
|
},
|
|
percent: function(x, y) {
|
|
if (x === 0) {
|
|
x = 1;
|
|
}
|
|
return Math.round(x / y * 100);
|
|
},
|
|
/*
|
|
This allows you to set object properties by dot-path. Eg, you can run pathSet('stats.hp',50,user) which is the same as
|
|
user.stats.hp = 50. This is useful because in our habitrpg-shared functions we're returning changesets as {path:value},
|
|
so that different consumers can implement setters their own way. Derby needs model.set(path, value) for example, where
|
|
Angular sets object properties directly - in which case, this function will be used.
|
|
*/
|
|
|
|
dotSet: function(path, val, obj) {
|
|
var arr;
|
|
|
|
if (~path.indexOf('undefined')) {
|
|
return;
|
|
}
|
|
arr = path.split('.');
|
|
return _.reduce(arr, function(curr, next, index) {
|
|
if ((arr.length - 1) === index) {
|
|
curr[next] = val;
|
|
}
|
|
return curr[next];
|
|
}, obj);
|
|
},
|
|
dotGet: function(path, obj) {
|
|
if (~path.indexOf('undefined')) {
|
|
return void 0;
|
|
}
|
|
return _.reduce(path.split('.'), (function(curr, next) {
|
|
return curr[next];
|
|
}), obj);
|
|
},
|
|
daysSince: daysSince,
|
|
startOfWeek: startOfWeek,
|
|
startOfDay: startOfDay,
|
|
shouldDo: shouldDo,
|
|
/*
|
|
Get a random property from an object
|
|
http://stackoverflow.com/questions/2532218/pick-random-property-from-a-javascript-object
|
|
returns random property (the value)
|
|
*/
|
|
|
|
randomVal: function(obj) {
|
|
var count, key, result, val;
|
|
|
|
result = void 0;
|
|
count = 0;
|
|
for (key in obj) {
|
|
val = obj[key];
|
|
if (Math.random() < (1 / ++count)) {
|
|
result = val;
|
|
}
|
|
}
|
|
return result;
|
|
},
|
|
/*
|
|
Remove whitespace #FIXME are we using this anywwhere? Should we be?
|
|
*/
|
|
|
|
removeWhitespace: function(str) {
|
|
if (!str) {
|
|
return '';
|
|
}
|
|
return str.replace(/\s/g, '');
|
|
},
|
|
/*
|
|
Generate the username, since it can be one of many things: their username, their facebook fullname, their manually-set profile name
|
|
*/
|
|
|
|
username: function(auth, override) {
|
|
var fb, _ref;
|
|
|
|
if (override) {
|
|
return override;
|
|
}
|
|
if ((auth != null ? (_ref = auth.facebook) != null ? _ref.displayName : void 0 : void 0) != null) {
|
|
return auth.facebook.displayName;
|
|
} else if ((auth != null ? auth.facebook : void 0) != null) {
|
|
fb = auth.facebook;
|
|
if (fb._raw) {
|
|
return "" + fb.name.givenName + " " + fb.name.familyName;
|
|
} else {
|
|
return fb.name;
|
|
}
|
|
} else if ((auth != null ? auth.local : void 0) != null) {
|
|
return auth.local.username;
|
|
} else {
|
|
return 'Anonymous';
|
|
}
|
|
},
|
|
/*
|
|
Encode the download link for .ics iCal file
|
|
*/
|
|
|
|
encodeiCalLink: function(uid, apiToken) {
|
|
var loc, _ref;
|
|
|
|
loc = (typeof window !== "undefined" && window !== null ? window.location.host : void 0) || (typeof process !== "undefined" && process !== null ? (_ref = process.env) != null ? _ref.BASE_URL : void 0 : void 0) || '';
|
|
return encodeURIComponent("http://" + loc + "/v1/users/" + uid + "/calendar.ics?apiToken=" + apiToken);
|
|
},
|
|
/*
|
|
User's currently equiped item
|
|
*/
|
|
|
|
equipped: function(type, item, preferences, backerTier) {
|
|
var armorSet, gender;
|
|
|
|
if (item == null) {
|
|
item = 0;
|
|
}
|
|
if (preferences == null) {
|
|
preferences = {
|
|
gender: 'm',
|
|
armorSet: 'v1'
|
|
};
|
|
}
|
|
if (backerTier == null) {
|
|
backerTier = 0;
|
|
}
|
|
gender = preferences.gender, armorSet = preferences.armorSet;
|
|
item = ~~item;
|
|
backerTier = ~~backerTier;
|
|
switch (type) {
|
|
case 'armor':
|
|
if (item > 5) {
|
|
if (backerTier >= 45) {
|
|
return 'armor_6';
|
|
}
|
|
item = 5;
|
|
}
|
|
if (gender === 'f') {
|
|
if (item === 0) {
|
|
return "f_armor_" + item + "_" + armorSet;
|
|
} else {
|
|
return "f_armor_" + item;
|
|
}
|
|
} else {
|
|
return "m_armor_" + item;
|
|
}
|
|
break;
|
|
case 'head':
|
|
if (item > 5) {
|
|
if (backerTier >= 45) {
|
|
return 'head_6';
|
|
}
|
|
item = 5;
|
|
}
|
|
if (gender === 'f') {
|
|
if (item > 1) {
|
|
return "f_head_" + item + "_" + armorSet;
|
|
} else {
|
|
return "f_head_" + item;
|
|
}
|
|
} else {
|
|
return "m_head_" + item;
|
|
}
|
|
break;
|
|
case 'shield':
|
|
if (item > 5) {
|
|
if (backerTier >= 45) {
|
|
return 'shield_6';
|
|
}
|
|
item = 5;
|
|
}
|
|
return "" + preferences.gender + "_shield_" + item;
|
|
case 'weapon':
|
|
if (item > 6) {
|
|
if (backerTier >= 70) {
|
|
return 'weapon_7';
|
|
}
|
|
item = 6;
|
|
}
|
|
return "" + preferences.gender + "_weapon_" + item;
|
|
}
|
|
},
|
|
/*
|
|
Gold amount from their money
|
|
*/
|
|
|
|
gold: function(num) {
|
|
if (num) {
|
|
return num.toFixed(1).split('.')[0];
|
|
} else {
|
|
return "0";
|
|
}
|
|
},
|
|
/*
|
|
Silver amount from their money
|
|
*/
|
|
|
|
silver: function(num) {
|
|
if (num) {
|
|
return num.toFixed(2).split('.')[1];
|
|
} else {
|
|
return "00";
|
|
}
|
|
},
|
|
/*
|
|
Task classes given everything about the class
|
|
*/
|
|
|
|
taskClasses: function(task, filters, dayStart, lastCron, showCompleted, main) {
|
|
var classes, completed, enabled, filter, repeat, type, value, _ref;
|
|
|
|
if (showCompleted == null) {
|
|
showCompleted = false;
|
|
}
|
|
if (!task) {
|
|
return;
|
|
}
|
|
type = task.type, completed = task.completed, value = task.value, repeat = task.repeat;
|
|
if ((type === 'todo') && (completed !== showCompleted)) {
|
|
return 'hidden';
|
|
}
|
|
if (main) {
|
|
for (filter in filters) {
|
|
enabled = filters[filter];
|
|
if (enabled && !((_ref = task.tags) != null ? _ref[filter] : void 0)) {
|
|
return 'hidden';
|
|
}
|
|
}
|
|
}
|
|
classes = type;
|
|
if (type === 'todo' || type === 'daily') {
|
|
if (completed || (type === 'daily' && !shouldDo(+(new Date), task.repeat, {
|
|
dayStart: dayStart
|
|
}))) {
|
|
classes += " completed";
|
|
} else {
|
|
classes += " uncompleted";
|
|
}
|
|
} else if (type === 'habit') {
|
|
if (task.down && task.up) {
|
|
classes += ' habit-wide';
|
|
}
|
|
}
|
|
if (value < -20) {
|
|
classes += ' color-worst';
|
|
} else if (value < -10) {
|
|
classes += ' color-worse';
|
|
} else if (value < -1) {
|
|
classes += ' color-bad';
|
|
} else if (value < 1) {
|
|
classes += ' color-neutral';
|
|
} else if (value < 5) {
|
|
classes += ' color-good';
|
|
} else if (value < 10) {
|
|
classes += ' color-better';
|
|
} else {
|
|
classes += ' color-best';
|
|
}
|
|
return classes;
|
|
},
|
|
/*
|
|
Does the user own this pet?
|
|
*/
|
|
|
|
ownsPet: function(pet, userPets) {
|
|
return _.isArray(userPets) && userPets.indexOf(pet) !== -1;
|
|
},
|
|
/*
|
|
Friendly timestamp
|
|
*/
|
|
|
|
friendlyTimestamp: function(timestamp) {
|
|
return moment(timestamp).format('MM/DD h:mm:ss a');
|
|
},
|
|
/*
|
|
Does user have new chat messages?
|
|
*/
|
|
|
|
newChatMessages: function(messages, lastMessageSeen) {
|
|
if (!((messages != null ? messages.length : void 0) > 0)) {
|
|
return false;
|
|
}
|
|
return (messages != null ? messages[0] : void 0) && (messages[0].id !== lastMessageSeen);
|
|
},
|
|
/*
|
|
Relative Date
|
|
*/
|
|
|
|
relativeDate: require('relative-date'),
|
|
/*
|
|
are any tags active?
|
|
*/
|
|
|
|
noTags: function(tags) {
|
|
return _.isEmpty(tags) || _.isEmpty(_.filter(tags, function(t) {
|
|
return t;
|
|
}));
|
|
},
|
|
/*
|
|
Are there tags applied?
|
|
*/
|
|
|
|
appliedTags: function(userTags, taskTags) {
|
|
var arr;
|
|
|
|
arr = [];
|
|
_.each(userTags, function(t) {
|
|
if (t == null) {
|
|
return;
|
|
}
|
|
if (taskTags != null ? taskTags[t.id] : void 0) {
|
|
return arr.push(t.name);
|
|
}
|
|
});
|
|
return arr.join(', ');
|
|
},
|
|
/*
|
|
User stats
|
|
*/
|
|
|
|
userStr: function(level) {
|
|
return (level - 1) / 2;
|
|
},
|
|
totalStr: function(level, weapon) {
|
|
var str;
|
|
|
|
if (weapon == null) {
|
|
weapon = 0;
|
|
}
|
|
str = (level - 1) / 2;
|
|
return str + items.getItem('weapon', weapon).strength;
|
|
},
|
|
userDef: function(level) {
|
|
return (level - 1) / 2;
|
|
},
|
|
totalDef: function(level, armor, head, shield) {
|
|
var totalDef;
|
|
|
|
if (armor == null) {
|
|
armor = 0;
|
|
}
|
|
if (head == null) {
|
|
head = 0;
|
|
}
|
|
if (shield == null) {
|
|
shield = 0;
|
|
}
|
|
totalDef = (level - 1) / 2 + items.getItem('armor', armor).defense + items.getItem('head', head).defense + items.getItem('shield', shield).defense;
|
|
return totalDef;
|
|
},
|
|
itemText: function(type, item) {
|
|
if (item == null) {
|
|
item = 0;
|
|
}
|
|
return items.getItem(type, item).text;
|
|
},
|
|
itemStat: function(type, item) {
|
|
var i;
|
|
|
|
if (item == null) {
|
|
item = 0;
|
|
}
|
|
i = items.getItem(type, item);
|
|
if (type === 'weapon') {
|
|
return i.strength;
|
|
} else {
|
|
return i.defense;
|
|
}
|
|
},
|
|
/*
|
|
----------------------------------------------------------------------
|
|
Derby-specific helpers. Will remove after the rewrite, need them here for now
|
|
----------------------------------------------------------------------
|
|
*/
|
|
|
|
/*
|
|
Make sure model.get() returns all properties, see https://github.com/codeparty/racer/issues/116
|
|
*/
|
|
|
|
hydrate: function(spec) {
|
|
var hydrated, keys,
|
|
_this = this;
|
|
|
|
if (_.isObject(spec) && !_.isArray(spec)) {
|
|
hydrated = {};
|
|
keys = _.keys(spec).concat(_.keys(spec.__proto__));
|
|
keys.forEach(function(k) {
|
|
return hydrated[k] = _this.hydrate(spec[k]);
|
|
});
|
|
return hydrated;
|
|
} else {
|
|
return spec;
|
|
}
|
|
}
|
|
};
|
|
|
|
}).call(this);
|
|
|
|
|
|
},{"./items.coffee":8,"__browserify_process":1,"lodash":2,"moment":3,"relative-date":4}],7:[function(require,module,exports){
|
|
exports.algos = require('./algos.coffee');
|
|
exports.items = require('./items.coffee');
|
|
exports.helpers = require('./helpers.coffee');
|
|
|
|
try {
|
|
window;
|
|
window.habitrpgShared = exports;
|
|
} catch(e) {}
|
|
},{"./algos.coffee":5,"./helpers.coffee":6,"./items.coffee":8}],8:[function(require,module,exports){
|
|
(function() {
|
|
var items, _;
|
|
|
|
_ = require('lodash');
|
|
|
|
items = module.exports.items = {
|
|
weapon: [
|
|
{
|
|
index: 0,
|
|
text: "Training Sword",
|
|
classes: "weapon_0",
|
|
notes: 'Training weapon.',
|
|
strength: 0,
|
|
value: 0
|
|
}, {
|
|
index: 1,
|
|
text: "Sword",
|
|
classes: 'weapon_1',
|
|
notes: 'Increases experience gain by 3%.',
|
|
strength: 3,
|
|
value: 20
|
|
}, {
|
|
index: 2,
|
|
text: "Axe",
|
|
classes: 'weapon_2',
|
|
notes: 'Increases experience gain by 6%.',
|
|
strength: 6,
|
|
value: 30
|
|
}, {
|
|
index: 3,
|
|
text: "Morningstar",
|
|
classes: 'weapon_3',
|
|
notes: 'Increases experience gain by 9%.',
|
|
strength: 9,
|
|
value: 45
|
|
}, {
|
|
index: 4,
|
|
text: "Blue Sword",
|
|
classes: 'weapon_4',
|
|
notes: 'Increases experience gain by 12%.',
|
|
strength: 12,
|
|
value: 65
|
|
}, {
|
|
index: 5,
|
|
text: "Red Sword",
|
|
classes: 'weapon_5',
|
|
notes: 'Increases experience gain by 15%.',
|
|
strength: 15,
|
|
value: 90
|
|
}, {
|
|
index: 6,
|
|
text: "Golden Sword",
|
|
classes: 'weapon_6',
|
|
notes: 'Increases experience gain by 18%.',
|
|
strength: 18,
|
|
value: 120
|
|
}, {
|
|
index: 7,
|
|
text: "Dark Souls Blade",
|
|
classes: 'weapon_7',
|
|
notes: 'Increases experience gain by 21%.',
|
|
strength: 21,
|
|
value: 150
|
|
}
|
|
],
|
|
armor: [
|
|
{
|
|
index: 0,
|
|
text: "Cloth Armor",
|
|
classes: 'armor_0',
|
|
notes: 'Training armor.',
|
|
defense: 0,
|
|
value: 0
|
|
}, {
|
|
index: 1,
|
|
text: "Leather Armor",
|
|
classes: 'armor_1',
|
|
notes: 'Decreases HP loss by 4%.',
|
|
defense: 4,
|
|
value: 30
|
|
}, {
|
|
index: 2,
|
|
text: "Chain Mail",
|
|
classes: 'armor_2',
|
|
notes: 'Decreases HP loss by 6%.',
|
|
defense: 6,
|
|
value: 45
|
|
}, {
|
|
index: 3,
|
|
text: "Plate Mail",
|
|
classes: 'armor_3',
|
|
notes: 'Decreases HP loss by 7%.',
|
|
defense: 7,
|
|
value: 65
|
|
}, {
|
|
index: 4,
|
|
text: "Red Armor",
|
|
classes: 'armor_4',
|
|
notes: 'Decreases HP loss by 8%.',
|
|
defense: 8,
|
|
value: 90
|
|
}, {
|
|
index: 5,
|
|
text: "Golden Armor",
|
|
classes: 'armor_5',
|
|
notes: 'Decreases HP loss by 10%.',
|
|
defense: 10,
|
|
value: 120
|
|
}, {
|
|
index: 6,
|
|
text: "Shade Armor",
|
|
classes: 'armor_6',
|
|
notes: 'Decreases HP loss by 12%.',
|
|
defense: 12,
|
|
value: 150
|
|
}
|
|
],
|
|
head: [
|
|
{
|
|
index: 0,
|
|
text: "No Helm",
|
|
classes: 'head_0',
|
|
notes: 'Training helm.',
|
|
defense: 0,
|
|
value: 0
|
|
}, {
|
|
index: 1,
|
|
text: "Leather Helm",
|
|
classes: 'head_1',
|
|
notes: 'Decreases HP loss by 2%.',
|
|
defense: 2,
|
|
value: 15
|
|
}, {
|
|
index: 2,
|
|
text: "Chain Coif",
|
|
classes: 'head_2',
|
|
notes: 'Decreases HP loss by 3%.',
|
|
defense: 3,
|
|
value: 25
|
|
}, {
|
|
index: 3,
|
|
text: "Plate Helm",
|
|
classes: 'head_3',
|
|
notes: 'Decreases HP loss by 4%.',
|
|
defense: 4,
|
|
value: 45
|
|
}, {
|
|
index: 4,
|
|
text: "Red Helm",
|
|
classes: 'head_4',
|
|
notes: 'Decreases HP loss by 5%.',
|
|
defense: 5,
|
|
value: 60
|
|
}, {
|
|
index: 5,
|
|
text: "Golden Helm",
|
|
classes: 'head_5',
|
|
notes: 'Decreases HP loss by 6%.',
|
|
defense: 6,
|
|
value: 80
|
|
}, {
|
|
index: 6,
|
|
text: "Shade Helm",
|
|
classes: 'head_6',
|
|
notes: 'Decreases HP loss by 7%.',
|
|
defense: 7,
|
|
value: 100
|
|
}
|
|
],
|
|
shield: [
|
|
{
|
|
index: 0,
|
|
text: "No Shield",
|
|
classes: 'shield_0',
|
|
notes: 'No Shield.',
|
|
defense: 0,
|
|
value: 0
|
|
}, {
|
|
index: 1,
|
|
text: "Wooden Shield",
|
|
classes: 'shield_1',
|
|
notes: 'Decreases HP loss by 3%',
|
|
defense: 3,
|
|
value: 20
|
|
}, {
|
|
index: 2,
|
|
text: "Buckler",
|
|
classes: 'shield_2',
|
|
notes: 'Decreases HP loss by 4%.',
|
|
defense: 4,
|
|
value: 35
|
|
}, {
|
|
index: 3,
|
|
text: "Reinforced Shield",
|
|
classes: 'shield_3',
|
|
notes: 'Decreases HP loss by 5%.',
|
|
defense: 5,
|
|
value: 55
|
|
}, {
|
|
index: 4,
|
|
text: "Red Shield",
|
|
classes: 'shield_4',
|
|
notes: 'Decreases HP loss by 7%.',
|
|
defense: 7,
|
|
value: 70
|
|
}, {
|
|
index: 5,
|
|
text: "Golden Shield",
|
|
classes: 'shield_5',
|
|
notes: 'Decreases HP loss by 8%.',
|
|
defense: 8,
|
|
value: 90
|
|
}, {
|
|
index: 6,
|
|
text: "Tormented Skull",
|
|
classes: 'shield_6',
|
|
notes: 'Decreases HP loss by 9%.',
|
|
defense: 9,
|
|
value: 120
|
|
}
|
|
],
|
|
potion: {
|
|
type: 'potion',
|
|
text: "Potion",
|
|
notes: "Recover 15 HP (Instant Use)",
|
|
value: 25,
|
|
classes: 'potion'
|
|
},
|
|
reroll: {
|
|
type: 'reroll',
|
|
text: "Re-Roll",
|
|
classes: 'reroll',
|
|
notes: "Resets your task values back to 0 (yellow). Useful when everything's red and it's hard to stay alive.",
|
|
value: 0
|
|
},
|
|
pets: [
|
|
{
|
|
text: 'Wolf',
|
|
name: 'Wolf',
|
|
value: 3
|
|
}, {
|
|
text: 'Tiger Cub',
|
|
name: 'TigerCub',
|
|
value: 3
|
|
}, {
|
|
text: 'Panda Cub',
|
|
name: 'PandaCub',
|
|
value: 3
|
|
}, {
|
|
text: 'Lion Cub',
|
|
name: 'LionCub',
|
|
value: 3
|
|
}, {
|
|
text: 'Fox',
|
|
name: 'Fox',
|
|
value: 3
|
|
}, {
|
|
text: 'Flying Pig',
|
|
name: 'FlyingPig',
|
|
value: 3
|
|
}, {
|
|
text: 'Dragon',
|
|
name: 'Dragon',
|
|
value: 3
|
|
}, {
|
|
text: 'Cactus',
|
|
name: 'Cactus',
|
|
value: 3
|
|
}, {
|
|
text: 'Bear Cub',
|
|
name: 'BearCub',
|
|
value: 3
|
|
}
|
|
],
|
|
hatchingPotions: [
|
|
{
|
|
text: 'Base',
|
|
name: 'Base',
|
|
notes: "Hatches your pet in it's base form.",
|
|
value: 1
|
|
}, {
|
|
text: 'White',
|
|
name: 'White',
|
|
notes: 'Turns your animal into a White pet.',
|
|
value: 2
|
|
}, {
|
|
text: 'Desert',
|
|
name: 'Desert',
|
|
notes: 'Turns your animal into a Desert pet.',
|
|
value: 2
|
|
}, {
|
|
text: 'Red',
|
|
name: 'Red',
|
|
notes: 'Turns your animal into a Red pet.',
|
|
value: 3
|
|
}, {
|
|
text: 'Shade',
|
|
name: 'Shade',
|
|
notes: 'Turns your animal into a Shade pet.',
|
|
value: 3
|
|
}, {
|
|
text: 'Skeleton',
|
|
name: 'Skeleton',
|
|
notes: 'Turns your animal into a Skeleton.',
|
|
value: 3
|
|
}, {
|
|
text: 'Zombie',
|
|
name: 'Zombie',
|
|
notes: 'Turns your animal into a Zombie.',
|
|
value: 4
|
|
}, {
|
|
text: 'Cotton Candy Pink',
|
|
name: 'CottonCandyPink',
|
|
notes: 'Turns your animal into a Cotton Candy Pink pet.',
|
|
value: 4
|
|
}, {
|
|
text: 'Cotton Candy Blue',
|
|
name: 'CottonCandyBlue',
|
|
notes: 'Turns your animal into a Cotton Candy Blue pet.',
|
|
value: 4
|
|
}, {
|
|
text: 'Golden',
|
|
name: 'Golden',
|
|
notes: 'Turns your animal into a Golden pet.',
|
|
value: 5
|
|
}
|
|
]
|
|
};
|
|
|
|
_.each(['weapon', 'armor', 'head', 'shield'], function(key) {
|
|
return _.each(items[key], function(item) {
|
|
return item.type = key;
|
|
});
|
|
});
|
|
|
|
_.each(items.pets, function(pet) {
|
|
return pet.notes = 'Find a hatching potion to pour on this egg, and it will hatch into a loyal pet.';
|
|
});
|
|
|
|
_.each(items.hatchingPotions, function(hatchingPotion) {
|
|
return hatchingPotion.notes = "Pour this on an egg, and it will hatch as a " + hatchingPotion.text + " pet.";
|
|
});
|
|
|
|
module.exports.buyItem = function(user, type, options) {
|
|
var nextItem;
|
|
|
|
if (options == null) {
|
|
options = {};
|
|
}
|
|
_.defaults(options, {
|
|
paths: {}
|
|
});
|
|
nextItem = type === 'potion' ? items.potion : module.exports.getItem(type, (~~user.items[type] || 0) + 1);
|
|
if (+user.stats.gp < +nextItem.value) {
|
|
return false;
|
|
}
|
|
if (nextItem.type === 'potion') {
|
|
user.stats.hp += 15;
|
|
if (user.stats.hp > 50) {
|
|
user.stats.hp = 50;
|
|
}
|
|
options.paths['stats.hp'] = true;
|
|
} else {
|
|
user.items[type] = ~~nextItem.index;
|
|
options.paths["items." + type] = true;
|
|
}
|
|
user.stats.gp -= +nextItem.value;
|
|
options.paths['stats.gp'] = true;
|
|
return true;
|
|
};
|
|
|
|
/*
|
|
update store
|
|
*/
|
|
|
|
|
|
module.exports.updateStore = function(user) {
|
|
var changes;
|
|
|
|
changes = {};
|
|
_.each(['weapon', 'armor', 'shield', 'head'], function(type) {
|
|
var i, showNext, _ref, _ref1, _ref2;
|
|
|
|
i = ~~(((_ref = user.items) != null ? _ref[type] : void 0) || 0) + 1;
|
|
showNext = true;
|
|
if (i === items[type].length - 1) {
|
|
if ((type === 'armor' || type === 'shield' || type === 'head')) {
|
|
showNext = ((_ref1 = user.backer) != null ? _ref1.tier : void 0) && user.backer.tier >= 45;
|
|
} else {
|
|
showNext = ((_ref2 = user.backer) != null ? _ref2.tier : void 0) && user.backer.tier >= 70;
|
|
}
|
|
} else if (i === items[type].length) {
|
|
showNext = false;
|
|
}
|
|
return changes[type] = showNext ? items[type][i] : {
|
|
hide: true
|
|
};
|
|
});
|
|
changes.potion = items.potion;
|
|
changes.reroll = items.reroll;
|
|
return changes;
|
|
};
|
|
|
|
/*
|
|
Gets an itme, and caps max to the last item in its array
|
|
*/
|
|
|
|
|
|
module.exports.getItem = function(type, index) {
|
|
var i;
|
|
|
|
if (index == null) {
|
|
index = 0;
|
|
}
|
|
i = ~~index > items[type].length - 1 ? items[type].length - 1 : ~~index;
|
|
return items[type][i];
|
|
};
|
|
|
|
}).call(this);
|
|
|
|
|
|
},{"lodash":2}]},{},[7])
|
|
//@ sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlcyI6WyIvaG9tZS9tYXR0ZW8vRHJvcGJveC9EZXZlbG9wbWVudC9oYWJpdHJwZy1zaGFyZWQvbm9kZV9tb2R1bGVzL2dydW50LWJyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2luc2VydC1tb2R1bGUtZ2xvYmFscy9ub2RlX21vZHVsZXMvcHJvY2Vzcy9icm93c2VyLmpzIiwiL2hvbWUvbWF0dGVvL0Ryb3Bib3gvRGV2ZWxvcG1lbnQvaGFiaXRycGctc2hhcmVkL25vZGVfbW9kdWxlcy9sb2Rhc2gvZGlzdC9sb2Rhc2guanMiLCIvaG9tZS9tYXR0ZW8vRHJvcGJveC9EZXZlbG9wbWVudC9oYWJpdHJwZy1zaGFyZWQvbm9kZV9tb2R1bGVzL21vbWVudC9tb21lbnQuanMiLCIvaG9tZS9tYXR0ZW8vRHJvcGJveC9EZXZlbG9wbWVudC9oYWJpdHJwZy1zaGFyZWQvbm9kZV9tb2R1bGVzL3JlbGF0aXZlLWRhdGUvbGliL3JlbGF0aXZlLWRhdGUuanMiLCIvaG9tZS9tYXR0ZW8vRHJvcGJveC9EZXZlbG9wbWVudC9oYWJpdHJwZy1zaGFyZWQvc2NyaXB0L2FsZ29zLmNvZmZlZSIsIi9ob21lL21hdHRlby9Ecm9wYm94L0RldmVsb3BtZW50L2hhYml0cnBnLXNoYXJlZC9zY3JpcHQvaGVscGVycy5jb2ZmZWUiLCIvaG9tZS9tYXR0ZW8vRHJvcGJveC9EZXZlbG9wbWVudC9oYWJpdHJwZy1zaGFyZWQvc2NyaXB0L2luZGV4LmpzIiwiL2hvbWUvbWF0dGVvL0Ryb3Bib3gvRGV2ZWxvcG1lbnQvaGFiaXRycGctc2hhcmVkL3NjcmlwdC9pdGVtcy5jb2ZmZWUiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuN0tBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNB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QW5IQTs7Q0FBQSxDQXNIQSxDQUF5QixDQUFBLENBQUEsQ0FBbkIsQ0FBUSxFQUFZO0NBQ3hCLE9BQUE7OztHQURvQyxHQUFOO01BQzlCO0FBQVMsQ0FBVCxFQUFRLENBQVIsQ0FBUSxDQUFVO0NBQ1osR0FBQSxDQUFBLE1BQU47Q0F4SEYsRUFzSHlCO0NBdEh6QiIsInNvdXJjZXNDb250ZW50IjpbIi8vIHNoaW0gZm9yIHVzaW5nIHByb2Nlc3MgaW4gYnJvd3NlclxuXG52YXIgcHJvY2VzcyA9IG1vZHVsZS5leHBvcnRzID0ge307XG5cbnByb2Nlc3MubmV4dFRpY2sgPSAoZnVuY3Rpb24gKCkge1xuICAgIHZhciBjYW5TZXRJbW1lZGlhdGUgPSB0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJ1xuICAgICYmIHdpbmRvdy5zZXRJbW1lZGlhdGU7XG4gICAgdmFyIGNhblBvc3QgPSB0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJ1xuICAgICYmIHdpbmRvdy5wb3N0TWVzc2FnZSAmJiB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lclxuICAgIDtcblxuICAgIGlmIChjYW5TZXRJbW1lZGlhdGUpIHtcbiAgICAgICAgcmV0dXJuIGZ1bmN0aW9uIChmKSB7IHJldHVybiB3aW5kb3cuc2V0SW1tZWRpYXRlKGYpIH07XG4gICAgfVxuXG4gICAgaWYgKGNhblBvc3QpIHtcbiAgICAgICAgdmFyIHF1ZXVlID0gW107XG4gICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdtZXNzYWdlJywgZnVuY3Rpb24gKGV2KSB7XG4gICAgICAgICAgICBpZiAoZXYuc291cmNlID09PSB3aW5kb3cgJiYgZXYuZGF0YSA9PT0gJ3Byb2Nlc3MtdGljaycpIHtcbiAgICAgICAgICAgICAgICBldi5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgICAgICAgICAgICBpZiAocXVldWUubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgICAgICB2YXIgZm4gPSBxdWV1ZS5zaGlmdCgpO1xuICAgICAgICAgICAgICAgICAgICBmbigpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSwgdHJ1ZSk7XG5cbiAgICAgICAgcmV0dXJuIGZ1bmN0aW9uIG5leHRUaWNrKGZuKSB7XG4gICAgICAgICAgICBxdWV1ZS5wdXNoKGZuKTtcbiAgICAgICAgICAgIHdpbmRvdy5wb3N0TWVzc2FnZSgncHJvY2Vzcy10aWNrJywgJyonKTtcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICByZXR1cm4gZnVuY3Rpb24gbmV4dFRpY2soZm4pIHtcbiAgICAgICAgc2V0VGltZW91dChmbiwgMCk7XG4gICAgfTtcbn0pKCk7XG5cbnByb2Nlc3MudGl0bGUgPSAnYnJvd3Nlcic7XG5wcm9jZXNzLmJyb3dzZXIgPSB0cnVlO1xucHJvY2Vzcy5lbnYgPSB7fTtcbnByb2Nlc3MuYXJndiA9IFtdO1xuXG5wcm9jZXNzLmJpbmRpbmcgPSBmdW5jdGlvbiAobmFtZSkge1xuICAgIHRocm93IG5ldyBFcnJvcigncHJvY2Vzcy5iaW5kaW5nIGlzIG5vdCBzdXBwb3J0ZWQnKTtcbn1cblxuLy8gVE9ETyhzaHR5bG1hbilcbnByb2Nlc3MuY3dkID0gZnVuY3Rpb24gKCkgeyByZXR1cm4gJy8nIH07XG5wcm9jZXNzLmNoZGlyID0gZnVuY3Rpb24gKGRpcikge1xuICAgIHRocm93IG5ldyBFcnJvcigncHJvY2Vzcy5jaGRpciBpcyBub3Qgc3VwcG9ydGVkJyk7XG59O1xuIiwidmFyIGdsb2JhbD1zZWxmOy8qKlxuICogQGxpY2Vuc2VcbiAqIExvLURhc2ggMS4zLjEgKEN1c3RvbSBCdWlsZCkgPGh0dHA6Ly9sb2Rhc2guY29tLz5cbiAqIEJ1aWxkOiBgbG9kYXNoIG1vZGVybiAtbyAuL2Rpc3QvbG9kYXNoLmpzYFxuICogQ29weXJpZ2h0IDIwMTItMjAxMyBUaGUgRG9qbyBGb3VuZGF0aW9uIDxodHRwOi8vZG9qb2ZvdW5kYXRpb24ub3JnLz5cbiAqIEJhc2VkIG9uIFVuZGVyc2NvcmUuanMgMS40LjQgPGh0dHA6Ly91bmRlcnNjb3JlanMub3JnLz5cbiAqIENvcHlyaWdodCAyMDA5LTIwMTMgSmVyZW15IEFzaGtlbmFzLCBEb2N1bWVudENsb3VkIEluYy5cbiAqIEF2YWlsYWJsZSB1bmRlciBNSVQgbGljZW5zZSA8aHR0cDovL2xvZGFzaC5jb20vbGljZW5zZT5cbiAqL1xuOyhmdW5jdGlvbih3aW5kb3cpIHtcblxuICAvKiogVXNlZCBhcyBhIHNhZmUgcmVmZXJlbmNlIGZvciBgdW5kZWZpbmVkYCBpbiBwcmUgRVM1IGVudmlyb25tZW50cyAqL1xuICB2YXIgdW5kZWZpbmVkO1xuXG4gIC8qKiBVc2VkIHRvIHBvb2wgYXJyYXlzIGFuZCBvYmplY3RzIHVzZWQgaW50ZXJuYWxseSAqL1xuICB2YXIgYXJyYXlQb29sID0gW10sXG4gICAgICBvYmplY3RQb29sID0gW107XG5cbiAgLyoqIFVzZWQgdG8gZ2VuZXJhdGUgdW5pcXVlIElEcyAqL1xuICB2YXIgaWRDb3VudGVyID0gMDtcblxuICAvKiogVXNlZCBpbnRlcm5hbGx5IHRvIGluZGljYXRlIHZhcmlvdXMgdGhpbmdzICovXG4gIHZhciBpbmRpY2F0b3JPYmplY3QgPSB7fTtcblxuICAvKiogVXNlZCB0byBwcmVmaXgga2V5cyB0byBhdm9pZCBpc3N1ZXMgd2l0aCBgX19wcm90b19fYCBhbmQgcHJvcGVydGllcyBvbiBgT2JqZWN0LnByb3RvdHlwZWAgKi9cbiAgdmFyIGtleVByZWZpeCA9ICtuZXcgRGF0ZSArICcnO1xuXG4gIC8qKiBVc2VkIGFzIHRoZSBzaXplIHdoZW4gb3B0aW1pemF0aW9ucyBhcmUgZW5hYmxlZCBmb3IgbGFyZ2UgYXJyYXlzICovXG4gIHZhciBsYXJnZUFycmF5U2l6ZSA9IDc1O1xuXG4gIC8qKiBVc2VkIGFzIHRoZSBtYXggc2l6ZSBvZiB0aGUgYGFycmF5UG9vbGAgYW5kIGBvYmplY3RQb29sYCAqL1xuICB2YXIgbWF4UG9vbFNpemUgPSA0MDtcblxuICAvKiogVXNlZCB0byBtYXRjaCBlbXB0eSBzdHJpbmcgbGl0ZXJhbHMgaW4gY29tcGlsZWQgdGVtcGxhdGUgc291cmNlICovXG4gIHZhciByZUVtcHR5U3RyaW5nTGVhZGluZyA9IC9cXGJfX3AgXFwrPSAnJzsvZyxcbiAgICAgIHJlRW1wdHlTdHJpbmdNaWRkbGUgPSAvXFxiKF9fcCBcXCs9KSAnJyBcXCsvZyxcbiAgICAgIHJlRW1wdHlTdHJpbmdUcmFpbGluZyA9IC8oX19lXFwoLio/XFwpfFxcYl9fdFxcKSkgXFwrXFxuJyc7L2c7XG5cbiAgLyoqIFVzZWQgdG8gbWF0Y2ggSFRNTCBlbnRpdGllcyAqL1xuICB2YXIgcmVFc2NhcGVkSHRtbCA9IC8mKD86YW1wfGx0fGd0fHF1b3R8IzM5KTsvZztcblxuICAvKipcbiAgICogVXNlZCB0byBtYXRjaCBFUzYgdGVtcGxhdGUgZGVsaW1pdGVyc1xuICAgKiBodHRwOi8vcGVvcGxlLm1vemlsbGEub3JnL35qb3JlbmRvcmZmL2VzNi1kcmFmdC5odG1sI3NlYy03LjguNlxuICAgKi9cbiAgdmFyIHJlRXNUZW1wbGF0ZSA9IC9cXCRcXHsoW15cXFxcfV0qKD86XFxcXC5bXlxcXFx9XSopKilcXH0vZztcblxuICAvKiogVXNlZCB0byBtYXRjaCByZWdleHAgZmxhZ3MgZnJvbSB0aGVpciBjb2VyY2VkIHN0cmluZyB2YWx1ZXMgKi9cbiAgdmFyIHJlRmxhZ3MgPSAvXFx3KiQvO1xuXG4gIC8qKiBVc2VkIHRvIG1hdGNoIFwiaW50ZXJwb2xhdGVcIiB0ZW1wbGF0ZSBkZWxpbWl0ZXJzICovXG4gIHZhciByZUludGVycG9sYXRlID0gLzwlPShbXFxzXFxTXSs/KSU+L2c7XG5cbiAgLyoqIFVzZWQgdG8gZGV0ZWN0IGZ1bmN0aW9ucyBjb250YWluaW5nIGEgYHRoaXNgIHJlZmVyZW5jZSAqL1xuICB2YXIgcmVUaGlzID0gKHJlVGhpcyA9IC9cXGJ0aGlzXFxiLykgJiYgcmVUaGlzLnRlc3QocnVuSW5Db250ZXh0KSAmJiByZVRoaXM7XG5cbiAgLyoqIFVzZWQgdG8gZGV0ZWN0IGFuZCB0ZXN0IHdoaXRlc3BhY2UgKi9cbiAgdmFyIHdoaXRlc3BhY2UgPSAoXG4gICAgLy8gd2hpdGVzcGFjZVxuICAgICcgXFx0XFx4MEJcXGZcXHhBMFxcdWZlZmYnICtcblxuICAgIC8vIGxpbmUgdGVybWluYXRvcnNcbiAgICAnXFxuXFxyXFx1MjAyOFxcdTIwMjknICtcblxuICAgIC8vIHVuaWNvZGUgY2F0ZWdvcnkgXCJac1wiIHNwYWNlIHNlcGFyYXRvcnNcbiAgICAnXFx1MTY4MFxcdTE4MGVcXHUyMDAwXFx1MjAwMVxcdTIwMDJcXHUyMDAzXFx1MjAwNFxcdTIwMDVcXHUyMDA2XFx1MjAwN1xcdTIwMDhcXHUyMDA5XFx1MjAwYVxcdTIwMmZcXHUyMDVmXFx1MzAwMCdcbiAgKTtcblxuICAvKiogVXNlZCB0byBtYXRjaCBsZWFkaW5nIHdoaXRlc3BhY2UgYW5kIHplcm9zIHRvIGJlIHJlbW92ZWQgKi9cbiAgdmFyIHJlTGVhZGluZ1NwYWNlc0FuZFplcm9zID0gUmVnRXhwKCdeWycgKyB3aGl0ZXNwYWNlICsgJ10qMCsoPz0uJCknKTtcblxuICAvKiogVXNlZCB0byBlbnN1cmUgY2FwdHVyaW5nIG9yZGVyIG9mIHRlbXBsYXRlIGRlbGltaXRlcnMgKi9cbiAgdmFyIHJlTm9NYXRjaCA9IC8oJF4pLztcblxuICAvKiogVXNlZCB0byBtYXRjaCBIVE1MIGNoYXJhY3RlcnMgKi9cbiAgdmFyIHJlVW5lc2NhcGVkSHRtbCA9IC9bJjw+XCInXS9nO1xuXG4gIC8qKiBVc2VkIHRvIG1hdGNoIHVuZXNjYXBlZCBjaGFyYWN0ZXJzIGluIGNvbXBpbGVkIHN0cmluZyBsaXRlcmFscyAqL1xuICB2YXIgcmVVbmVzY2FwZWRTdHJpbmcgPSAvWydcXG5cXHJcXHRcXHUyMDI4XFx1MjAyOVxcXFxdL2c7XG5cbiAgLyoqIFVzZWQgdG8gYXNzaWduIGRlZmF1bHQgYGNvbnRleHRgIG9iamVjdCBwcm9wZXJ0aWVzICovXG4gIHZhciBjb250ZXh0UHJvcHMgPSBbXG4gICAgJ0FycmF5JywgJ0Jvb2xlYW4nLCAnRGF0ZScsICdGdW5jdGlvbicsICdNYXRoJywgJ051bWJlcicsICdPYmplY3QnLFxuICAgICdSZWdFeHAnLCAnU3RyaW5nJywgJ18nLCAnYXR0YWNoRXZlbnQnLCAnY2xlYXJUaW1lb3V0JywgJ2lzRmluaXRlJywgJ2lzTmFOJyxcbiAgICAncGFyc2VJbnQnLCAnc2V0SW1tZWRpYXRlJywgJ3NldFRpbWVvdXQnXG4gIF07XG5cbiAgLyoqIFVzZWQgdG8gbWFrZSB0ZW1wbGF0ZSBzb3VyY2VVUkxzIGVhc2llciB0byBpZGVudGlmeSAqL1xuICB2YXIgdGVtcGxhdGVDb3VudGVyID0gMDtcblxuICAvKiogYE9iamVjdCN0b1N0cmluZ2AgcmVzdWx0IHNob3J0Y3V0cyAqL1xuICB2YXIgYXJnc0NsYXNzID0gJ1tvYmplY3QgQXJndW1lbnRzXScsXG4gICAgICBhcnJheUNsYXNzID0gJ1tvYmplY3QgQXJyYXldJyxcbiAgICAgIGJvb2xDbGFzcyA9ICdbb2JqZWN0IEJvb2xlYW5dJyxcbiAgICAgIGRhdGVDbGFzcyA9ICdbb2JqZWN0IERhdGVdJyxcbiAgICAgIGVycm9yQ2xhc3MgPSAnW29iamVjdCBFcnJvcl0nLFxuICAgICAgZnVuY0NsYXNzID0gJ1tvYmplY3QgRnVuY3Rpb25dJyxcbiAgICAgIG51bWJlckNsYXNzID0gJ1tvYmplY3QgTnVtYmVyXScsXG4gICAgICBvYmplY3RDbGFzcyA9ICdbb2JqZWN0IE9iamVjdF0nLFxuICAgICAgcmVnZXhwQ2xhc3MgPSAnW29iamVjdCBSZWdFeHBdJyxcbiAgICAgIHN0cmluZ0NsYXNzID0gJ1tvYmplY3QgU3RyaW5nXSc7XG5cbiAgLyoqIFVzZWQgdG8gaWRlbnRpZnkgb2JqZWN0IGNsYXNzaWZpY2F0aW9ucyB0aGF0IGBfLmNsb25lYCBzdXBwb3J0cyAqL1xuICB2YXIgY2xvbmVhYmxlQ2xhc3NlcyA9IHt9O1xuICBjbG9uZWFibGVDbGFzc2VzW2Z1bmNDbGFzc10gPSBmYWxzZTtcbiAgY2xvbmVhYmxlQ2xhc3Nlc1thcmdzQ2xhc3NdID0gY2xvbmVhYmxlQ2xhc3Nlc1thcnJheUNsYXNzXSA9XG4gIGNsb25lYWJsZUNsYXNzZXNbYm9vbENsYXNzXSA9IGNsb25lYWJsZUNsYXNzZXNbZGF0ZUNsYXNzXSA9XG4gIGNsb25lYWJsZUNsYXNzZXNbbnVtYmVyQ2xhc3NdID0gY2xvbmVhYmxlQ2xhc3Nlc1tvYmplY3RDbGFzc10gPVxuICBjbG9uZWFibGVDbGFzc2VzW3JlZ2V4cENsYXNzXSA9IGNsb25lYWJsZUNsYXNzZXNbc3RyaW5nQ2xhc3NdID0gdHJ1ZTtcblxuICAvKiogVXNlZCB0byBkZXRlcm1pbmUgaWYgdmFsdWVzIGFyZSBvZiB0aGUgbGFuZ3VhZ2UgdHlwZSBPYmplY3QgKi9cbiAgdmFyIG9iamVjdFR5cGVzID0ge1xuICAgICdib29sZWFuJzogZmFsc2UsXG4gICAgJ2Z1bmN0aW9uJzogdHJ1ZSxcbiAgICAnb2JqZWN0JzogdHJ1ZSxcbiAgICAnbnVtYmVyJzogZmFsc2UsXG4gICAgJ3N0cmluZyc6IGZhbHNlLFxuICAgICd1bmRlZmluZWQnOiBmYWxzZVxuICB9O1xuXG4gIC8qKiBVc2VkIHRvIGVzY2FwZSBjaGFyYWN0ZXJzIGZvciBpbmNsdXNpb24gaW4gY29tcGlsZWQgc3RyaW5nIGxpdGVyYWxzICovXG4gIHZhciBzdHJpbmdFc2NhcGVzID0ge1xuICAgICdcXFxcJzogJ1xcXFwnLFxuICAgIFwiJ1wiOiBcIidcIixcbiAgICAnXFxuJzogJ24nLFxuICAgICdcXHInOiAncicsXG4gICAgJ1xcdCc6ICd0JyxcbiAgICAnXFx1MjAyOCc6ICd1MjAyOCcsXG4gICAgJ1xcdTIwMjknOiAndTIwMjknXG4gIH07XG5cbiAgLyoqIERldGVjdCBmcmVlIHZhcmlhYmxlIGBleHBvcnRzYCAqL1xuICB2YXIgZnJlZUV4cG9ydHMgPSBvYmplY3RUeXBlc1t0eXBlb2YgZXhwb3J0c10gJiYgZXhwb3J0cztcblxuICAvKiogRGV0ZWN0IGZyZWUgdmFyaWFibGUgYG1vZHVsZWAgKi9cbiAgdmFyIGZyZWVNb2R1bGUgPSBvYmplY3RUeXBlc1t0eXBlb2YgbW9kdWxlXSAmJiBtb2R1bGUgJiYgbW9kdWxlLmV4cG9ydHMgPT0gZnJlZUV4cG9ydHMgJiYgbW9kdWxlO1xuXG4gIC8qKiBEZXRlY3QgZnJlZSB2YXJpYWJsZSBgZ2xvYmFsYCwgZnJvbSBOb2RlLmpzIG9yIEJyb3dzZXJpZmllZCBjb2RlLCBhbmQgdXNlIGl0IGFzIGB3aW5kb3dgICovXG4gIHZhciBmcmVlR2xvYmFsID0gb2JqZWN0VHlwZXNbdHlwZW9mIGdsb2JhbF0gJiYgZ2xvYmFsO1xuICBpZiAoZnJlZUdsb2JhbCAmJiAoZnJlZUdsb2JhbC5nbG9iYWwgPT09IGZyZWVHbG9iYWwgfHwgZnJlZUdsb2JhbC53aW5kb3cgPT09IGZyZWVHbG9iYWwpKSB7XG4gICAgd2luZG93ID0gZnJlZUdsb2JhbDtcbiAgfVxuXG4gIC8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuXG4gIC8qKlxuICAgKiBBIGJhc2ljIGltcGxlbWVudGF0aW9uIG9mIGBfLmluZGV4T2ZgIHdpdGhvdXQgc3VwcG9ydCBmb3IgYmluYXJ5IHNlYXJjaGVzXG4gICAqIG9yIGBmcm9tSW5kZXhgIGNvbnN0cmFpbnRzLlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcGFyYW0ge0FycmF5fSBhcnJheSBUaGUgYXJyYXkgdG8gc2VhcmNoLlxuICAgKiBAcGFyYW0ge01peGVkfSB2YWx1ZSBUaGUgdmFsdWUgdG8gc2VhcmNoIGZvci5cbiAgICogQHBhcmFtIHtOdW1iZXJ9IFtmcm9tSW5kZXg9MF0gVGhlIGluZGV4IHRvIHNlYXJjaCBmcm9tLlxuICAgKiBAcmV0dXJucyB7TnVtYmVyfSBSZXR1cm5zIHRoZSBpbmRleCBvZiB0aGUgbWF0Y2hlZCB2YWx1ZSBvciBgLTFgLlxuICAgKi9cbiAgZnVuY3Rpb24gYmFzaWNJbmRleE9mKGFycmF5LCB2YWx1ZSwgZnJvbUluZGV4KSB7XG4gICAgdmFyIGluZGV4ID0gKGZyb21JbmRleCB8fCAwKSAtIDEsXG4gICAgICAgIGxlbmd0aCA9IGFycmF5Lmxlbmd0aDtcblxuICAgIHdoaWxlICgrK2luZGV4IDwgbGVuZ3RoKSB7XG4gICAgICBpZiAoYXJyYXlbaW5kZXhdID09PSB2YWx1ZSkge1xuICAgICAgICByZXR1cm4gaW5kZXg7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiAtMTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBbiBpbXBsZW1lbnRhdGlvbiBvZiBgXy5jb250YWluc2AgZm9yIGNhY2hlIG9iamVjdHMgdGhhdCBtaW1pY3MgdGhlIHJldHVyblxuICAgKiBzaWduYXR1cmUgb2YgYF8uaW5kZXhPZmAgYnkgcmV0dXJuaW5nIGAwYCBpZiB0aGUgdmFsdWUgaXMgZm91bmQsIGVsc2UgYC0xYC5cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICogQHBhcmFtIHtPYmplY3R9IGNhY2hlIFRoZSBjYWNoZSBvYmplY3QgdG8gaW5zcGVjdC5cbiAgICogQHBhcmFtIHtNaXhlZH0gdmFsdWUgVGhlIHZhbHVlIHRvIHNlYXJjaCBmb3IuXG4gICAqIEByZXR1cm5zIHtOdW1iZXJ9IFJldHVybnMgYDBgIGlmIGB2YWx1ZWAgaXMgZm91bmQsIGVsc2UgYC0xYC5cbiAgICovXG4gIGZ1bmN0aW9uIGNhY2hlSW5kZXhPZihjYWNoZSwgdmFsdWUpIHtcbiAgICB2YXIgdHlwZSA9IHR5cGVvZiB2YWx1ZTtcbiAgICBjYWNoZSA9IGNhY2hlLmNhY2hlO1xuXG4gICAgaWYgKHR5cGUgPT0gJ2Jvb2xlYW4nIHx8IHZhbHVlID09IG51bGwpIHtcbiAgICAgIHJldHVybiBjYWNoZVt2YWx1ZV07XG4gICAgfVxuICAgIGlmICh0eXBlICE9ICdudW1iZXInICYmIHR5cGUgIT0gJ3N0cmluZycpIHtcbiAgICAgIHR5cGUgPSAnb2JqZWN0JztcbiAgICB9XG4gICAgdmFyIGtleSA9IHR5cGUgPT0gJ251bWJlcicgPyB2YWx1ZSA6IGtleVByZWZpeCArIHZhbHVlO1xuICAgIGNhY2hlID0gY2FjaGVbdHlwZV0gfHwgKGNhY2hlW3R5cGVdID0ge30pO1xuXG4gICAgcmV0dXJuIHR5cGUgPT0gJ29iamVjdCdcbiAgICAgID8gKGNhY2hlW2tleV0gJiYgYmFzaWNJbmRleE9mKGNhY2hlW2tleV0sIHZhbHVlKSA+IC0xID8gMCA6IC0xKVxuICAgICAgOiAoY2FjaGVba2V5XSA/IDAgOiAtMSk7XG4gIH1cblxuICAvKipcbiAgICogQWRkcyBhIGdpdmVuIGB2YWx1ZWAgdG8gdGhlIGNvcnJlc3BvbmRpbmcgY2FjaGUgb2JqZWN0LlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcGFyYW0ge01peGVkfSB2YWx1ZSBUaGUgdmFsdWUgdG8gYWRkIHRvIHRoZSBjYWNoZS5cbiAgICovXG4gIGZ1bmN0aW9uIGNhY2hlUHVzaCh2YWx1ZSkge1xuICAgIHZhciBjYWNoZSA9IHRoaXMuY2FjaGUsXG4gICAgICAgIHR5cGUgPSB0eXBlb2YgdmFsdWU7XG5cbiAgICBpZiAodHlwZSA9PSAnYm9vbGVhbicgfHwgdmFsdWUgPT0gbnVsbCkge1xuICAgICAgY2FjaGVbdmFsdWVdID0gdHJ1ZTtcbiAgICB9IGVsc2Uge1xuICAgICAgaWYgKHR5cGUgIT0gJ251bWJlcicgJiYgdHlwZSAhPSAnc3RyaW5nJykge1xuICAgICAgICB0eXBlID0gJ29iamVjdCc7XG4gICAgICB9XG4gICAgICB2YXIga2V5ID0gdHlwZSA9PSAnbnVtYmVyJyA/IHZhbHVlIDoga2V5UHJlZml4ICsgdmFsdWUsXG4gICAgICAgICAgdHlwZUNhY2hlID0gY2FjaGVbdHlwZV0gfHwgKGNhY2hlW3R5cGVdID0ge30pO1xuXG4gICAgICBpZiAodHlwZSA9PSAnb2JqZWN0Jykge1xuICAgICAgICBpZiAoKHR5cGVDYWNoZVtrZXldIHx8ICh0eXBlQ2FjaGVba2V5XSA9IFtdKSkucHVzaCh2YWx1ZSkgPT0gdGhpcy5hcnJheS5sZW5ndGgpIHtcbiAgICAgICAgICBjYWNoZVt0eXBlXSA9IGZhbHNlO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0eXBlQ2FjaGVba2V5XSA9IHRydWU7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFVzZWQgYnkgYF8ubWF4YCBhbmQgYF8ubWluYCBhcyB0aGUgZGVmYXVsdCBgY2FsbGJhY2tgIHdoZW4gYSBnaXZlblxuICAgKiBgY29sbGVjdGlvbmAgaXMgYSBzdHJpbmcgdmFsdWUuXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqIEBwYXJhbSB7U3RyaW5nfSB2YWx1ZSBUaGUgY2hhcmFjdGVyIHRvIGluc3BlY3QuXG4gICAqIEByZXR1cm5zIHtOdW1iZXJ9IFJldHVybnMgdGhlIGNvZGUgdW5pdCBvZiBnaXZlbiBjaGFyYWN0ZXIuXG4gICAqL1xuICBmdW5jdGlvbiBjaGFyQXRDYWxsYmFjayh2YWx1ZSkge1xuICAgIHJldHVybiB2YWx1ZS5jaGFyQ29kZUF0KDApO1xuICB9XG5cbiAgLyoqXG4gICAqIFVzZWQgYnkgYHNvcnRCeWAgdG8gY29tcGFyZSB0cmFuc2Zvcm1lZCBgY29sbGVjdGlvbmAgdmFsdWVzLCBzdGFibGUgc29ydGluZ1xuICAgKiB0aGVtIGluIGFzY2VuZGluZyBvcmRlci5cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICogQHBhcmFtIHtPYmplY3R9IGEgVGhlIG9iamVjdCB0byBjb21wYXJlIHRvIGBiYC5cbiAgICogQHBhcmFtIHtPYmplY3R9IGIgVGhlIG9iamVjdCB0byBjb21wYXJlIHRvIGBhYC5cbiAgICogQHJldHVybnMge051bWJlcn0gUmV0dXJucyB0aGUgc29ydCBvcmRlciBpbmRpY2F0b3Igb2YgYDFgIG9yIGAtMWAuXG4gICAqL1xuICBmdW5jdGlvbiBjb21wYXJlQXNjZW5kaW5nKGEsIGIpIHtcbiAgICB2YXIgYWkgPSBhLmluZGV4LFxuICAgICAgICBiaSA9IGIuaW5kZXg7XG5cbiAgICBhID0gYS5jcml0ZXJpYTtcbiAgICBiID0gYi5jcml0ZXJpYTtcblxuICAgIC8vIGVuc3VyZSBhIHN0YWJsZSBzb3J0IGluIFY4IGFuZCBvdGhlciBlbmdpbmVzXG4gICAgLy8gaHR0cDovL2NvZGUuZ29vZ2xlLmNvbS9wL3Y4L2lzc3Vlcy9kZXRhaWw/aWQ9OTBcbiAgICBpZiAoYSAhPT0gYikge1xuICAgICAgaWYgKGEgPiBiIHx8IHR5cGVvZiBhID09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgIHJldHVybiAxO1xuICAgICAgfVxuICAgICAgaWYgKGEgPCBiIHx8IHR5cGVvZiBiID09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgIHJldHVybiAtMTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGFpIDwgYmkgPyAtMSA6IDE7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBhIGNhY2hlIG9iamVjdCB0byBvcHRpbWl6ZSBsaW5lYXIgc2VhcmNoZXMgb2YgbGFyZ2UgYXJyYXlzLlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcGFyYW0ge0FycmF5fSBbYXJyYXk9W11dIFRoZSBhcnJheSB0byBzZWFyY2guXG4gICAqIEByZXR1cm5zIHtOdWxsfE9iamVjdH0gUmV0dXJucyB0aGUgY2FjaGUgb2JqZWN0IG9yIGBudWxsYCBpZiBjYWNoaW5nIHNob3VsZCBub3QgYmUgdXNlZC5cbiAgICovXG4gIGZ1bmN0aW9uIGNyZWF0ZUNhY2hlKGFycmF5KSB7XG4gICAgdmFyIGluZGV4ID0gLTEsXG4gICAgICAgIGxlbmd0aCA9IGFycmF5Lmxlbmd0aDtcblxuICAgIHZhciBjYWNoZSA9IGdldE9iamVjdCgpO1xuICAgIGNhY2hlWydmYWxzZSddID0gY2FjaGVbJ251bGwnXSA9IGNhY2hlWyd0cnVlJ10gPSBjYWNoZVsndW5kZWZpbmVkJ10gPSBmYWxzZTtcblxuICAgIHZhciByZXN1bHQgPSBnZXRPYmplY3QoKTtcbiAgICByZXN1bHQuYXJyYXkgPSBhcnJheTtcbiAgICByZXN1bHQuY2FjaGUgPSBjYWNoZTtcbiAgICByZXN1bHQucHVzaCA9IGNhY2hlUHVzaDtcblxuICAgIHdoaWxlICgrK2luZGV4IDwgbGVuZ3RoKSB7XG4gICAgICByZXN1bHQucHVzaChhcnJheVtpbmRleF0pO1xuICAgIH1cbiAgICByZXR1cm4gY2FjaGUub2JqZWN0ID09PSBmYWxzZVxuICAgICAgPyAocmVsZWFzZU9iamVjdChyZXN1bHQpLCBudWxsKVxuICAgICAgOiByZXN1bHQ7XG4gIH1cblxuICAvKipcbiAgICogVXNlZCBieSBgdGVtcGxhdGVgIHRvIGVzY2FwZSBjaGFyYWN0ZXJzIGZvciBpbmNsdXNpb24gaW4gY29tcGlsZWRcbiAgICogc3RyaW5nIGxpdGVyYWxzLlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcGFyYW0ge1N0cmluZ30gbWF0Y2ggVGhlIG1hdGNoZWQgY2hhcmFjdGVyIHRvIGVzY2FwZS5cbiAgICogQHJldHVybnMge1N0cmluZ30gUmV0dXJucyB0aGUgZXNjYXBlZCBjaGFyYWN0ZXIuXG4gICAqL1xuICBmdW5jdGlvbiBlc2NhcGVTdHJpbmdDaGFyKG1hdGNoKSB7XG4gICAgcmV0dXJuICdcXFxcJyArIHN0cmluZ0VzY2FwZXNbbWF0Y2hdO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgYW4gYXJyYXkgZnJvbSB0aGUgYXJyYXkgcG9vbCBvciBjcmVhdGVzIGEgbmV3IG9uZSBpZiB0aGUgcG9vbCBpcyBlbXB0eS5cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICogQHJldHVybnMge0FycmF5fSBUaGUgYXJyYXkgZnJvbSB0aGUgcG9vbC5cbiAgICovXG4gIGZ1bmN0aW9uIGdldEFycmF5KCkge1xuICAgIHJldHVybiBhcnJheVBvb2wucG9wKCkgfHwgW107XG4gIH1cblxuICAvKipcbiAgICogR2V0cyBhbiBvYmplY3QgZnJvbSB0aGUgb2JqZWN0IHBvb2wgb3IgY3JlYXRlcyBhIG5ldyBvbmUgaWYgdGhlIHBvb2wgaXMgZW1wdHkuXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBvYmplY3QgZnJvbSB0aGUgcG9vbC5cbiAgICovXG4gIGZ1bmN0aW9uIGdldE9iamVjdCgpIHtcbiAgICByZXR1cm4gb2JqZWN0UG9vbC5wb3AoKSB8fCB7XG4gICAgICAnYXJyYXknOiBudWxsLFxuICAgICAgJ2NhY2hlJzogbnVsbCxcbiAgICAgICdjcml0ZXJpYSc6IG51bGwsXG4gICAgICAnZmFsc2UnOiBmYWxzZSxcbiAgICAgICdpbmRleCc6IDAsXG4gICAgICAnbGVhZGluZyc6IGZhbHNlLFxuICAgICAgJ21heFdhaXQnOiAwLFxuICAgICAgJ251bGwnOiBmYWxzZSxcbiAgICAgICdudW1iZXInOiBudWxsLFxuICAgICAgJ29iamVjdCc6IG51bGwsXG4gICAgICAncHVzaCc6IG51bGwsXG4gICAgICAnc3RyaW5nJzogbnVsbCxcbiAgICAgICd0cmFpbGluZyc6IGZhbHNlLFxuICAgICAgJ3RydWUnOiBmYWxzZSxcbiAgICAgICd1bmRlZmluZWQnOiBmYWxzZSxcbiAgICAgICd2YWx1ZSc6IG51bGxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEEgbm8tb3BlcmF0aW9uIGZ1bmN0aW9uLlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgZnVuY3Rpb24gbm9vcCgpIHtcbiAgICAvLyBubyBvcGVyYXRpb24gcGVyZm9ybWVkXG4gIH1cblxuICAvKipcbiAgICogUmVsZWFzZXMgdGhlIGdpdmVuIGBhcnJheWAgYmFjayB0byB0aGUgYXJyYXkgcG9vbC5cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICogQHBhcmFtIHtBcnJheX0gW2FycmF5XSBUaGUgYXJyYXkgdG8gcmVsZWFzZS5cbiAgICovXG4gIGZ1bmN0aW9uIHJlbGVhc2VBcnJheShhcnJheSkge1xuICAgIGFycmF5Lmxlbmd0aCA9IDA7XG4gICAgaWYgKGFycmF5UG9vbC5sZW5ndGggPCBtYXhQb29sU2l6ZSkge1xuICAgICAgYXJyYXlQb29sLnB1c2goYXJyYXkpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZWxlYXNlcyB0aGUgZ2l2ZW4gYG9iamVjdGAgYmFjayB0byB0aGUgb2JqZWN0IHBvb2wuXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBbb2JqZWN0XSBUaGUgb2JqZWN0IHRvIHJlbGVhc2UuXG4gICAqL1xuICBmdW5jdGlvbiByZWxlYXNlT2JqZWN0KG9iamVjdCkge1xuICAgIHZhciBjYWNoZSA9IG9iamVjdC5jYWNoZTtcbiAgICBpZiAoY2FjaGUpIHtcbiAgICAgIHJlbGVhc2VPYmplY3QoY2FjaGUpO1xuICAgIH1cbiAgICBvYmplY3QuYXJyYXkgPSBvYmplY3QuY2FjaGUgPSBvYmplY3QuY3JpdGVyaWEgPSBvYmplY3Qub2JqZWN0ID0gb2JqZWN0Lm51bWJlciA9IG9iamVjdC5zdHJpbmcgPSBvYmplY3QudmFsdWUgPSBudWxsO1xuICAgIGlmIChvYmplY3RQb29sLmxlbmd0aCA8IG1heFBvb2xTaXplKSB7XG4gICAgICBvYmplY3RQb29sLnB1c2gob2JqZWN0KTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogU2xpY2VzIHRoZSBgY29sbGVjdGlvbmAgZnJvbSB0aGUgYHN0YXJ0YCBpbmRleCB1cCB0bywgYnV0IG5vdCBpbmNsdWRpbmcsXG4gICAqIHRoZSBgZW5kYCBpbmRleC5cbiAgICpcbiAgICogTm90ZTogVGhpcyBmdW5jdGlvbiBpcyB1c2VkLCBpbnN0ZWFkIG9mIGBBcnJheSNzbGljZWAsIHRvIHN1cHBvcnQgbm9kZSBsaXN0c1xuICAgKiBpbiBJRSA8IDkgYW5kIHRvIGVuc3VyZSBkZW5zZSBhcnJheXMgYXJlIHJldHVybmVkLlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcGFyYW0ge0FycmF5fE9iamVjdHxTdHJpbmd9IGNvbGxlY3Rpb24gVGhlIGNvbGxlY3Rpb24gdG8gc2xpY2UuXG4gICAqIEBwYXJhbSB7TnVtYmVyfSBzdGFydCBUaGUgc3RhcnQgaW5kZXguXG4gICAqIEBwYXJhbSB7TnVtYmVyfSBlbmQgVGhlIGVuZCBpbmRleC5cbiAgICogQHJldHVybnMge0FycmF5fSBSZXR1cm5zIHRoZSBuZXcgYXJyYXkuXG4gICAqL1xuICBmdW5jdGlvbiBzbGljZShhcnJheSwgc3RhcnQsIGVuZCkge1xuICAgIHN0YXJ0IHx8IChzdGFydCA9IDApO1xuICAgIGlmICh0eXBlb2YgZW5kID09ICd1bmRlZmluZWQnKSB7XG4gICAgICBlbmQgPSBhcnJheSA/IGFycmF5Lmxlbmd0aCA6IDA7XG4gICAgfVxuICAgIHZhciBpbmRleCA9IC0xLFxuICAgICAgICBsZW5ndGggPSBlbmQgLSBzdGFydCB8fCAwLFxuICAgICAgICByZXN1bHQgPSBBcnJheShsZW5ndGggPCAwID8gMCA6IGxlbmd0aCk7XG5cbiAgICB3aGlsZSAoKytpbmRleCA8IGxlbmd0aCkge1xuICAgICAgcmVzdWx0W2luZGV4XSA9IGFycmF5W3N0YXJ0ICsgaW5kZXhdO1xuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5cbiAgLyoqXG4gICAqIENyZWF0ZSBhIG5ldyBgbG9kYXNoYCBmdW5jdGlvbiB1c2luZyB0aGUgZ2l2ZW4gYGNvbnRleHRgIG9iamVjdC5cbiAgICpcbiAgICogQHN0YXRpY1xuICAgKiBAbWVtYmVyT2YgX1xuICAgKiBAY2F0ZWdvcnkgVXRpbGl0aWVzXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBbY29udGV4dD13aW5kb3ddIFRoZSBjb250ZXh0IG9iamVjdC5cbiAgICogQHJldHVybnMge0Z1bmN0aW9ufSBSZXR1cm5zIHRoZSBgbG9kYXNoYCBmdW5jdGlvbi5cbiAgICovXG4gIGZ1bmN0aW9uIHJ1bkluQ29udGV4dChjb250ZXh0KSB7XG4gICAgLy8gQXZvaWQgaXNzdWVzIHdpdGggc29tZSBFUzMgZW52aXJvbm1lbnRzIHRoYXQgYXR0ZW1wdCB0byB1c2UgdmFsdWVzLCBuYW1lZFxuICAgIC8vIGFmdGVyIGJ1aWx0LWluIGNvbnN0cnVjdG9ycyBsaWtlIGBPYmplY3RgLCBmb3IgdGhlIGNyZWF0aW9uIG9mIGxpdGVyYWxzLlxuICAgIC8vIEVTNSBjbGVhcnMgdGhpcyB1cCBieSBzdGF0aW5nIHRoYXQgbGl0ZXJhbHMgbXVzdCB1c2UgYnVpbHQtaW4gY29uc3RydWN0b3JzLlxuICAgIC8vIFNlZSBodHRwOi8vZXM1LmdpdGh1Yi5jb20vI3gxMS4xLjUuXG4gICAgY29udGV4dCA9IGNvbnRleHQgPyBfLmRlZmF1bHRzKHdpbmRvdy5PYmplY3QoKSwgY29udGV4dCwgXy5waWNrKHdpbmRvdywgY29udGV4dFByb3BzKSkgOiB3aW5kb3c7XG5cbiAgICAvKiogTmF0aXZlIGNvbnN0cnVjdG9yIHJlZmVyZW5jZXMgKi9cbiAgICB2YXIgQXJyYXkgPSBjb250ZXh0LkFycmF5LFxuICAgICAgICBCb29sZWFuID0gY29udGV4dC5Cb29sZWFuLFxuICAgICAgICBEYXRlID0gY29udGV4dC5EYXRlLFxuICAgICAgICBGdW5jdGlvbiA9IGNvbnRleHQuRnVuY3Rpb24sXG4gICAgICAgIE1hdGggPSBjb250ZXh0Lk1hdGgsXG4gICAgICAgIE51bWJlciA9IGNvbnRleHQuTnVtYmVyLFxuICAgICAgICBPYmplY3QgPSBjb250ZXh0Lk9iamVjdCxcbiAgICAgICAgUmVnRXhwID0gY29udGV4dC5SZWdFeHAsXG4gICAgICAgIFN0cmluZyA9IGNvbnRleHQuU3RyaW5nLFxuICAgICAgICBUeXBlRXJyb3IgPSBjb250ZXh0LlR5cGVFcnJvcjtcblxuICAgIC8qKlxuICAgICAqIFVzZWQgZm9yIGBBcnJheWAgbWV0aG9kIHJlZmVyZW5jZXMuXG4gICAgICpcbiAgICAgKiBOb3JtYWxseSBgQXJyYXkucHJvdG90eXBlYCB3b3VsZCBzdWZmaWNlLCBob3dldmVyLCB1c2luZyBhbiBhcnJheSBsaXRlcmFsXG4gICAgICogYXZvaWRzIGlzc3VlcyBpbiBOYXJ3aGFsLlxuICAgICAqL1xuICAgIHZhciBhcnJheVJlZiA9IFtdO1xuXG4gICAgLyoqIFVzZWQgZm9yIG5hdGl2ZSBtZXRob2QgcmVmZXJlbmNlcyAqL1xuICAgIHZhciBvYmplY3RQcm90byA9IE9iamVjdC5wcm90b3R5cGUsXG4gICAgICAgIHN0cmluZ1Byb3RvID0gU3RyaW5nLnByb3RvdHlwZTtcblxuICAgIC8qKiBVc2VkIHRvIHJlc3RvcmUgdGhlIG9yaWdpbmFsIGBfYCByZWZlcmVuY2UgaW4gYG5vQ29uZmxpY3RgICovXG4gICAgdmFyIG9sZERhc2ggPSBjb250ZXh0Ll87XG5cbiAgICAvKiogVXNlZCB0byBkZXRlY3QgaWYgYSBtZXRob2QgaXMgbmF0aXZlICovXG4gICAgdmFyIHJlTmF0aXZlID0gUmVnRXhwKCdeJyArXG4gICAgICBTdHJpbmcob2JqZWN0UHJvdG8udmFsdWVPZilcbiAgICAgICAgLnJlcGxhY2UoL1suKis/XiR7fSgpfFtcXF1cXFxcXS9nLCAnXFxcXCQmJylcbiAgICAgICAgLnJlcGxhY2UoL3ZhbHVlT2Z8Zm9yIFteXFxdXSsvZywgJy4rPycpICsgJyQnXG4gICAgKTtcblxuICAgIC8qKiBOYXRpdmUgbWV0aG9kIHNob3J0Y3V0cyAqL1xuICAgIHZhciBjZWlsID0gTWF0aC5jZWlsLFxuICAgICAgICBjbGVhclRpbWVvdXQgPSBjb250ZXh0LmNsZWFyVGltZW91dCxcbiAgICAgICAgY29uY2F0ID0gYXJyYXlSZWYuY29uY2F0LFxuICAgICAgICBmbG9vciA9IE1hdGguZmxvb3IsXG4gICAgICAgIGZuVG9TdHJpbmcgPSBGdW5jdGlvbi5wcm90b3R5cGUudG9TdHJpbmcsXG4gICAgICAgIGdldFByb3RvdHlwZU9mID0gcmVOYXRpdmUudGVzdChnZXRQcm90b3R5cGVPZiA9IE9iamVjdC5nZXRQcm90b3R5cGVPZikgJiYgZ2V0UHJvdG90eXBlT2YsXG4gICAgICAgIGhhc093blByb3BlcnR5ID0gb2JqZWN0UHJvdG8uaGFzT3duUHJvcGVydHksXG4gICAgICAgIHB1c2ggPSBhcnJheVJlZi5wdXNoLFxuICAgICAgICBwcm9wZXJ0eUlzRW51bWVyYWJsZSA9IG9iamVjdFByb3RvLnByb3BlcnR5SXNFbnVtZXJhYmxlLFxuICAgICAgICBzZXRJbW1lZGlhdGUgPSBjb250ZXh0LnNldEltbWVkaWF0ZSxcbiAgICAgICAgc2V0VGltZW91dCA9IGNvbnRleHQuc2V0VGltZW91dCxcbiAgICAgICAgdG9TdHJpbmcgPSBvYmplY3RQcm90by50b1N0cmluZztcblxuICAgIC8qIE5hdGl2ZSBtZXRob2Qgc2hvcnRjdXRzIGZvciBtZXRob2RzIHdpdGggdGhlIHNhbWUgbmFtZSBhcyBvdGhlciBgbG9kYXNoYCBtZXRob2RzICovXG4gICAgdmFyIG5hdGl2ZUJpbmQgPSByZU5hdGl2ZS50ZXN0KG5hdGl2ZUJpbmQgPSB0b1N0cmluZy5iaW5kKSAmJiBuYXRpdmVCaW5kLFxuICAgICAgICBuYXRpdmVDcmVhdGUgPSByZU5hdGl2ZS50ZXN0KG5hdGl2ZUNyZWF0ZSA9ICBPYmplY3QuY3JlYXRlKSAmJiBuYXRpdmVDcmVhdGUsXG4gICAgICAgIG5hdGl2ZUlzQXJyYXkgPSByZU5hdGl2ZS50ZXN0KG5hdGl2ZUlzQXJyYXkgPSBBcnJheS5pc0FycmF5KSAmJiBuYXRpdmVJc0FycmF5LFxuICAgICAgICBuYXRpdmVJc0Zpbml0ZSA9IGNvbnRleHQuaXNGaW5pdGUsXG4gICAgICAgIG5hdGl2ZUlzTmFOID0gY29udGV4dC5pc05hTixcbiAgICAgICAgbmF0aXZlS2V5cyA9IHJlTmF0aXZlLnRlc3QobmF0aXZlS2V5cyA9IE9iamVjdC5rZXlzKSAmJiBuYXRpdmVLZXlzLFxuICAgICAgICBuYXRpdmVNYXggPSBNYXRoLm1heCxcbiAgICAgICAgbmF0aXZlTWluID0gTWF0aC5taW4sXG4gICAgICAgIG5hdGl2ZVBhcnNlSW50ID0gY29udGV4dC5wYXJzZUludCxcbiAgICAgICAgbmF0aXZlUmFuZG9tID0gTWF0aC5yYW5kb20sXG4gICAgICAgIG5hdGl2ZVNsaWNlID0gYXJyYXlSZWYuc2xpY2U7XG5cbiAgICAvKiogRGV0ZWN0IHZhcmlvdXMgZW52aXJvbm1lbnRzICovXG4gICAgdmFyIGlzSWVPcGVyYSA9IHJlTmF0aXZlLnRlc3QoY29udGV4dC5hdHRhY2hFdmVudCksXG4gICAgICAgIGlzVjggPSBuYXRpdmVCaW5kICYmICEvXFxufHRydWUvLnRlc3QobmF0aXZlQmluZCArIGlzSWVPcGVyYSk7XG5cbiAgICAvKiogVXNlZCB0byBsb29rdXAgYSBidWlsdC1pbiBjb25zdHJ1Y3RvciBieSBbW0NsYXNzXV0gKi9cbiAgICB2YXIgY3RvckJ5Q2xhc3MgPSB7fTtcbiAgICBjdG9yQnlDbGFzc1thcnJheUNsYXNzXSA9IEFycmF5O1xuICAgIGN0b3JCeUNsYXNzW2Jvb2xDbGFzc10gPSBCb29sZWFuO1xuICAgIGN0b3JCeUNsYXNzW2RhdGVDbGFzc10gPSBEYXRlO1xuICAgIGN0b3JCeUNsYXNzW2Z1bmNDbGFzc10gPSBGdW5jdGlvbjtcbiAgICBjdG9yQnlDbGFzc1tvYmplY3RDbGFzc10gPSBPYmplY3Q7XG4gICAgY3RvckJ5Q2xhc3NbbnVtYmVyQ2xhc3NdID0gTnVtYmVyO1xuICAgIGN0b3JCeUNsYXNzW3JlZ2V4cENsYXNzXSA9IFJlZ0V4cDtcbiAgICBjdG9yQnlDbGFzc1tzdHJpbmdDbGFzc10gPSBTdHJpbmc7XG5cbiAgICAvKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYSBgbG9kYXNoYCBvYmplY3QsIHdoaWNoIHdyYXBzIHRoZSBnaXZlbiBgdmFsdWVgLCB0byBlbmFibGUgbWV0aG9kXG4gICAgICogY2hhaW5pbmcuXG4gICAgICpcbiAgICAgKiBJbiBhZGRpdGlvbiB0byBMby1EYXNoIG1ldGhvZHMsIHdyYXBwZXJzIGFsc28gaGF2ZSB0aGUgZm9sbG93aW5nIGBBcnJheWAgbWV0aG9kczpcbiAgICAgKiBgY29uY2F0YCwgYGpvaW5gLCBgcG9wYCwgYHB1c2hgLCBgcmV2ZXJzZWAsIGBzaGlmdGAsIGBzbGljZWAsIGBzb3J0YCwgYHNwbGljZWAsXG4gICAgICogYW5kIGB1bnNoaWZ0YFxuICAgICAqXG4gICAgICogQ2hhaW5pbmcgaXMgc3VwcG9ydGVkIGluIGN1c3RvbSBidWlsZHMgYXMgbG9uZyBhcyB0aGUgYHZhbHVlYCBtZXRob2QgaXNcbiAgICAgKiBpbXBsaWNpdGx5IG9yIGV4cGxpY2l0bHkgaW5jbHVkZWQgaW4gdGhlIGJ1aWxkLlxuICAgICAqXG4gICAgICogVGhlIGNoYWluYWJsZSB3cmFwcGVyIGZ1bmN0aW9ucyBhcmU6XG4gICAgICogYGFmdGVyYCwgYGFzc2lnbmAsIGBiaW5kYCwgYGJpbmRBbGxgLCBgYmluZEtleWAsIGBjaGFpbmAsIGBjb21wYWN0YCxcbiAgICAgKiBgY29tcG9zZWAsIGBjb25jYXRgLCBgY291bnRCeWAsIGBjcmVhdGVDYWxsYmFja2AsIGBkZWJvdW5jZWAsIGBkZWZhdWx0c2AsXG4gICAgICogYGRlZmVyYCwgYGRlbGF5YCwgYGRpZmZlcmVuY2VgLCBgZmlsdGVyYCwgYGZsYXR0ZW5gLCBgZm9yRWFjaGAsIGBmb3JJbmAsXG4gICAgICogYGZvck93bmAsIGBmdW5jdGlvbnNgLCBgZ3JvdXBCeWAsIGBpbml0aWFsYCwgYGludGVyc2VjdGlvbmAsIGBpbnZlcnRgLFxuICAgICAqIGBpbnZva2VgLCBga2V5c2AsIGBtYXBgLCBgbWF4YCwgYG1lbW9pemVgLCBgbWVyZ2VgLCBgbWluYCwgYG9iamVjdGAsIGBvbWl0YCxcbiAgICAgKiBgb25jZWAsIGBwYWlyc2AsIGBwYXJ0aWFsYCwgYHBhcnRpYWxSaWdodGAsIGBwaWNrYCwgYHBsdWNrYCwgYHB1c2hgLCBgcmFuZ2VgLFxuICAgICAqIGByZWplY3RgLCBgcmVzdGAsIGByZXZlcnNlYCwgYHNodWZmbGVgLCBgc2xpY2VgLCBgc29ydGAsIGBzb3J0QnlgLCBgc3BsaWNlYCxcbiAgICAgKiBgdGFwYCwgYHRocm90dGxlYCwgYHRpbWVzYCwgYHRvQXJyYXlgLCBgdHJhbnNmb3JtYCwgYHVuaW9uYCwgYHVuaXFgLCBgdW5zaGlmdGAsXG4gICAgICogYHVuemlwYCwgYHZhbHVlc2AsIGB3aGVyZWAsIGB3aXRob3V0YCwgYHdyYXBgLCBhbmQgYHppcGBcbiAgICAgKlxuICAgICAqIFRoZSBub24tY2hhaW5hYmxlIHdyYXBwZXIgZnVuY3Rpb25zIGFyZTpcbiAgICAgKiBgY2xvbmVgLCBgY2xvbmVEZWVwYCwgYGNvbnRhaW5zYCwgYGVzY2FwZWAsIGBldmVyeWAsIGBmaW5kYCwgYGhhc2AsXG4gICAgICogYGlkZW50aXR5YCwgYGluZGV4T2ZgLCBgaXNBcmd1bWVudHNgLCBgaXNBcnJheWAsIGBpc0Jvb2xlYW5gLCBgaXNEYXRlYCxcbiAgICAgKiBgaXNFbGVtZW50YCwgYGlzRW1wdHlgLCBgaXNFcXVhbGAsIGBpc0Zpbml0ZWAsIGBpc0Z1bmN0aW9uYCwgYGlzTmFOYCxcbiAgICAgKiBgaXNOdWxsYCwgYGlzTnVtYmVyYCwgYGlzT2JqZWN0YCwgYGlzUGxhaW5PYmplY3RgLCBgaXNSZWdFeHBgLCBgaXNTdHJpbmdgLFxuICAgICAqIGBpc1VuZGVmaW5lZGAsIGBqb2luYCwgYGxhc3RJbmRleE9mYCwgYG1peGluYCwgYG5vQ29uZmxpY3RgLCBgcGFyc2VJbnRgLFxuICAgICAqIGBwb3BgLCBgcmFuZG9tYCwgYHJlZHVjZWAsIGByZWR1Y2VSaWdodGAsIGByZXN1bHRgLCBgc2hpZnRgLCBgc2l6ZWAsIGBzb21lYCxcbiAgICAgKiBgc29ydGVkSW5kZXhgLCBgcnVuSW5Db250ZXh0YCwgYHRlbXBsYXRlYCwgYHVuZXNjYXBlYCwgYHVuaXF1ZUlkYCwgYW5kIGB2YWx1ZWBcbiAgICAgKlxuICAgICAqIFRoZSB3cmFwcGVyIGZ1bmN0aW9ucyBgZmlyc3RgIGFuZCBgbGFzdGAgcmV0dXJuIHdyYXBwZWQgdmFsdWVzIHdoZW4gYG5gIGlzXG4gICAgICogcGFzc2VkLCBvdGhlcndpc2UgdGhleSByZXR1cm4gdW53cmFwcGVkIHZhbHVlcy5cbiAgICAgKlxuICAgICAqIEBuYW1lIF9cbiAgICAgKiBAY29uc3RydWN0b3JcbiAgICAgKiBAYWxpYXMgY2hhaW5cbiAgICAgKiBAY2F0ZWdvcnkgQ2hhaW5pbmdcbiAgICAgKiBAcGFyYW0ge01peGVkfSB2YWx1ZSBUaGUgdmFsdWUgdG8gd3JhcCBpbiBhIGBsb2Rhc2hgIGluc3RhbmNlLlxuICAgICAqIEByZXR1cm5zIHtPYmplY3R9IFJldHVybnMgYSBgbG9kYXNoYCBpbnN0YW5jZS5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogdmFyIHdyYXBwZWQgPSBfKFsxLCAyLCAzXSk7XG4gICAgICpcbiAgICAgKiAvLyByZXR1cm5zIGFuIHVud3JhcHBlZCB2YWx1ZVxuICAgICAqIHdyYXBwZWQucmVkdWNlKGZ1bmN0aW9uKHN1bSwgbnVtKSB7XG4gICAgICogICByZXR1cm4gc3VtICsgbnVtO1xuICAgICAqIH0pO1xuICAgICAqIC8vID0+IDZcbiAgICAgKlxuICAgICAqIC8vIHJldHVybnMgYSB3cmFwcGVkIHZhbHVlXG4gICAgICogdmFyIHNxdWFyZXMgPSB3cmFwcGVkLm1hcChmdW5jdGlvbihudW0pIHtcbiAgICAgKiAgIHJldHVybiBudW0gKiBudW07XG4gICAgICogfSk7XG4gICAgICpcbiAgICAgKiBfLmlzQXJyYXkoc3F1YXJlcyk7XG4gICAgICogLy8gPT4gZmFsc2VcbiAgICAgKlxuICAgICAqIF8uaXNBcnJheShzcXVhcmVzLnZhbHVlKCkpO1xuICAgICAqIC8vID0+IHRydWVcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBsb2Rhc2godmFsdWUpIHtcbiAgICAgIC8vIGRvbid0IHdyYXAgaWYgYWxyZWFkeSB3cmFwcGVkLCBldmVuIGlmIHdyYXBwZWQgYnkgYSBkaWZmZXJlbnQgYGxvZGFzaGAgY29uc3RydWN0b3JcbiAgICAgIHJldHVybiAodmFsdWUgJiYgdHlwZW9mIHZhbHVlID09ICdvYmplY3QnICYmICFpc0FycmF5KHZhbHVlKSAmJiBoYXNPd25Qcm9wZXJ0eS5jYWxsKHZhbHVlLCAnX193cmFwcGVkX18nKSlcbiAgICAgICA/IHZhbHVlXG4gICAgICAgOiBuZXcgbG9kYXNoV3JhcHBlcih2YWx1ZSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQSBmYXN0IHBhdGggZm9yIGNyZWF0aW5nIGBsb2Rhc2hgIHdyYXBwZXIgb2JqZWN0cy5cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtNaXhlZH0gdmFsdWUgVGhlIHZhbHVlIHRvIHdyYXAgaW4gYSBgbG9kYXNoYCBpbnN0YW5jZS5cbiAgICAgKiBAcmV0dXJucyB7T2JqZWN0fSBSZXR1cm5zIGEgYGxvZGFzaGAgaW5zdGFuY2UuXG4gICAgICovXG4gICAgZnVuY3Rpb24gbG9kYXNoV3JhcHBlcih2YWx1ZSkge1xuICAgICAgdGhpcy5fX3dyYXBwZWRfXyA9IHZhbHVlO1xuICAgIH1cbiAgICAvLyBlbnN1cmUgYG5ldyBsb2Rhc2hXcmFwcGVyYCBpcyBhbiBpbnN0YW5jZSBvZiBgbG9kYXNoYFxuICAgIGxvZGFzaFdyYXBwZXIucHJvdG90eXBlID0gbG9kYXNoLnByb3RvdHlwZTtcblxuICAgIC8qKlxuICAgICAqIEFuIG9iamVjdCB1c2VkIHRvIGZsYWcgZW52aXJvbm1lbnRzIGZlYXR1cmVzLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQHR5cGUgT2JqZWN0XG4gICAgICovXG4gICAgdmFyIHN1cHBvcnQgPSBsb2Rhc2guc3VwcG9ydCA9IHt9O1xuXG4gICAgLyoqXG4gICAgICogRGV0ZWN0IGlmIGBGdW5jdGlvbiNiaW5kYCBleGlzdHMgYW5kIGlzIGluZmVycmVkIHRvIGJlIGZhc3QgKGFsbCBidXQgVjgpLlxuICAgICAqXG4gICAgICogQG1lbWJlck9mIF8uc3VwcG9ydFxuICAgICAqIEB0eXBlIEJvb2xlYW5cbiAgICAgKi9cbiAgICBzdXBwb3J0LmZhc3RCaW5kID0gbmF0aXZlQmluZCAmJiAhaXNWODtcblxuICAgIC8qKlxuICAgICAqIEJ5IGRlZmF1bHQsIHRoZSB0ZW1wbGF0ZSBkZWxpbWl0ZXJzIHVzZWQgYnkgTG8tRGFzaCBhcmUgc2ltaWxhciB0byB0aG9zZSBpblxuICAgICAqIGVtYmVkZGVkIFJ1YnkgKEVSQikuIENoYW5nZSB0aGUgZm9sbG93aW5nIHRlbXBsYXRlIHNldHRpbmdzIHRvIHVzZSBhbHRlcm5hdGl2ZVxuICAgICAqIGRlbGltaXRlcnMuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAdHlwZSBPYmplY3RcbiAgICAgKi9cbiAgICBsb2Rhc2gudGVtcGxhdGVTZXR0aW5ncyA9IHtcblxuICAgICAgLyoqXG4gICAgICAgKiBVc2VkIHRvIGRldGVjdCBgZGF0YWAgcHJvcGVydHkgdmFsdWVzIHRvIGJlIEhUTUwtZXNjYXBlZC5cbiAgICAgICAqXG4gICAgICAgKiBAbWVtYmVyT2YgXy50ZW1wbGF0ZVNldHRpbmdzXG4gICAgICAgKiBAdHlwZSBSZWdFeHBcbiAgICAgICAqL1xuICAgICAgJ2VzY2FwZSc6IC88JS0oW1xcc1xcU10rPyklPi9nLFxuXG4gICAgICAvKipcbiAgICAgICAqIFVzZWQgdG8gZGV0ZWN0IGNvZGUgdG8gYmUgZXZhbHVhdGVkLlxuICAgICAgICpcbiAgICAgICAqIEBtZW1iZXJPZiBfLnRlbXBsYXRlU2V0dGluZ3NcbiAgICAgICAqIEB0eXBlIFJlZ0V4cFxuICAgICAgICovXG4gICAgICAnZXZhbHVhdGUnOiAvPCUoW1xcc1xcU10rPyklPi9nLFxuXG4gICAgICAvKipcbiAgICAgICAqIFVzZWQgdG8gZGV0ZWN0IGBkYXRhYCBwcm9wZXJ0eSB2YWx1ZXMgdG8gaW5qZWN0LlxuICAgICAgICpcbiAgICAgICAqIEBtZW1iZXJPZiBfLnRlbXBsYXRlU2V0dGluZ3NcbiAgICAgICAqIEB0eXBlIFJlZ0V4cFxuICAgICAgICovXG4gICAgICAnaW50ZXJwb2xhdGUnOiByZUludGVycG9sYXRlLFxuXG4gICAgICAvKipcbiAgICAgICAqIFVzZWQgdG8gcmVmZXJlbmNlIHRoZSBkYXRhIG9iamVjdCBpbiB0aGUgdGVtcGxhdGUgdGV4dC5cbiAgICAgICAqXG4gICAgICAgKiBAbWVtYmVyT2YgXy50ZW1wbGF0ZVNldHRpbmdzXG4gICAgICAgKiBAdHlwZSBTdHJpbmdcbiAgICAgICAqL1xuICAgICAgJ3ZhcmlhYmxlJzogJycsXG5cbiAgICAgIC8qKlxuICAgICAgICogVXNlZCB0byBpbXBvcnQgdmFyaWFibGVzIGludG8gdGhlIGNvbXBpbGVkIHRlbXBsYXRlLlxuICAgICAgICpcbiAgICAgICAqIEBtZW1iZXJPZiBfLnRlbXBsYXRlU2V0dGluZ3NcbiAgICAgICAqIEB0eXBlIE9iamVjdFxuICAgICAgICovXG4gICAgICAnaW1wb3J0cyc6IHtcblxuICAgICAgICAvKipcbiAgICAgICAgICogQSByZWZlcmVuY2UgdG8gdGhlIGBsb2Rhc2hgIGZ1bmN0aW9uLlxuICAgICAgICAgKlxuICAgICAgICAgKiBAbWVtYmVyT2YgXy50ZW1wbGF0ZVNldHRpbmdzLmltcG9ydHNcbiAgICAgICAgICogQHR5cGUgRnVuY3Rpb25cbiAgICAgICAgICovXG4gICAgICAgICdfJzogbG9kYXNoXG4gICAgICB9XG4gICAgfTtcblxuICAgIC8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhIGZ1bmN0aW9uIHRoYXQsIHdoZW4gY2FsbGVkLCBpbnZva2VzIGBmdW5jYCB3aXRoIHRoZSBgdGhpc2AgYmluZGluZ1xuICAgICAqIG9mIGB0aGlzQXJnYCBhbmQgcHJlcGVuZHMgYW55IGBwYXJ0aWFsQXJnc2AgdG8gdGhlIGFyZ3VtZW50cyBwYXNzZWQgdG8gdGhlXG4gICAgICogYm91bmQgZnVuY3Rpb24uXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb258U3RyaW5nfSBmdW5jIFRoZSBmdW5jdGlvbiB0byBiaW5kIG9yIHRoZSBtZXRob2QgbmFtZS5cbiAgICAgKiBAcGFyYW0ge01peGVkfSBbdGhpc0FyZ10gVGhlIGB0aGlzYCBiaW5kaW5nIG9mIGBmdW5jYC5cbiAgICAgKiBAcGFyYW0ge0FycmF5fSBwYXJ0aWFsQXJncyBBbiBhcnJheSBvZiBhcmd1bWVudHMgdG8gYmUgcGFydGlhbGx5IGFwcGxpZWQuXG4gICAgICogQHBhcmFtIHtPYmplY3R9IFtpZGljYXRvcl0gVXNlZCB0byBpbmRpY2F0ZSBiaW5kaW5nIGJ5IGtleSBvciBwYXJ0aWFsbHlcbiAgICAgKiAgYXBwbHlpbmcgYXJndW1lbnRzIGZyb20gdGhlIHJpZ2h0LlxuICAgICAqIEByZXR1cm5zIHtGdW5jdGlvbn0gUmV0dXJucyB0aGUgbmV3IGJvdW5kIGZ1bmN0aW9uLlxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGNyZWF0ZUJvdW5kKGZ1bmMsIHRoaXNBcmcsIHBhcnRpYWxBcmdzLCBpbmRpY2F0b3IpIHtcbiAgICAgIHZhciBpc0Z1bmMgPSBpc0Z1bmN0aW9uKGZ1bmMpLFxuICAgICAgICAgIGlzUGFydGlhbCA9ICFwYXJ0aWFsQXJncyxcbiAgICAgICAgICBrZXkgPSB0aGlzQXJnO1xuXG4gICAgICAvLyBqdWdnbGUgYXJndW1lbnRzXG4gICAgICBpZiAoaXNQYXJ0aWFsKSB7XG4gICAgICAgIHZhciByaWdodEluZGljYXRvciA9IGluZGljYXRvcjtcbiAgICAgICAgcGFydGlhbEFyZ3MgPSB0aGlzQXJnO1xuICAgICAgfVxuICAgICAgZWxzZSBpZiAoIWlzRnVuYykge1xuICAgICAgICBpZiAoIWluZGljYXRvcikge1xuICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3I7XG4gICAgICAgIH1cbiAgICAgICAgdGhpc0FyZyA9IGZ1bmM7XG4gICAgICB9XG5cbiAgICAgIGZ1bmN0aW9uIGJvdW5kKCkge1xuICAgICAgICAvLyBgRnVuY3Rpb24jYmluZGAgc3BlY1xuICAgICAgICAvLyBodHRwOi8vZXM1LmdpdGh1Yi5jb20vI3gxNS4zLjQuNVxuICAgICAgICB2YXIgYXJncyA9IGFyZ3VtZW50cyxcbiAgICAgICAgICAgIHRoaXNCaW5kaW5nID0gaXNQYXJ0aWFsID8gdGhpcyA6IHRoaXNBcmc7XG5cbiAgICAgICAgaWYgKCFpc0Z1bmMpIHtcbiAgICAgICAgICBmdW5jID0gdGhpc0FyZ1trZXldO1xuICAgICAgICB9XG4gICAgICAgIGlmIChwYXJ0aWFsQXJncy5sZW5ndGgpIHtcbiAgICAgICAgICBhcmdzID0gYXJncy5sZW5ndGhcbiAgICAgICAgICAgID8gKGFyZ3MgPSBuYXRpdmVTbGljZS5jYWxsKGFyZ3MpLCByaWdodEluZGljYXRvciA/IGFyZ3MuY29uY2F0KHBhcnRpYWxBcmdzKSA6IHBhcnRpYWxBcmdzLmNvbmNhdChhcmdzKSlcbiAgICAgICAgICAgIDogcGFydGlhbEFyZ3M7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMgaW5zdGFuY2VvZiBib3VuZCkge1xuICAgICAgICAgIC8vIGVuc3VyZSBgbmV3IGJvdW5kYCBpcyBhbiBpbnN0YW5jZSBvZiBgZnVuY2BcbiAgICAgICAgICB0aGlzQmluZGluZyA9IGNyZWF0ZU9iamVjdChmdW5jLnByb3RvdHlwZSk7XG5cbiAgICAgICAgICAvLyBtaW1pYyB0aGUgY29uc3RydWN0b3IncyBgcmV0dXJuYCBiZWhhdmlvclxuICAgICAgICAgIC8vIGh0dHA6Ly9lczUuZ2l0aHViLmNvbS8jeDEzLjIuMlxuICAgICAgICAgIHZhciByZXN1bHQgPSBmdW5jLmFwcGx5KHRoaXNCaW5kaW5nLCBhcmdzKTtcbiAgICAgICAgICByZXR1cm4gaXNPYmplY3QocmVzdWx0KSA/IHJlc3VsdCA6IHRoaXNCaW5kaW5nO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmdW5jLmFwcGx5KHRoaXNCaW5kaW5nLCBhcmdzKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBib3VuZDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGEgbmV3IG9iamVjdCB3aXRoIHRoZSBzcGVjaWZpZWQgYHByb3RvdHlwZWAuXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBwcm90b3R5cGUgVGhlIHByb3RvdHlwZSBvYmplY3QuXG4gICAgICogQHJldHVybnMge09iamVjdH0gUmV0dXJucyB0aGUgbmV3IG9iamVjdC5cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBjcmVhdGVPYmplY3QocHJvdG90eXBlKSB7XG4gICAgICByZXR1cm4gaXNPYmplY3QocHJvdG90eXBlKSA/IG5hdGl2ZUNyZWF0ZShwcm90b3R5cGUpIDoge307XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVXNlZCBieSBgZXNjYXBlYCB0byBjb252ZXJ0IGNoYXJhY3RlcnMgdG8gSFRNTCBlbnRpdGllcy5cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IG1hdGNoIFRoZSBtYXRjaGVkIGNoYXJhY3RlciB0byBlc2NhcGUuXG4gICAgICogQHJldHVybnMge1N0cmluZ30gUmV0dXJucyB0aGUgZXNjYXBlZCBjaGFyYWN0ZXIuXG4gICAgICovXG4gICAgZnVuY3Rpb24gZXNjYXBlSHRtbENoYXIobWF0Y2gpIHtcbiAgICAgIHJldHVybiBodG1sRXNjYXBlc1ttYXRjaF07XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0cyB0aGUgYXBwcm9wcmlhdGUgXCJpbmRleE9mXCIgZnVuY3Rpb24uIElmIHRoZSBgXy5pbmRleE9mYCBtZXRob2QgaXNcbiAgICAgKiBjdXN0b21pemVkLCB0aGlzIG1ldGhvZCByZXR1cm5zIHRoZSBjdXN0b20gbWV0aG9kLCBvdGhlcndpc2UgaXQgcmV0dXJuc1xuICAgICAqIHRoZSBgYmFzaWNJbmRleE9mYCBmdW5jdGlvbi5cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHJldHVybnMge0Z1bmN0aW9ufSBSZXR1cm5zIHRoZSBcImluZGV4T2ZcIiBmdW5jdGlvbi5cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBnZXRJbmRleE9mKGFycmF5LCB2YWx1ZSwgZnJvbUluZGV4KSB7XG4gICAgICB2YXIgcmVzdWx0ID0gKHJlc3VsdCA9IGxvZGFzaC5pbmRleE9mKSA9PT0gaW5kZXhPZiA/IGJhc2ljSW5kZXhPZiA6IHJlc3VsdDtcbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhIGZ1bmN0aW9uIHRoYXQganVnZ2xlcyBhcmd1bWVudHMsIGFsbG93aW5nIGFyZ3VtZW50IG92ZXJsb2FkaW5nXG4gICAgICogZm9yIGBfLmZsYXR0ZW5gIGFuZCBgXy51bmlxYCwgYmVmb3JlIHBhc3NpbmcgdGhlbSB0byB0aGUgZ2l2ZW4gYGZ1bmNgLlxuICAgICAqXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBmdW5jIFRoZSBmdW5jdGlvbiB0byB3cmFwLlxuICAgICAqIEByZXR1cm5zIHtGdW5jdGlvbn0gUmV0dXJucyB0aGUgbmV3IGZ1bmN0aW9uLlxuICAgICAqL1xuICAgIGZ1bmN0aW9uIG92ZXJsb2FkV3JhcHBlcihmdW5jKSB7XG4gICAgICByZXR1cm4gZnVuY3Rpb24oYXJyYXksIGZsYWcsIGNhbGxiYWNrLCB0aGlzQXJnKSB7XG4gICAgICAgIC8vIGp1Z2dsZSBhcmd1bWVudHNcbiAgICAgICAgaWYgKHR5cGVvZiBmbGFnICE9ICdib29sZWFuJyAmJiBmbGFnICE9IG51bGwpIHtcbiAgICAgICAgICB0aGlzQXJnID0gY2FsbGJhY2s7XG4gICAgICAgICAgY2FsbGJhY2sgPSAhKHRoaXNBcmcgJiYgdGhpc0FyZ1tmbGFnXSA9PT0gYXJyYXkpID8gZmxhZyA6IHVuZGVmaW5lZDtcbiAgICAgICAgICBmbGFnID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGNhbGxiYWNrICE9IG51bGwpIHtcbiAgICAgICAgICBjYWxsYmFjayA9IGxvZGFzaC5jcmVhdGVDYWxsYmFjayhjYWxsYmFjaywgdGhpc0FyZyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZ1bmMoYXJyYXksIGZsYWcsIGNhbGxiYWNrLCB0aGlzQXJnKTtcbiAgICAgIH07XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQSBmYWxsYmFjayBpbXBsZW1lbnRhdGlvbiBvZiBgaXNQbGFpbk9iamVjdGAgd2hpY2ggY2hlY2tzIGlmIGEgZ2l2ZW4gYHZhbHVlYFxuICAgICAqIGlzIGFuIG9iamVjdCBjcmVhdGVkIGJ5IHRoZSBgT2JqZWN0YCBjb25zdHJ1Y3RvciwgYXNzdW1pbmcgb2JqZWN0cyBjcmVhdGVkXG4gICAgICogYnkgdGhlIGBPYmplY3RgIGNvbnN0cnVjdG9yIGhhdmUgbm8gaW5oZXJpdGVkIGVudW1lcmFibGUgcHJvcGVydGllcyBhbmQgdGhhdFxuICAgICAqIHRoZXJlIGFyZSBubyBgT2JqZWN0LnByb3RvdHlwZWAgZXh0ZW5zaW9ucy5cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtNaXhlZH0gdmFsdWUgVGhlIHZhbHVlIHRvIGNoZWNrLlxuICAgICAqIEByZXR1cm5zIHtCb29sZWFufSBSZXR1cm5zIGB0cnVlYCwgaWYgYHZhbHVlYCBpcyBhIHBsYWluIG9iamVjdCwgZWxzZSBgZmFsc2VgLlxuICAgICAqL1xuICAgIGZ1bmN0aW9uIHNoaW1Jc1BsYWluT2JqZWN0KHZhbHVlKSB7XG4gICAgICB2YXIgY3RvcixcbiAgICAgICAgICByZXN1bHQ7XG5cbiAgICAgIC8vIGF2b2lkIG5vbiBPYmplY3Qgb2JqZWN0cywgYGFyZ3VtZW50c2Agb2JqZWN0cywgYW5kIERPTSBlbGVtZW50c1xuICAgICAgaWYgKCEodmFsdWUgJiYgdG9TdHJpbmcuY2FsbCh2YWx1ZSkgPT0gb2JqZWN0Q2xhc3MpIHx8XG4gICAgICAgICAgKGN0b3IgPSB2YWx1ZS5jb25zdHJ1Y3RvciwgaXNGdW5jdGlvbihjdG9yKSAmJiAhKGN0b3IgaW5zdGFuY2VvZiBjdG9yKSkpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuICAgICAgLy8gSW4gbW9zdCBlbnZpcm9ubWVudHMgYW4gb2JqZWN0J3Mgb3duIHByb3BlcnRpZXMgYXJlIGl0ZXJhdGVkIGJlZm9yZVxuICAgICAgLy8gaXRzIGluaGVyaXRlZCBwcm9wZXJ0aWVzLiBJZiB0aGUgbGFzdCBpdGVyYXRlZCBwcm9wZXJ0eSBpcyBhbiBvYmplY3Qnc1xuICAgICAgLy8gb3duIHByb3BlcnR5IHRoZW4gdGhlcmUgYXJlIG5vIGluaGVyaXRlZCBlbnVtZXJhYmxlIHByb3BlcnRpZXMuXG4gICAgICBmb3JJbih2YWx1ZSwgZnVuY3Rpb24odmFsdWUsIGtleSkge1xuICAgICAgICByZXN1bHQgPSBrZXk7XG4gICAgICB9KTtcbiAgICAgIHJldHVybiByZXN1bHQgPT09IHVuZGVmaW5lZCB8fCBoYXNPd25Qcm9wZXJ0eS5jYWxsKHZhbHVlLCByZXN1bHQpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFVzZWQgYnkgYHVuZXNjYXBlYCB0byBjb252ZXJ0IEhUTUwgZW50aXRpZXMgdG8gY2hhcmFjdGVycy5cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IG1hdGNoIFRoZSBtYXRjaGVkIGNoYXJhY3RlciB0byB1bmVzY2FwZS5cbiAgICAgKiBAcmV0dXJucyB7U3RyaW5nfSBSZXR1cm5zIHRoZSB1bmVzY2FwZWQgY2hhcmFjdGVyLlxuICAgICAqL1xuICAgIGZ1bmN0aW9uIHVuZXNjYXBlSHRtbENoYXIobWF0Y2gpIHtcbiAgICAgIHJldHVybiBodG1sVW5lc2NhcGVzW21hdGNoXTtcbiAgICB9XG5cbiAgICAvKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cblxuICAgIC8qKlxuICAgICAqIENoZWNrcyBpZiBgdmFsdWVgIGlzIGFuIGBhcmd1bWVudHNgIG9iamVjdC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBPYmplY3RzXG4gICAgICogQHBhcmFtIHtNaXhlZH0gdmFsdWUgVGhlIHZhbHVlIHRvIGNoZWNrLlxuICAgICAqIEByZXR1cm5zIHtCb29sZWFufSBSZXR1cm5zIGB0cnVlYCwgaWYgdGhlIGB2YWx1ZWAgaXMgYW4gYGFyZ3VtZW50c2Agb2JqZWN0LCBlbHNlIGBmYWxzZWAuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIChmdW5jdGlvbigpIHsgcmV0dXJuIF8uaXNBcmd1bWVudHMoYXJndW1lbnRzKTsgfSkoMSwgMiwgMyk7XG4gICAgICogLy8gPT4gdHJ1ZVxuICAgICAqXG4gICAgICogXy5pc0FyZ3VtZW50cyhbMSwgMiwgM10pO1xuICAgICAqIC8vID0+IGZhbHNlXG4gICAgICovXG4gICAgZnVuY3Rpb24gaXNBcmd1bWVudHModmFsdWUpIHtcbiAgICAgIHJldHVybiB0b1N0cmluZy5jYWxsKHZhbHVlKSA9PSBhcmdzQ2xhc3M7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2hlY2tzIGlmIGB2YWx1ZWAgaXMgYW4gYXJyYXkuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgT2JqZWN0c1xuICAgICAqIEBwYXJhbSB7TWl4ZWR9IHZhbHVlIFRoZSB2YWx1ZSB0byBjaGVjay5cbiAgICAgKiBAcmV0dXJucyB7Qm9vbGVhbn0gUmV0dXJucyBgdHJ1ZWAsIGlmIHRoZSBgdmFsdWVgIGlzIGFuIGFycmF5LCBlbHNlIGBmYWxzZWAuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIChmdW5jdGlvbigpIHsgcmV0dXJuIF8uaXNBcnJheShhcmd1bWVudHMpOyB9KSgpO1xuICAgICAqIC8vID0+IGZhbHNlXG4gICAgICpcbiAgICAgKiBfLmlzQXJyYXkoWzEsIDIsIDNdKTtcbiAgICAgKiAvLyA9PiB0cnVlXG4gICAgICovXG4gICAgdmFyIGlzQXJyYXkgPSBuYXRpdmVJc0FycmF5O1xuXG4gICAgLyoqXG4gICAgICogQSBmYWxsYmFjayBpbXBsZW1lbnRhdGlvbiBvZiBgT2JqZWN0LmtleXNgIHdoaWNoIHByb2R1Y2VzIGFuIGFycmF5IG9mIHRoZVxuICAgICAqIGdpdmVuIG9iamVjdCdzIG93biBlbnVtZXJhYmxlIHByb3BlcnR5IG5hbWVzLlxuICAgICAqXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAdHlwZSBGdW5jdGlvblxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3QgVGhlIG9iamVjdCB0byBpbnNwZWN0LlxuICAgICAqIEByZXR1cm5zIHtBcnJheX0gUmV0dXJucyBhIG5ldyBhcnJheSBvZiBwcm9wZXJ0eSBuYW1lcy5cbiAgICAgKi9cbiAgICB2YXIgc2hpbUtleXMgPSBmdW5jdGlvbiAob2JqZWN0KSB7XG4gICAgICB2YXIgaW5kZXgsIGl0ZXJhYmxlID0gb2JqZWN0LCByZXN1bHQgPSBbXTtcbiAgICAgIGlmICghaXRlcmFibGUpIHJldHVybiByZXN1bHQ7XG4gICAgICBpZiAoIShvYmplY3RUeXBlc1t0eXBlb2Ygb2JqZWN0XSkpIHJldHVybiByZXN1bHQ7ICAgIFxuICAgICAgICBmb3IgKGluZGV4IGluIGl0ZXJhYmxlKSB7XG4gICAgICAgICAgaWYgKGhhc093blByb3BlcnR5LmNhbGwoaXRlcmFibGUsIGluZGV4KSkge1xuICAgICAgICAgICAgcmVzdWx0LnB1c2goaW5kZXgpOyAgICBcbiAgICAgICAgICB9XG4gICAgICAgIH0gICAgXG4gICAgICByZXR1cm4gcmVzdWx0XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYW4gYXJyYXkgY29tcG9zZWQgb2YgdGhlIG93biBlbnVtZXJhYmxlIHByb3BlcnR5IG5hbWVzIG9mIGBvYmplY3RgLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IE9iamVjdHNcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0IFRoZSBvYmplY3QgdG8gaW5zcGVjdC5cbiAgICAgKiBAcmV0dXJucyB7QXJyYXl9IFJldHVybnMgYSBuZXcgYXJyYXkgb2YgcHJvcGVydHkgbmFtZXMuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8ua2V5cyh7ICdvbmUnOiAxLCAndHdvJzogMiwgJ3RocmVlJzogMyB9KTtcbiAgICAgKiAvLyA9PiBbJ29uZScsICd0d28nLCAndGhyZWUnXSAob3JkZXIgaXMgbm90IGd1YXJhbnRlZWQpXG4gICAgICovXG4gICAgdmFyIGtleXMgPSAhbmF0aXZlS2V5cyA/IHNoaW1LZXlzIDogZnVuY3Rpb24ob2JqZWN0KSB7XG4gICAgICBpZiAoIWlzT2JqZWN0KG9iamVjdCkpIHtcbiAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgfVxuICAgICAgcmV0dXJuIG5hdGl2ZUtleXMob2JqZWN0KTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogVXNlZCB0byBjb252ZXJ0IGNoYXJhY3RlcnMgdG8gSFRNTCBlbnRpdGllczpcbiAgICAgKlxuICAgICAqIFRob3VnaCB0aGUgYD5gIGNoYXJhY3RlciBpcyBlc2NhcGVkIGZvciBzeW1tZXRyeSwgY2hhcmFjdGVycyBsaWtlIGA+YCBhbmQgYC9gXG4gICAgICogZG9uJ3QgcmVxdWlyZSBlc2NhcGluZyBpbiBIVE1MIGFuZCBoYXZlIG5vIHNwZWNpYWwgbWVhbmluZyB1bmxlc3MgdGhleSdyZSBwYXJ0XG4gICAgICogb2YgYSB0YWcgb3IgYW4gdW5xdW90ZWQgYXR0cmlidXRlIHZhbHVlLlxuICAgICAqIGh0dHA6Ly9tYXRoaWFzYnluZW5zLmJlL25vdGVzL2FtYmlndW91cy1hbXBlcnNhbmRzICh1bmRlciBcInNlbWktcmVsYXRlZCBmdW4gZmFjdFwiKVxuICAgICAqL1xuICAgIHZhciBodG1sRXNjYXBlcyA9IHtcbiAgICAgICcmJzogJyZhbXA7JyxcbiAgICAgICc8JzogJyZsdDsnLFxuICAgICAgJz4nOiAnJmd0OycsXG4gICAgICAnXCInOiAnJnF1b3Q7JyxcbiAgICAgIFwiJ1wiOiAnJiMzOTsnXG4gICAgfTtcblxuICAgIC8qKiBVc2VkIHRvIGNvbnZlcnQgSFRNTCBlbnRpdGllcyB0byBjaGFyYWN0ZXJzICovXG4gICAgdmFyIGh0bWxVbmVzY2FwZXMgPSBpbnZlcnQoaHRtbEVzY2FwZXMpO1xuXG4gICAgLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5cbiAgICAvKipcbiAgICAgKiBBc3NpZ25zIG93biBlbnVtZXJhYmxlIHByb3BlcnRpZXMgb2Ygc291cmNlIG9iamVjdChzKSB0byB0aGUgZGVzdGluYXRpb25cbiAgICAgKiBvYmplY3QuIFN1YnNlcXVlbnQgc291cmNlcyB3aWxsIG92ZXJ3cml0ZSBwcm9wZXJ0eSBhc3NpZ25tZW50cyBvZiBwcmV2aW91c1xuICAgICAqIHNvdXJjZXMuIElmIGEgYGNhbGxiYWNrYCBmdW5jdGlvbiBpcyBwYXNzZWQsIGl0IHdpbGwgYmUgZXhlY3V0ZWQgdG8gcHJvZHVjZVxuICAgICAqIHRoZSBhc3NpZ25lZCB2YWx1ZXMuIFRoZSBgY2FsbGJhY2tgIGlzIGJvdW5kIHRvIGB0aGlzQXJnYCBhbmQgaW52b2tlZCB3aXRoXG4gICAgICogdHdvIGFyZ3VtZW50czsgKG9iamVjdFZhbHVlLCBzb3VyY2VWYWx1ZSkuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAdHlwZSBGdW5jdGlvblxuICAgICAqIEBhbGlhcyBleHRlbmRcbiAgICAgKiBAY2F0ZWdvcnkgT2JqZWN0c1xuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3QgVGhlIGRlc3RpbmF0aW9uIG9iamVjdC5cbiAgICAgKiBAcGFyYW0ge09iamVjdH0gW3NvdXJjZTEsIHNvdXJjZTIsIC4uLl0gVGhlIHNvdXJjZSBvYmplY3RzLlxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb259IFtjYWxsYmFja10gVGhlIGZ1bmN0aW9uIHRvIGN1c3RvbWl6ZSBhc3NpZ25pbmcgdmFsdWVzLlxuICAgICAqIEBwYXJhbSB7TWl4ZWR9IFt0aGlzQXJnXSBUaGUgYHRoaXNgIGJpbmRpbmcgb2YgYGNhbGxiYWNrYC5cbiAgICAgKiBAcmV0dXJucyB7T2JqZWN0fSBSZXR1cm5zIHRoZSBkZXN0aW5hdGlvbiBvYmplY3QuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8uYXNzaWduKHsgJ25hbWUnOiAnbW9lJyB9LCB7ICdhZ2UnOiA0MCB9KTtcbiAgICAgKiAvLyA9PiB7ICduYW1lJzogJ21vZScsICdhZ2UnOiA0MCB9XG4gICAgICpcbiAgICAgKiB2YXIgZGVmYXVsdHMgPSBfLnBhcnRpYWxSaWdodChfLmFzc2lnbiwgZnVuY3Rpb24oYSwgYikge1xuICAgICAqICAgcmV0dXJuIHR5cGVvZiBhID09ICd1bmRlZmluZWQnID8gYiA6IGE7XG4gICAgICogfSk7XG4gICAgICpcbiAgICAgKiB2YXIgZm9vZCA9IHsgJ25hbWUnOiAnYXBwbGUnIH07XG4gICAgICogZGVmYXVsdHMoZm9vZCwgeyAnbmFtZSc6ICdiYW5hbmEnLCAndHlwZSc6ICdmcnVpdCcgfSk7XG4gICAgICogLy8gPT4geyAnbmFtZSc6ICdhcHBsZScsICd0eXBlJzogJ2ZydWl0JyB9XG4gICAgICovXG4gICAgdmFyIGFzc2lnbiA9IGZ1bmN0aW9uIChvYmplY3QsIHNvdXJjZSwgZ3VhcmQpIHtcbiAgICAgIHZhciBpbmRleCwgaXRlcmFibGUgPSBvYmplY3QsIHJlc3VsdCA9IGl0ZXJhYmxlO1xuICAgICAgaWYgKCFpdGVyYWJsZSkgcmV0dXJuIHJlc3VsdDtcbiAgICAgIHZhciBhcmdzID0gYXJndW1lbnRzLFxuICAgICAgICAgIGFyZ3NJbmRleCA9IDAsXG4gICAgICAgICAgYXJnc0xlbmd0aCA9IHR5cGVvZiBndWFyZCA9PSAnbnVtYmVyJyA/IDIgOiBhcmdzLmxlbmd0aDtcbiAgICAgIGlmIChhcmdzTGVuZ3RoID4gMyAmJiB0eXBlb2YgYXJnc1thcmdzTGVuZ3RoIC0gMl0gPT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICB2YXIgY2FsbGJhY2sgPSBsb2Rhc2guY3JlYXRlQ2FsbGJhY2soYXJnc1stLWFyZ3NMZW5ndGggLSAxXSwgYXJnc1thcmdzTGVuZ3RoLS1dLCAyKTtcbiAgICAgIH0gZWxzZSBpZiAoYXJnc0xlbmd0aCA+IDIgJiYgdHlwZW9mIGFyZ3NbYXJnc0xlbmd0aCAtIDFdID09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgY2FsbGJhY2sgPSBhcmdzWy0tYXJnc0xlbmd0aF07XG4gICAgICB9XG4gICAgICB3aGlsZSAoKythcmdzSW5kZXggPCBhcmdzTGVuZ3RoKSB7XG4gICAgICAgIGl0ZXJhYmxlID0gYXJnc1thcmdzSW5kZXhdO1xuICAgICAgICBpZiAoaXRlcmFibGUgJiYgb2JqZWN0VHlwZXNbdHlwZW9mIGl0ZXJhYmxlXSkgeyAgICBcbiAgICAgICAgdmFyIG93bkluZGV4ID0gLTEsXG4gICAgICAgICAgICBvd25Qcm9wcyA9IG9iamVjdFR5cGVzW3R5cGVvZiBpdGVyYWJsZV0gJiYga2V5cyhpdGVyYWJsZSksXG4gICAgICAgICAgICBsZW5ndGggPSBvd25Qcm9wcyA/IG93blByb3BzLmxlbmd0aCA6IDA7XG5cbiAgICAgICAgd2hpbGUgKCsrb3duSW5kZXggPCBsZW5ndGgpIHtcbiAgICAgICAgICBpbmRleCA9IG93blByb3BzW293bkluZGV4XTtcbiAgICAgICAgICByZXN1bHRbaW5kZXhdID0gY2FsbGJhY2sgPyBjYWxsYmFjayhyZXN1bHRbaW5kZXhdLCBpdGVyYWJsZVtpbmRleF0pIDogaXRlcmFibGVbaW5kZXhdOyAgICBcbiAgICAgICAgfSAgICBcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgcmV0dXJuIHJlc3VsdFxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGEgY2xvbmUgb2YgYHZhbHVlYC4gSWYgYGRlZXBgIGlzIGB0cnVlYCwgbmVzdGVkIG9iamVjdHMgd2lsbCBhbHNvXG4gICAgICogYmUgY2xvbmVkLCBvdGhlcndpc2UgdGhleSB3aWxsIGJlIGFzc2lnbmVkIGJ5IHJlZmVyZW5jZS4gSWYgYSBgY2FsbGJhY2tgXG4gICAgICogZnVuY3Rpb24gaXMgcGFzc2VkLCBpdCB3aWxsIGJlIGV4ZWN1dGVkIHRvIHByb2R1Y2UgdGhlIGNsb25lZCB2YWx1ZXMuIElmXG4gICAgICogYGNhbGxiYWNrYCByZXR1cm5zIGB1bmRlZmluZWRgLCBjbG9uaW5nIHdpbGwgYmUgaGFuZGxlZCBieSB0aGUgbWV0aG9kIGluc3RlYWQuXG4gICAgICogVGhlIGBjYWxsYmFja2AgaXMgYm91bmQgdG8gYHRoaXNBcmdgIGFuZCBpbnZva2VkIHdpdGggb25lIGFyZ3VtZW50OyAodmFsdWUpLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IE9iamVjdHNcbiAgICAgKiBAcGFyYW0ge01peGVkfSB2YWx1ZSBUaGUgdmFsdWUgdG8gY2xvbmUuXG4gICAgICogQHBhcmFtIHtCb29sZWFufSBbZGVlcD1mYWxzZV0gQSBmbGFnIHRvIGluZGljYXRlIGEgZGVlcCBjbG9uZS5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBbY2FsbGJhY2tdIFRoZSBmdW5jdGlvbiB0byBjdXN0b21pemUgY2xvbmluZyB2YWx1ZXMuXG4gICAgICogQHBhcmFtIHtNaXhlZH0gW3RoaXNBcmddIFRoZSBgdGhpc2AgYmluZGluZyBvZiBgY2FsbGJhY2tgLlxuICAgICAqIEBwYXJhbS0ge0FycmF5fSBbc3RhY2tBPVtdXSBUcmFja3MgdHJhdmVyc2VkIHNvdXJjZSBvYmplY3RzLlxuICAgICAqIEBwYXJhbS0ge0FycmF5fSBbc3RhY2tCPVtdXSBBc3NvY2lhdGVzIGNsb25lcyB3aXRoIHNvdXJjZSBjb3VudGVycGFydHMuXG4gICAgICogQHJldHVybnMge01peGVkfSBSZXR1cm5zIHRoZSBjbG9uZWQgYHZhbHVlYC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogdmFyIHN0b29nZXMgPSBbXG4gICAgICogICB7ICduYW1lJzogJ21vZScsICdhZ2UnOiA0MCB9LFxuICAgICAqICAgeyAnbmFtZSc6ICdsYXJyeScsICdhZ2UnOiA1MCB9XG4gICAgICogXTtcbiAgICAgKlxuICAgICAqIHZhciBzaGFsbG93ID0gXy5jbG9uZShzdG9vZ2VzKTtcbiAgICAgKiBzaGFsbG93WzBdID09PSBzdG9vZ2VzWzBdO1xuICAgICAqIC8vID0+IHRydWVcbiAgICAgKlxuICAgICAqIHZhciBkZWVwID0gXy5jbG9uZShzdG9vZ2VzLCB0cnVlKTtcbiAgICAgKiBkZWVwWzBdID09PSBzdG9vZ2VzWzBdO1xuICAgICAqIC8vID0+IGZhbHNlXG4gICAgICpcbiAgICAgKiBfLm1peGluKHtcbiAgICAgKiAgICdjbG9uZSc6IF8ucGFydGlhbFJpZ2h0KF8uY2xvbmUsIGZ1bmN0aW9uKHZhbHVlKSB7XG4gICAgICogICAgIHJldHVybiBfLmlzRWxlbWVudCh2YWx1ZSkgPyB2YWx1ZS5jbG9uZU5vZGUoZmFsc2UpIDogdW5kZWZpbmVkO1xuICAgICAqICAgfSlcbiAgICAgKiB9KTtcbiAgICAgKlxuICAgICAqIHZhciBjbG9uZSA9IF8uY2xvbmUoZG9jdW1lbnQuYm9keSk7XG4gICAgICogY2xvbmUuY2hpbGROb2Rlcy5sZW5ndGg7XG4gICAgICogLy8gPT4gMFxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGNsb25lKHZhbHVlLCBkZWVwLCBjYWxsYmFjaywgdGhpc0FyZywgc3RhY2tBLCBzdGFja0IpIHtcbiAgICAgIHZhciByZXN1bHQgPSB2YWx1ZTtcblxuICAgICAgLy8gYWxsb3dzIHdvcmtpbmcgd2l0aCBcIkNvbGxlY3Rpb25zXCIgbWV0aG9kcyB3aXRob3V0IHVzaW5nIHRoZWlyIGBjYWxsYmFja2BcbiAgICAgIC8vIGFyZ3VtZW50LCBgaW5kZXh8a2V5YCwgZm9yIHRoaXMgbWV0aG9kJ3MgYGNhbGxiYWNrYFxuICAgICAgaWYgKHR5cGVvZiBkZWVwICE9ICdib29sZWFuJyAmJiBkZWVwICE9IG51bGwpIHtcbiAgICAgICAgdGhpc0FyZyA9IGNhbGxiYWNrO1xuICAgICAgICBjYWxsYmFjayA9IGRlZXA7XG4gICAgICAgIGRlZXAgPSBmYWxzZTtcbiAgICAgIH1cbiAgICAgIGlmICh0eXBlb2YgY2FsbGJhY2sgPT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICBjYWxsYmFjayA9ICh0eXBlb2YgdGhpc0FyZyA9PSAndW5kZWZpbmVkJylcbiAgICAgICAgICA/IGNhbGxiYWNrXG4gICAgICAgICAgOiBsb2Rhc2guY3JlYXRlQ2FsbGJhY2soY2FsbGJhY2ssIHRoaXNBcmcsIDEpO1xuXG4gICAgICAgIHJlc3VsdCA9IGNhbGxiYWNrKHJlc3VsdCk7XG4gICAgICAgIGlmICh0eXBlb2YgcmVzdWx0ICE9ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfVxuICAgICAgICByZXN1bHQgPSB2YWx1ZTtcbiAgICAgIH1cbiAgICAgIC8vIGluc3BlY3QgW1tDbGFzc11dXG4gICAgICB2YXIgaXNPYmogPSBpc09iamVjdChyZXN1bHQpO1xuICAgICAgaWYgKGlzT2JqKSB7XG4gICAgICAgIHZhciBjbGFzc05hbWUgPSB0b1N0cmluZy5jYWxsKHJlc3VsdCk7XG4gICAgICAgIGlmICghY2xvbmVhYmxlQ2xhc3Nlc1tjbGFzc05hbWVdKSB7XG4gICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfVxuICAgICAgICB2YXIgaXNBcnIgPSBpc0FycmF5KHJlc3VsdCk7XG4gICAgICB9XG4gICAgICAvLyBzaGFsbG93IGNsb25lXG4gICAgICBpZiAoIWlzT2JqIHx8ICFkZWVwKSB7XG4gICAgICAgIHJldHVybiBpc09ialxuICAgICAgICAgID8gKGlzQXJyID8gc2xpY2UocmVzdWx0KSA6IGFzc2lnbih7fSwgcmVzdWx0KSlcbiAgICAgICAgICA6IHJlc3VsdDtcbiAgICAgIH1cbiAgICAgIHZhciBjdG9yID0gY3RvckJ5Q2xhc3NbY2xhc3NOYW1lXTtcbiAgICAgIHN3aXRjaCAoY2xhc3NOYW1lKSB7XG4gICAgICAgIGNhc2UgYm9vbENsYXNzOlxuICAgICAgICBjYXNlIGRhdGVDbGFzczpcbiAgICAgICAgICByZXR1cm4gbmV3IGN0b3IoK3Jlc3VsdCk7XG5cbiAgICAgICAgY2FzZSBudW1iZXJDbGFzczpcbiAgICAgICAgY2FzZSBzdHJpbmdDbGFzczpcbiAgICAgICAgICByZXR1cm4gbmV3IGN0b3IocmVzdWx0KTtcblxuICAgICAgICBjYXNlIHJlZ2V4cENsYXNzOlxuICAgICAgICAgIHJldHVybiBjdG9yKHJlc3VsdC5zb3VyY2UsIHJlRmxhZ3MuZXhlYyhyZXN1bHQpKTtcbiAgICAgIH1cbiAgICAgIC8vIGNoZWNrIGZvciBjaXJjdWxhciByZWZlcmVuY2VzIGFuZCByZXR1cm4gY29ycmVzcG9uZGluZyBjbG9uZVxuICAgICAgdmFyIGluaXRlZFN0YWNrID0gIXN0YWNrQTtcbiAgICAgIHN0YWNrQSB8fCAoc3RhY2tBID0gZ2V0QXJyYXkoKSk7XG4gICAgICBzdGFja0IgfHwgKHN0YWNrQiA9IGdldEFycmF5KCkpO1xuXG4gICAgICB2YXIgbGVuZ3RoID0gc3RhY2tBLmxlbmd0aDtcbiAgICAgIHdoaWxlIChsZW5ndGgtLSkge1xuICAgICAgICBpZiAoc3RhY2tBW2xlbmd0aF0gPT0gdmFsdWUpIHtcbiAgICAgICAgICByZXR1cm4gc3RhY2tCW2xlbmd0aF07XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIC8vIGluaXQgY2xvbmVkIG9iamVjdFxuICAgICAgcmVzdWx0ID0gaXNBcnIgPyBjdG9yKHJlc3VsdC5sZW5ndGgpIDoge307XG5cbiAgICAgIC8vIGFkZCBhcnJheSBwcm9wZXJ0aWVzIGFzc2lnbmVkIGJ5IGBSZWdFeHAjZXhlY2BcbiAgICAgIGlmIChpc0Fycikge1xuICAgICAgICBpZiAoaGFzT3duUHJvcGVydHkuY2FsbCh2YWx1ZSwgJ2luZGV4JykpIHtcbiAgICAgICAgICByZXN1bHQuaW5kZXggPSB2YWx1ZS5pbmRleDtcbiAgICAgICAgfVxuICAgICAgICBpZiAoaGFzT3duUHJvcGVydHkuY2FsbCh2YWx1ZSwgJ2lucHV0JykpIHtcbiAgICAgICAgICByZXN1bHQuaW5wdXQgPSB2YWx1ZS5pbnB1dDtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgLy8gYWRkIHRoZSBzb3VyY2UgdmFsdWUgdG8gdGhlIHN0YWNrIG9mIHRyYXZlcnNlZCBvYmplY3RzXG4gICAgICAvLyBhbmQgYXNzb2NpYXRlIGl0IHdpdGggaXRzIGNsb25lXG4gICAgICBzdGFja0EucHVzaCh2YWx1ZSk7XG4gICAgICBzdGFja0IucHVzaChyZXN1bHQpO1xuXG4gICAgICAvLyByZWN1cnNpdmVseSBwb3B1bGF0ZSBjbG9uZSAoc3VzY2VwdGlibGUgdG8gY2FsbCBzdGFjayBsaW1pdHMpXG4gICAgICAoaXNBcnIgPyBmb3JFYWNoIDogZm9yT3duKSh2YWx1ZSwgZnVuY3Rpb24ob2JqVmFsdWUsIGtleSkge1xuICAgICAgICByZXN1bHRba2V5XSA9IGNsb25lKG9ialZhbHVlLCBkZWVwLCBjYWxsYmFjaywgdW5kZWZpbmVkLCBzdGFja0EsIHN0YWNrQik7XG4gICAgICB9KTtcblxuICAgICAgaWYgKGluaXRlZFN0YWNrKSB7XG4gICAgICAgIHJlbGVhc2VBcnJheShzdGFja0EpO1xuICAgICAgICByZWxlYXNlQXJyYXkoc3RhY2tCKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhIGRlZXAgY2xvbmUgb2YgYHZhbHVlYC4gSWYgYSBgY2FsbGJhY2tgIGZ1bmN0aW9uIGlzIHBhc3NlZCxcbiAgICAgKiBpdCB3aWxsIGJlIGV4ZWN1dGVkIHRvIHByb2R1Y2UgdGhlIGNsb25lZCB2YWx1ZXMuIElmIGBjYWxsYmFja2AgcmV0dXJuc1xuICAgICAqIGB1bmRlZmluZWRgLCBjbG9uaW5nIHdpbGwgYmUgaGFuZGxlZCBieSB0aGUgbWV0aG9kIGluc3RlYWQuIFRoZSBgY2FsbGJhY2tgXG4gICAgICogaXMgYm91bmQgdG8gYHRoaXNBcmdgIGFuZCBpbnZva2VkIHdpdGggb25lIGFyZ3VtZW50OyAodmFsdWUpLlxuICAgICAqXG4gICAgICogTm90ZTogVGhpcyBtZXRob2QgaXMgbG9vc2VseSBiYXNlZCBvbiB0aGUgc3RydWN0dXJlZCBjbG9uZSBhbGdvcml0aG0uIEZ1bmN0aW9uc1xuICAgICAqIGFuZCBET00gbm9kZXMgYXJlICoqbm90KiogY2xvbmVkLiBUaGUgZW51bWVyYWJsZSBwcm9wZXJ0aWVzIG9mIGBhcmd1bWVudHNgIG9iamVjdHMgYW5kXG4gICAgICogb2JqZWN0cyBjcmVhdGVkIGJ5IGNvbnN0cnVjdG9ycyBvdGhlciB0aGFuIGBPYmplY3RgIGFyZSBjbG9uZWQgdG8gcGxhaW4gYE9iamVjdGAgb2JqZWN0cy5cbiAgICAgKiBTZWUgaHR0cDovL3d3dy53My5vcmcvVFIvaHRtbDUvaW5mcmFzdHJ1Y3R1cmUuaHRtbCNpbnRlcm5hbC1zdHJ1Y3R1cmVkLWNsb25pbmctYWxnb3JpdGhtLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IE9iamVjdHNcbiAgICAgKiBAcGFyYW0ge01peGVkfSB2YWx1ZSBUaGUgdmFsdWUgdG8gZGVlcCBjbG9uZS5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBbY2FsbGJhY2tdIFRoZSBmdW5jdGlvbiB0byBjdXN0b21pemUgY2xvbmluZyB2YWx1ZXMuXG4gICAgICogQHBhcmFtIHtNaXhlZH0gW3RoaXNBcmddIFRoZSBgdGhpc2AgYmluZGluZyBvZiBgY2FsbGJhY2tgLlxuICAgICAqIEByZXR1cm5zIHtNaXhlZH0gUmV0dXJucyB0aGUgZGVlcCBjbG9uZWQgYHZhbHVlYC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogdmFyIHN0b29nZXMgPSBbXG4gICAgICogICB7ICduYW1lJzogJ21vZScsICdhZ2UnOiA0MCB9LFxuICAgICAqICAgeyAnbmFtZSc6ICdsYXJyeScsICdhZ2UnOiA1MCB9XG4gICAgICogXTtcbiAgICAgKlxuICAgICAqIHZhciBkZWVwID0gXy5jbG9uZURlZXAoc3Rvb2dlcyk7XG4gICAgICogZGVlcFswXSA9PT0gc3Rvb2dlc1swXTtcbiAgICAgKiAvLyA9PiBmYWxzZVxuICAgICAqXG4gICAgICogdmFyIHZpZXcgPSB7XG4gICAgICogICAnbGFiZWwnOiAnZG9jcycsXG4gICAgICogICAnbm9kZSc6IGVsZW1lbnRcbiAgICAgKiB9O1xuICAgICAqXG4gICAgICogdmFyIGNsb25lID0gXy5jbG9uZURlZXAodmlldywgZnVuY3Rpb24odmFsdWUpIHtcbiAgICAgKiAgIHJldHVybiBfLmlzRWxlbWVudCh2YWx1ZSkgPyB2YWx1ZS5jbG9uZU5vZGUodHJ1ZSkgOiB1bmRlZmluZWQ7XG4gICAgICogfSk7XG4gICAgICpcbiAgICAgKiBjbG9uZS5ub2RlID09IHZpZXcubm9kZTtcbiAgICAgKiAvLyA9PiBmYWxzZVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGNsb25lRGVlcCh2YWx1ZSwgY2FsbGJhY2ssIHRoaXNBcmcpIHtcbiAgICAgIHJldHVybiBjbG9uZSh2YWx1ZSwgdHJ1ZSwgY2FsbGJhY2ssIHRoaXNBcmcpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEFzc2lnbnMgb3duIGVudW1lcmFibGUgcHJvcGVydGllcyBvZiBzb3VyY2Ugb2JqZWN0KHMpIHRvIHRoZSBkZXN0aW5hdGlvblxuICAgICAqIG9iamVjdCBmb3IgYWxsIGRlc3RpbmF0aW9uIHByb3BlcnRpZXMgdGhhdCByZXNvbHZlIHRvIGB1bmRlZmluZWRgLiBPbmNlIGFcbiAgICAgKiBwcm9wZXJ0eSBpcyBzZXQsIGFkZGl0aW9uYWwgZGVmYXVsdHMgb2YgdGhlIHNhbWUgcHJvcGVydHkgd2lsbCBiZSBpZ25vcmVkLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQHR5cGUgRnVuY3Rpb25cbiAgICAgKiBAY2F0ZWdvcnkgT2JqZWN0c1xuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3QgVGhlIGRlc3RpbmF0aW9uIG9iamVjdC5cbiAgICAgKiBAcGFyYW0ge09iamVjdH0gW3NvdXJjZTEsIHNvdXJjZTIsIC4uLl0gVGhlIHNvdXJjZSBvYmplY3RzLlxuICAgICAqIEBwYXJhbS0ge09iamVjdH0gW2d1YXJkXSBBbGxvd3Mgd29ya2luZyB3aXRoIGBfLnJlZHVjZWAgd2l0aG91dCB1c2luZyBpdHNcbiAgICAgKiAgY2FsbGJhY2sncyBga2V5YCBhbmQgYG9iamVjdGAgYXJndW1lbnRzIGFzIHNvdXJjZXMuXG4gICAgICogQHJldHVybnMge09iamVjdH0gUmV0dXJucyB0aGUgZGVzdGluYXRpb24gb2JqZWN0LlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiB2YXIgZm9vZCA9IHsgJ25hbWUnOiAnYXBwbGUnIH07XG4gICAgICogXy5kZWZhdWx0cyhmb29kLCB7ICduYW1lJzogJ2JhbmFuYScsICd0eXBlJzogJ2ZydWl0JyB9KTtcbiAgICAgKiAvLyA9PiB7ICduYW1lJzogJ2FwcGxlJywgJ3R5cGUnOiAnZnJ1aXQnIH1cbiAgICAgKi9cbiAgICB2YXIgZGVmYXVsdHMgPSBmdW5jdGlvbiAob2JqZWN0LCBzb3VyY2UsIGd1YXJkKSB7XG4gICAgICB2YXIgaW5kZXgsIGl0ZXJhYmxlID0gb2JqZWN0LCByZXN1bHQgPSBpdGVyYWJsZTtcbiAgICAgIGlmICghaXRlcmFibGUpIHJldHVybiByZXN1bHQ7XG4gICAgICB2YXIgYXJncyA9IGFyZ3VtZW50cyxcbiAgICAgICAgICBhcmdzSW5kZXggPSAwLFxuICAgICAgICAgIGFyZ3NMZW5ndGggPSB0eXBlb2YgZ3VhcmQgPT0gJ251bWJlcicgPyAyIDogYXJncy5sZW5ndGg7XG4gICAgICB3aGlsZSAoKythcmdzSW5kZXggPCBhcmdzTGVuZ3RoKSB7XG4gICAgICAgIGl0ZXJhYmxlID0gYXJnc1thcmdzSW5kZXhdO1xuICAgICAgICBpZiAoaXRlcmFibGUgJiYgb2JqZWN0VHlwZXNbdHlwZW9mIGl0ZXJhYmxlXSkgeyAgICBcbiAgICAgICAgdmFyIG93bkluZGV4ID0gLTEsXG4gICAgICAgICAgICBvd25Qcm9wcyA9IG9iamVjdFR5cGVzW3R5cGVvZiBpdGVyYWJsZV0gJiYga2V5cyhpdGVyYWJsZSksXG4gICAgICAgICAgICBsZW5ndGggPSBvd25Qcm9wcyA/IG93blByb3BzLmxlbmd0aCA6IDA7XG5cbiAgICAgICAgd2hpbGUgKCsrb3duSW5kZXggPCBsZW5ndGgpIHtcbiAgICAgICAgICBpbmRleCA9IG93blByb3BzW293bkluZGV4XTtcbiAgICAgICAgICBpZiAodHlwZW9mIHJlc3VsdFtpbmRleF0gPT0gJ3VuZGVmaW5lZCcpIHJlc3VsdFtpbmRleF0gPSBpdGVyYWJsZVtpbmRleF07ICAgIFxuICAgICAgICB9ICAgIFxuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gcmVzdWx0XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFRoaXMgbWV0aG9kIGlzIHNpbWlsYXIgdG8gYF8uZmluZGAsIGV4Y2VwdCB0aGF0IGl0IHJldHVybnMgdGhlIGtleSBvZiB0aGVcbiAgICAgKiBlbGVtZW50IHRoYXQgcGFzc2VzIHRoZSBjYWxsYmFjayBjaGVjaywgaW5zdGVhZCBvZiB0aGUgZWxlbWVudCBpdHNlbGYuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgT2JqZWN0c1xuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3QgVGhlIG9iamVjdCB0byBzZWFyY2guXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbnxPYmplY3R8U3RyaW5nfSBbY2FsbGJhY2s9aWRlbnRpdHldIFRoZSBmdW5jdGlvbiBjYWxsZWQgcGVyXG4gICAgICogIGl0ZXJhdGlvbi4gSWYgYSBwcm9wZXJ0eSBuYW1lIG9yIG9iamVjdCBpcyBwYXNzZWQsIGl0IHdpbGwgYmUgdXNlZCB0byBjcmVhdGVcbiAgICAgKiAgYSBcIl8ucGx1Y2tcIiBvciBcIl8ud2hlcmVcIiBzdHlsZSBjYWxsYmFjaywgcmVzcGVjdGl2ZWx5LlxuICAgICAqIEBwYXJhbSB7TWl4ZWR9IFt0aGlzQXJnXSBUaGUgYHRoaXNgIGJpbmRpbmcgb2YgYGNhbGxiYWNrYC5cbiAgICAgKiBAcmV0dXJucyB7TWl4ZWR9IFJldHVybnMgdGhlIGtleSBvZiB0aGUgZm91bmQgZWxlbWVudCwgZWxzZSBgdW5kZWZpbmVkYC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5maW5kS2V5KHsgJ2EnOiAxLCAnYic6IDIsICdjJzogMywgJ2QnOiA0IH0sIGZ1bmN0aW9uKG51bSkge1xuICAgICAqICAgcmV0dXJuIG51bSAlIDIgPT0gMDtcbiAgICAgKiB9KTtcbiAgICAgKiAvLyA9PiAnYidcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBmaW5kS2V5KG9iamVjdCwgY2FsbGJhY2ssIHRoaXNBcmcpIHtcbiAgICAgIHZhciByZXN1bHQ7XG4gICAgICBjYWxsYmFjayA9IGxvZGFzaC5jcmVhdGVDYWxsYmFjayhjYWxsYmFjaywgdGhpc0FyZyk7XG4gICAgICBmb3JPd24ob2JqZWN0LCBmdW5jdGlvbih2YWx1ZSwga2V5LCBvYmplY3QpIHtcbiAgICAgICAgaWYgKGNhbGxiYWNrKHZhbHVlLCBrZXksIG9iamVjdCkpIHtcbiAgICAgICAgICByZXN1bHQgPSBrZXk7XG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSXRlcmF0ZXMgb3ZlciBgb2JqZWN0YCdzIG93biBhbmQgaW5oZXJpdGVkIGVudW1lcmFibGUgcHJvcGVydGllcywgZXhlY3V0aW5nXG4gICAgICogdGhlIGBjYWxsYmFja2AgZm9yIGVhY2ggcHJvcGVydHkuIFRoZSBgY2FsbGJhY2tgIGlzIGJvdW5kIHRvIGB0aGlzQXJnYCBhbmRcbiAgICAgKiBpbnZva2VkIHdpdGggdGhyZWUgYXJndW1lbnRzOyAodmFsdWUsIGtleSwgb2JqZWN0KS4gQ2FsbGJhY2tzIG1heSBleGl0IGl0ZXJhdGlvblxuICAgICAqIGVhcmx5IGJ5IGV4cGxpY2l0bHkgcmV0dXJuaW5nIGBmYWxzZWAuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAdHlwZSBGdW5jdGlvblxuICAgICAqIEBjYXRlZ29yeSBPYmplY3RzXG4gICAgICogQHBhcmFtIHtPYmplY3R9IG9iamVjdCBUaGUgb2JqZWN0IHRvIGl0ZXJhdGUgb3Zlci5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBbY2FsbGJhY2s9aWRlbnRpdHldIFRoZSBmdW5jdGlvbiBjYWxsZWQgcGVyIGl0ZXJhdGlvbi5cbiAgICAgKiBAcGFyYW0ge01peGVkfSBbdGhpc0FyZ10gVGhlIGB0aGlzYCBiaW5kaW5nIG9mIGBjYWxsYmFja2AuXG4gICAgICogQHJldHVybnMge09iamVjdH0gUmV0dXJucyBgb2JqZWN0YC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogZnVuY3Rpb24gRG9nKG5hbWUpIHtcbiAgICAgKiAgIHRoaXMubmFtZSA9IG5hbWU7XG4gICAgICogfVxuICAgICAqXG4gICAgICogRG9nLnByb3RvdHlwZS5iYXJrID0gZnVuY3Rpb24oKSB7XG4gICAgICogICBhbGVydCgnV29vZiwgd29vZiEnKTtcbiAgICAgKiB9O1xuICAgICAqXG4gICAgICogXy5mb3JJbihuZXcgRG9nKCdEYWdueScpLCBmdW5jdGlvbih2YWx1ZSwga2V5KSB7XG4gICAgICogICBhbGVydChrZXkpO1xuICAgICAqIH0pO1xuICAgICAqIC8vID0+IGFsZXJ0cyAnbmFtZScgYW5kICdiYXJrJyAob3JkZXIgaXMgbm90IGd1YXJhbnRlZWQpXG4gICAgICovXG4gICAgdmFyIGZvckluID0gZnVuY3Rpb24gKGNvbGxlY3Rpb24sIGNhbGxiYWNrLCB0aGlzQXJnKSB7XG4gICAgICB2YXIgaW5kZXgsIGl0ZXJhYmxlID0gY29sbGVjdGlvbiwgcmVzdWx0ID0gaXRlcmFibGU7XG4gICAgICBpZiAoIWl0ZXJhYmxlKSByZXR1cm4gcmVzdWx0O1xuICAgICAgaWYgKCFvYmplY3RUeXBlc1t0eXBlb2YgaXRlcmFibGVdKSByZXR1cm4gcmVzdWx0O1xuICAgICAgY2FsbGJhY2sgPSBjYWxsYmFjayAmJiB0eXBlb2YgdGhpc0FyZyA9PSAndW5kZWZpbmVkJyA/IGNhbGxiYWNrIDogbG9kYXNoLmNyZWF0ZUNhbGxiYWNrKGNhbGxiYWNrLCB0aGlzQXJnKTsgICAgXG4gICAgICAgIGZvciAoaW5kZXggaW4gaXRlcmFibGUpIHtcbiAgICAgICAgICBpZiAoY2FsbGJhY2soaXRlcmFibGVbaW5kZXhdLCBpbmRleCwgY29sbGVjdGlvbikgPT09IGZhbHNlKSByZXR1cm4gcmVzdWx0OyAgICBcbiAgICAgICAgfSAgICBcbiAgICAgIHJldHVybiByZXN1bHRcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogSXRlcmF0ZXMgb3ZlciBhbiBvYmplY3QncyBvd24gZW51bWVyYWJsZSBwcm9wZXJ0aWVzLCBleGVjdXRpbmcgdGhlIGBjYWxsYmFja2BcbiAgICAgKiBmb3IgZWFjaCBwcm9wZXJ0eS4gVGhlIGBjYWxsYmFja2AgaXMgYm91bmQgdG8gYHRoaXNBcmdgIGFuZCBpbnZva2VkIHdpdGggdGhyZWVcbiAgICAgKiBhcmd1bWVudHM7ICh2YWx1ZSwga2V5LCBvYmplY3QpLiBDYWxsYmFja3MgbWF5IGV4aXQgaXRlcmF0aW9uIGVhcmx5IGJ5IGV4cGxpY2l0bHlcbiAgICAgKiByZXR1cm5pbmcgYGZhbHNlYC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEB0eXBlIEZ1bmN0aW9uXG4gICAgICogQGNhdGVnb3J5IE9iamVjdHNcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0IFRoZSBvYmplY3QgdG8gaXRlcmF0ZSBvdmVyLlxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb259IFtjYWxsYmFjaz1pZGVudGl0eV0gVGhlIGZ1bmN0aW9uIGNhbGxlZCBwZXIgaXRlcmF0aW9uLlxuICAgICAqIEBwYXJhbSB7TWl4ZWR9IFt0aGlzQXJnXSBUaGUgYHRoaXNgIGJpbmRpbmcgb2YgYGNhbGxiYWNrYC5cbiAgICAgKiBAcmV0dXJucyB7T2JqZWN0fSBSZXR1cm5zIGBvYmplY3RgLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLmZvck93bih7ICcwJzogJ3plcm8nLCAnMSc6ICdvbmUnLCAnbGVuZ3RoJzogMiB9LCBmdW5jdGlvbihudW0sIGtleSkge1xuICAgICAqICAgYWxlcnQoa2V5KTtcbiAgICAgKiB9KTtcbiAgICAgKiAvLyA9PiBhbGVydHMgJzAnLCAnMScsIGFuZCAnbGVuZ3RoJyAob3JkZXIgaXMgbm90IGd1YXJhbnRlZWQpXG4gICAgICovXG4gICAgdmFyIGZvck93biA9IGZ1bmN0aW9uIChjb2xsZWN0aW9uLCBjYWxsYmFjaywgdGhpc0FyZykge1xuICAgICAgdmFyIGluZGV4LCBpdGVyYWJsZSA9IGNvbGxlY3Rpb24sIHJlc3VsdCA9IGl0ZXJhYmxlO1xuICAgICAgaWYgKCFpdGVyYWJsZSkgcmV0dXJuIHJlc3VsdDtcbiAgICAgIGlmICghb2JqZWN0VHlwZXNbdHlwZW9mIGl0ZXJhYmxlXSkgcmV0dXJuIHJlc3VsdDtcbiAgICAgIGNhbGxiYWNrID0gY2FsbGJhY2sgJiYgdHlwZW9mIHRoaXNBcmcgPT0gJ3VuZGVmaW5lZCcgPyBjYWxsYmFjayA6IGxvZGFzaC5jcmVhdGVDYWxsYmFjayhjYWxsYmFjaywgdGhpc0FyZyk7ICAgIFxuICAgICAgICB2YXIgb3duSW5kZXggPSAtMSxcbiAgICAgICAgICAgIG93blByb3BzID0gb2JqZWN0VHlwZXNbdHlwZW9mIGl0ZXJhYmxlXSAmJiBrZXlzKGl0ZXJhYmxlKSxcbiAgICAgICAgICAgIGxlbmd0aCA9IG93blByb3BzID8gb3duUHJvcHMubGVuZ3RoIDogMDtcblxuICAgICAgICB3aGlsZSAoKytvd25JbmRleCA8IGxlbmd0aCkge1xuICAgICAgICAgIGluZGV4ID0gb3duUHJvcHNbb3duSW5kZXhdO1xuICAgICAgICAgIGlmIChjYWxsYmFjayhpdGVyYWJsZVtpbmRleF0sIGluZGV4LCBjb2xsZWN0aW9uKSA9PT0gZmFsc2UpIHJldHVybiByZXN1bHQ7ICAgIFxuICAgICAgICB9ICAgIFxuICAgICAgcmV0dXJuIHJlc3VsdFxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGEgc29ydGVkIGFycmF5IG9mIGFsbCBlbnVtZXJhYmxlIHByb3BlcnRpZXMsIG93biBhbmQgaW5oZXJpdGVkLFxuICAgICAqIG9mIGBvYmplY3RgIHRoYXQgaGF2ZSBmdW5jdGlvbiB2YWx1ZXMuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAYWxpYXMgbWV0aG9kc1xuICAgICAqIEBjYXRlZ29yeSBPYmplY3RzXG4gICAgICogQHBhcmFtIHtPYmplY3R9IG9iamVjdCBUaGUgb2JqZWN0IHRvIGluc3BlY3QuXG4gICAgICogQHJldHVybnMge0FycmF5fSBSZXR1cm5zIGEgbmV3IGFycmF5IG9mIHByb3BlcnR5IG5hbWVzIHRoYXQgaGF2ZSBmdW5jdGlvbiB2YWx1ZXMuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8uZnVuY3Rpb25zKF8pO1xuICAgICAqIC8vID0+IFsnYWxsJywgJ2FueScsICdiaW5kJywgJ2JpbmRBbGwnLCAnY2xvbmUnLCAnY29tcGFjdCcsICdjb21wb3NlJywgLi4uXVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGZ1bmN0aW9ucyhvYmplY3QpIHtcbiAgICAgIHZhciByZXN1bHQgPSBbXTtcbiAgICAgIGZvckluKG9iamVjdCwgZnVuY3Rpb24odmFsdWUsIGtleSkge1xuICAgICAgICBpZiAoaXNGdW5jdGlvbih2YWx1ZSkpIHtcbiAgICAgICAgICByZXN1bHQucHVzaChrZXkpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIHJldHVybiByZXN1bHQuc29ydCgpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENoZWNrcyBpZiB0aGUgc3BlY2lmaWVkIG9iamVjdCBgcHJvcGVydHlgIGV4aXN0cyBhbmQgaXMgYSBkaXJlY3QgcHJvcGVydHksXG4gICAgICogaW5zdGVhZCBvZiBhbiBpbmhlcml0ZWQgcHJvcGVydHkuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgT2JqZWN0c1xuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3QgVGhlIG9iamVjdCB0byBjaGVjay5cbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gcHJvcGVydHkgVGhlIHByb3BlcnR5IHRvIGNoZWNrIGZvci5cbiAgICAgKiBAcmV0dXJucyB7Qm9vbGVhbn0gUmV0dXJucyBgdHJ1ZWAgaWYga2V5IGlzIGEgZGlyZWN0IHByb3BlcnR5LCBlbHNlIGBmYWxzZWAuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8uaGFzKHsgJ2EnOiAxLCAnYic6IDIsICdjJzogMyB9LCAnYicpO1xuICAgICAqIC8vID0+IHRydWVcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBoYXMob2JqZWN0LCBwcm9wZXJ0eSkge1xuICAgICAgcmV0dXJuIG9iamVjdCA/IGhhc093blByb3BlcnR5LmNhbGwob2JqZWN0LCBwcm9wZXJ0eSkgOiBmYWxzZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuIG9iamVjdCBjb21wb3NlZCBvZiB0aGUgaW52ZXJ0ZWQga2V5cyBhbmQgdmFsdWVzIG9mIHRoZSBnaXZlbiBgb2JqZWN0YC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBPYmplY3RzXG4gICAgICogQHBhcmFtIHtPYmplY3R9IG9iamVjdCBUaGUgb2JqZWN0IHRvIGludmVydC5cbiAgICAgKiBAcmV0dXJucyB7T2JqZWN0fSBSZXR1cm5zIHRoZSBjcmVhdGVkIGludmVydGVkIG9iamVjdC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogIF8uaW52ZXJ0KHsgJ2ZpcnN0JzogJ21vZScsICdzZWNvbmQnOiAnbGFycnknIH0pO1xuICAgICAqIC8vID0+IHsgJ21vZSc6ICdmaXJzdCcsICdsYXJyeSc6ICdzZWNvbmQnIH1cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBpbnZlcnQob2JqZWN0KSB7XG4gICAgICB2YXIgaW5kZXggPSAtMSxcbiAgICAgICAgICBwcm9wcyA9IGtleXMob2JqZWN0KSxcbiAgICAgICAgICBsZW5ndGggPSBwcm9wcy5sZW5ndGgsXG4gICAgICAgICAgcmVzdWx0ID0ge307XG5cbiAgICAgIHdoaWxlICgrK2luZGV4IDwgbGVuZ3RoKSB7XG4gICAgICAgIHZhciBrZXkgPSBwcm9wc1tpbmRleF07XG4gICAgICAgIHJlc3VsdFtvYmplY3Rba2V5XV0gPSBrZXk7XG4gICAgICB9XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENoZWNrcyBpZiBgdmFsdWVgIGlzIGEgYm9vbGVhbiB2YWx1ZS5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBPYmplY3RzXG4gICAgICogQHBhcmFtIHtNaXhlZH0gdmFsdWUgVGhlIHZhbHVlIHRvIGNoZWNrLlxuICAgICAqIEByZXR1cm5zIHtCb29sZWFufSBSZXR1cm5zIGB0cnVlYCwgaWYgdGhlIGB2YWx1ZWAgaXMgYSBib29sZWFuIHZhbHVlLCBlbHNlIGBmYWxzZWAuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8uaXNCb29sZWFuKG51bGwpO1xuICAgICAqIC8vID0+IGZhbHNlXG4gICAgICovXG4gICAgZnVuY3Rpb24gaXNCb29sZWFuKHZhbHVlKSB7XG4gICAgICByZXR1cm4gdmFsdWUgPT09IHRydWUgfHwgdmFsdWUgPT09IGZhbHNlIHx8IHRvU3RyaW5nLmNhbGwodmFsdWUpID09IGJvb2xDbGFzcztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDaGVja3MgaWYgYHZhbHVlYCBpcyBhIGRhdGUuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgT2JqZWN0c1xuICAgICAqIEBwYXJhbSB7TWl4ZWR9IHZhbHVlIFRoZSB2YWx1ZSB0byBjaGVjay5cbiAgICAgKiBAcmV0dXJucyB7Qm9vbGVhbn0gUmV0dXJucyBgdHJ1ZWAsIGlmIHRoZSBgdmFsdWVgIGlzIGEgZGF0ZSwgZWxzZSBgZmFsc2VgLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLmlzRGF0ZShuZXcgRGF0ZSk7XG4gICAgICogLy8gPT4gdHJ1ZVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGlzRGF0ZSh2YWx1ZSkge1xuICAgICAgcmV0dXJuIHZhbHVlID8gKHR5cGVvZiB2YWx1ZSA9PSAnb2JqZWN0JyAmJiB0b1N0cmluZy5jYWxsKHZhbHVlKSA9PSBkYXRlQ2xhc3MpIDogZmFsc2U7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2hlY2tzIGlmIGB2YWx1ZWAgaXMgYSBET00gZWxlbWVudC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBPYmplY3RzXG4gICAgICogQHBhcmFtIHtNaXhlZH0gdmFsdWUgVGhlIHZhbHVlIHRvIGNoZWNrLlxuICAgICAqIEByZXR1cm5zIHtCb29sZWFufSBSZXR1cm5zIGB0cnVlYCwgaWYgdGhlIGB2YWx1ZWAgaXMgYSBET00gZWxlbWVudCwgZWxzZSBgZmFsc2VgLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLmlzRWxlbWVudChkb2N1bWVudC5ib2R5KTtcbiAgICAgKiAvLyA9PiB0cnVlXG4gICAgICovXG4gICAgZnVuY3Rpb24gaXNFbGVtZW50KHZhbHVlKSB7XG4gICAgICByZXR1cm4gdmFsdWUgPyB2YWx1ZS5ub2RlVHlwZSA9PT0gMSA6IGZhbHNlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENoZWNrcyBpZiBgdmFsdWVgIGlzIGVtcHR5LiBBcnJheXMsIHN0cmluZ3MsIG9yIGBhcmd1bWVudHNgIG9iamVjdHMgd2l0aCBhXG4gICAgICogbGVuZ3RoIG9mIGAwYCBhbmQgb2JqZWN0cyB3aXRoIG5vIG93biBlbnVtZXJhYmxlIHByb3BlcnRpZXMgYXJlIGNvbnNpZGVyZWRcbiAgICAgKiBcImVtcHR5XCIuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgT2JqZWN0c1xuICAgICAqIEBwYXJhbSB7QXJyYXl8T2JqZWN0fFN0cmluZ30gdmFsdWUgVGhlIHZhbHVlIHRvIGluc3BlY3QuXG4gICAgICogQHJldHVybnMge0Jvb2xlYW59IFJldHVybnMgYHRydWVgLCBpZiB0aGUgYHZhbHVlYCBpcyBlbXB0eSwgZWxzZSBgZmFsc2VgLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLmlzRW1wdHkoWzEsIDIsIDNdKTtcbiAgICAgKiAvLyA9PiBmYWxzZVxuICAgICAqXG4gICAgICogXy5pc0VtcHR5KHt9KTtcbiAgICAgKiAvLyA9PiB0cnVlXG4gICAgICpcbiAgICAgKiBfLmlzRW1wdHkoJycpO1xuICAgICAqIC8vID0+IHRydWVcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBpc0VtcHR5KHZhbHVlKSB7XG4gICAgICB2YXIgcmVzdWx0ID0gdHJ1ZTtcbiAgICAgIGlmICghdmFsdWUpIHtcbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgIH1cbiAgICAgIHZhciBjbGFzc05hbWUgPSB0b1N0cmluZy5jYWxsKHZhbHVlKSxcbiAgICAgICAgICBsZW5ndGggPSB2YWx1ZS5sZW5ndGg7XG5cbiAgICAgIGlmICgoY2xhc3NOYW1lID09IGFycmF5Q2xhc3MgfHwgY2xhc3NOYW1lID09IHN0cmluZ0NsYXNzIHx8IGNsYXNzTmFtZSA9PSBhcmdzQ2xhc3MgKSB8fFxuICAgICAgICAgIChjbGFzc05hbWUgPT0gb2JqZWN0Q2xhc3MgJiYgdHlwZW9mIGxlbmd0aCA9PSAnbnVtYmVyJyAmJiBpc0Z1bmN0aW9uKHZhbHVlLnNwbGljZSkpKSB7XG4gICAgICAgIHJldHVybiAhbGVuZ3RoO1xuICAgICAgfVxuICAgICAgZm9yT3duKHZhbHVlLCBmdW5jdGlvbigpIHtcbiAgICAgICAgcmV0dXJuIChyZXN1bHQgPSBmYWxzZSk7XG4gICAgICB9KTtcbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUGVyZm9ybXMgYSBkZWVwIGNvbXBhcmlzb24gYmV0d2VlbiB0d28gdmFsdWVzIHRvIGRldGVybWluZSBpZiB0aGV5IGFyZVxuICAgICAqIGVxdWl2YWxlbnQgdG8gZWFjaCBvdGhlci4gSWYgYGNhbGxiYWNrYCBpcyBwYXNzZWQsIGl0IHdpbGwgYmUgZXhlY3V0ZWQgdG9cbiAgICAgKiBjb21wYXJlIHZhbHVlcy4gSWYgYGNhbGxiYWNrYCByZXR1cm5zIGB1bmRlZmluZWRgLCBjb21wYXJpc29ucyB3aWxsIGJlIGhhbmRsZWRcbiAgICAgKiBieSB0aGUgbWV0aG9kIGluc3RlYWQuIFRoZSBgY2FsbGJhY2tgIGlzIGJvdW5kIHRvIGB0aGlzQXJnYCBhbmQgaW52b2tlZCB3aXRoXG4gICAgICogdHdvIGFyZ3VtZW50czsgKGEsIGIpLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IE9iamVjdHNcbiAgICAgKiBAcGFyYW0ge01peGVkfSBhIFRoZSB2YWx1ZSB0byBjb21wYXJlLlxuICAgICAqIEBwYXJhbSB7TWl4ZWR9IGIgVGhlIG90aGVyIHZhbHVlIHRvIGNvbXBhcmUuXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbn0gW2NhbGxiYWNrXSBUaGUgZnVuY3Rpb24gdG8gY3VzdG9taXplIGNvbXBhcmluZyB2YWx1ZXMuXG4gICAgICogQHBhcmFtIHtNaXhlZH0gW3RoaXNBcmddIFRoZSBgdGhpc2AgYmluZGluZyBvZiBgY2FsbGJhY2tgLlxuICAgICAqIEBwYXJhbS0ge0FycmF5fSBbc3RhY2tBPVtdXSBUcmFja3MgdHJhdmVyc2VkIGBhYCBvYmplY3RzLlxuICAgICAqIEBwYXJhbS0ge0FycmF5fSBbc3RhY2tCPVtdXSBUcmFja3MgdHJhdmVyc2VkIGBiYCBvYmplY3RzLlxuICAgICAqIEByZXR1cm5zIHtCb29sZWFufSBSZXR1cm5zIGB0cnVlYCwgaWYgdGhlIHZhbHVlcyBhcmUgZXF1aXZhbGVudCwgZWxzZSBgZmFsc2VgLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiB2YXIgbW9lID0geyAnbmFtZSc6ICdtb2UnLCAnYWdlJzogNDAgfTtcbiAgICAgKiB2YXIgY29weSA9IHsgJ25hbWUnOiAnbW9lJywgJ2FnZSc6IDQwIH07XG4gICAgICpcbiAgICAgKiBtb2UgPT0gY29weTtcbiAgICAgKiAvLyA9PiBmYWxzZVxuICAgICAqXG4gICAgICogXy5pc0VxdWFsKG1vZSwgY29weSk7XG4gICAgICogLy8gPT4gdHJ1ZVxuICAgICAqXG4gICAgICogdmFyIHdvcmRzID0gWydoZWxsbycsICdnb29kYnllJ107XG4gICAgICogdmFyIG90aGVyV29yZHMgPSBbJ2hpJywgJ2dvb2RieWUnXTtcbiAgICAgKlxuICAgICAqIF8uaXNFcXVhbCh3b3Jkcywgb3RoZXJXb3JkcywgZnVuY3Rpb24oYSwgYikge1xuICAgICAqICAgdmFyIHJlR3JlZXQgPSAvXig/OmhlbGxvfGhpKSQvaSxcbiAgICAgKiAgICAgICBhR3JlZXQgPSBfLmlzU3RyaW5nKGEpICYmIHJlR3JlZXQudGVzdChhKSxcbiAgICAgKiAgICAgICBiR3JlZXQgPSBfLmlzU3RyaW5nKGIpICYmIHJlR3JlZXQudGVzdChiKTtcbiAgICAgKlxuICAgICAqICAgcmV0dXJuIChhR3JlZXQgfHwgYkdyZWV0KSA/IChhR3JlZXQgPT0gYkdyZWV0KSA6IHVuZGVmaW5lZDtcbiAgICAgKiB9KTtcbiAgICAgKiAvLyA9PiB0cnVlXG4gICAgICovXG4gICAgZnVuY3Rpb24gaXNFcXVhbChhLCBiLCBjYWxsYmFjaywgdGhpc0FyZywgc3RhY2tBLCBzdGFja0IpIHtcbiAgICAgIC8vIHVzZWQgdG8gaW5kaWNhdGUgdGhhdCB3aGVuIGNvbXBhcmluZyBvYmplY3RzLCBgYWAgaGFzIGF0IGxlYXN0IHRoZSBwcm9wZXJ0aWVzIG9mIGBiYFxuICAgICAgdmFyIHdoZXJlSW5kaWNhdG9yID0gY2FsbGJhY2sgPT09IGluZGljYXRvck9iamVjdDtcbiAgICAgIGlmICh0eXBlb2YgY2FsbGJhY2sgPT0gJ2Z1bmN0aW9uJyAmJiAhd2hlcmVJbmRpY2F0b3IpIHtcbiAgICAgICAgY2FsbGJhY2sgPSBsb2Rhc2guY3JlYXRlQ2FsbGJhY2soY2FsbGJhY2ssIHRoaXNBcmcsIDIpO1xuICAgICAgICB2YXIgcmVzdWx0ID0gY2FsbGJhY2soYSwgYik7XG4gICAgICAgIGlmICh0eXBlb2YgcmVzdWx0ICE9ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgcmV0dXJuICEhcmVzdWx0O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICAvLyBleGl0IGVhcmx5IGZvciBpZGVudGljYWwgdmFsdWVzXG4gICAgICBpZiAoYSA9PT0gYikge1xuICAgICAgICAvLyB0cmVhdCBgKzBgIHZzLiBgLTBgIGFzIG5vdCBlcXVhbFxuICAgICAgICByZXR1cm4gYSAhPT0gMCB8fCAoMSAvIGEgPT0gMSAvIGIpO1xuICAgICAgfVxuICAgICAgdmFyIHR5cGUgPSB0eXBlb2YgYSxcbiAgICAgICAgICBvdGhlclR5cGUgPSB0eXBlb2YgYjtcblxuICAgICAgLy8gZXhpdCBlYXJseSBmb3IgdW5saWtlIHByaW1pdGl2ZSB2YWx1ZXNcbiAgICAgIGlmIChhID09PSBhICYmXG4gICAgICAgICAgKCFhIHx8ICh0eXBlICE9ICdmdW5jdGlvbicgJiYgdHlwZSAhPSAnb2JqZWN0JykpICYmXG4gICAgICAgICAgKCFiIHx8IChvdGhlclR5cGUgIT0gJ2Z1bmN0aW9uJyAmJiBvdGhlclR5cGUgIT0gJ29iamVjdCcpKSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgICAvLyBleGl0IGVhcmx5IGZvciBgbnVsbGAgYW5kIGB1bmRlZmluZWRgLCBhdm9pZGluZyBFUzMncyBGdW5jdGlvbiNjYWxsIGJlaGF2aW9yXG4gICAgICAvLyBodHRwOi8vZXM1LmdpdGh1Yi5jb20vI3gxNS4zLjQuNFxuICAgICAgaWYgKGEgPT0gbnVsbCB8fCBiID09IG51bGwpIHtcbiAgICAgICAgcmV0dXJuIGEgPT09IGI7XG4gICAgICB9XG4gICAgICAvLyBjb21wYXJlIFtbQ2xhc3NdXSBuYW1lc1xuICAgICAgdmFyIGNsYXNzTmFtZSA9IHRvU3RyaW5nLmNhbGwoYSksXG4gICAgICAgICAgb3RoZXJDbGFzcyA9IHRvU3RyaW5nLmNhbGwoYik7XG5cbiAgICAgIGlmIChjbGFzc05hbWUgPT0gYXJnc0NsYXNzKSB7XG4gICAgICAgIGNsYXNzTmFtZSA9IG9iamVjdENsYXNzO1xuICAgICAgfVxuICAgICAgaWYgKG90aGVyQ2xhc3MgPT0gYXJnc0NsYXNzKSB7XG4gICAgICAgIG90aGVyQ2xhc3MgPSBvYmplY3RDbGFzcztcbiAgICAgIH1cbiAgICAgIGlmIChjbGFzc05hbWUgIT0gb3RoZXJDbGFzcykge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgICBzd2l0Y2ggKGNsYXNzTmFtZSkge1xuICAgICAgICBjYXNlIGJvb2xDbGFzczpcbiAgICAgICAgY2FzZSBkYXRlQ2xhc3M6XG4gICAgICAgICAgLy8gY29lcmNlIGRhdGVzIGFuZCBib29sZWFucyB0byBudW1iZXJzLCBkYXRlcyB0byBtaWxsaXNlY29uZHMgYW5kIGJvb2xlYW5zXG4gICAgICAgICAgLy8gdG8gYDFgIG9yIGAwYCwgdHJlYXRpbmcgaW52YWxpZCBkYXRlcyBjb2VyY2VkIHRvIGBOYU5gIGFzIG5vdCBlcXVhbFxuICAgICAgICAgIHJldHVybiArYSA9PSArYjtcblxuICAgICAgICBjYXNlIG51bWJlckNsYXNzOlxuICAgICAgICAgIC8vIHRyZWF0IGBOYU5gIHZzLiBgTmFOYCBhcyBlcXVhbFxuICAgICAgICAgIHJldHVybiAoYSAhPSArYSlcbiAgICAgICAgICAgID8gYiAhPSArYlxuICAgICAgICAgICAgLy8gYnV0IHRyZWF0IGArMGAgdnMuIGAtMGAgYXMgbm90IGVxdWFsXG4gICAgICAgICAgICA6IChhID09IDAgPyAoMSAvIGEgPT0gMSAvIGIpIDogYSA9PSArYik7XG5cbiAgICAgICAgY2FzZSByZWdleHBDbGFzczpcbiAgICAgICAgY2FzZSBzdHJpbmdDbGFzczpcbiAgICAgICAgICAvLyBjb2VyY2UgcmVnZXhlcyB0byBzdHJpbmdzIChodHRwOi8vZXM1LmdpdGh1Yi5jb20vI3gxNS4xMC42LjQpXG4gICAgICAgICAgLy8gdHJlYXQgc3RyaW5nIHByaW1pdGl2ZXMgYW5kIHRoZWlyIGNvcnJlc3BvbmRpbmcgb2JqZWN0IGluc3RhbmNlcyBhcyBlcXVhbFxuICAgICAgICAgIHJldHVybiBhID09IFN0cmluZyhiKTtcbiAgICAgIH1cbiAgICAgIHZhciBpc0FyciA9IGNsYXNzTmFtZSA9PSBhcnJheUNsYXNzO1xuICAgICAgaWYgKCFpc0Fycikge1xuICAgICAgICAvLyB1bndyYXAgYW55IGBsb2Rhc2hgIHdyYXBwZWQgdmFsdWVzXG4gICAgICAgIGlmIChoYXNPd25Qcm9wZXJ0eS5jYWxsKGEsICdfX3dyYXBwZWRfXyAnKSB8fCBoYXNPd25Qcm9wZXJ0eS5jYWxsKGIsICdfX3dyYXBwZWRfXycpKSB7XG4gICAgICAgICAgcmV0dXJuIGlzRXF1YWwoYS5fX3dyYXBwZWRfXyB8fCBhLCBiLl9fd3JhcHBlZF9fIHx8IGIsIGNhbGxiYWNrLCB0aGlzQXJnLCBzdGFja0EsIHN0YWNrQik7XG4gICAgICAgIH1cbiAgICAgICAgLy8gZXhpdCBmb3IgZnVuY3Rpb25zIGFuZCBET00gbm9kZXNcbiAgICAgICAgaWYgKGNsYXNzTmFtZSAhPSBvYmplY3RDbGFzcykge1xuICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICAvLyBpbiBvbGRlciB2ZXJzaW9ucyBvZiBPcGVyYSwgYGFyZ3VtZW50c2Agb2JqZWN0cyBoYXZlIGBBcnJheWAgY29uc3RydWN0b3JzXG4gICAgICAgIHZhciBjdG9yQSA9IGEuY29uc3RydWN0b3IsXG4gICAgICAgICAgICBjdG9yQiA9IGIuY29uc3RydWN0b3I7XG5cbiAgICAgICAgLy8gbm9uIGBPYmplY3RgIG9iamVjdCBpbnN0YW5jZXMgd2l0aCBkaWZmZXJlbnQgY29uc3RydWN0b3JzIGFyZSBub3QgZXF1YWxcbiAgICAgICAgaWYgKGN0b3JBICE9IGN0b3JCICYmICEoXG4gICAgICAgICAgICAgIGlzRnVuY3Rpb24oY3RvckEpICYmIGN0b3JBIGluc3RhbmNlb2YgY3RvckEgJiZcbiAgICAgICAgICAgICAgaXNGdW5jdGlvbihjdG9yQikgJiYgY3RvckIgaW5zdGFuY2VvZiBjdG9yQlxuICAgICAgICAgICAgKSkge1xuICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgLy8gYXNzdW1lIGN5Y2xpYyBzdHJ1Y3R1cmVzIGFyZSBlcXVhbFxuICAgICAgLy8gdGhlIGFsZ29yaXRobSBmb3IgZGV0ZWN0aW5nIGN5Y2xpYyBzdHJ1Y3R1cmVzIGlzIGFkYXB0ZWQgZnJvbSBFUyA1LjFcbiAgICAgIC8vIHNlY3Rpb24gMTUuMTIuMywgYWJzdHJhY3Qgb3BlcmF0aW9uIGBKT2AgKGh0dHA6Ly9lczUuZ2l0aHViLmNvbS8jeDE1LjEyLjMpXG4gICAgICB2YXIgaW5pdGVkU3RhY2sgPSAhc3RhY2tBO1xuICAgICAgc3RhY2tBIHx8IChzdGFja0EgPSBnZXRBcnJheSgpKTtcbiAgICAgIHN0YWNrQiB8fCAoc3RhY2tCID0gZ2V0QXJyYXkoKSk7XG5cbiAgICAgIHZhciBsZW5ndGggPSBzdGFja0EubGVuZ3RoO1xuICAgICAgd2hpbGUgKGxlbmd0aC0tKSB7XG4gICAgICAgIGlmIChzdGFja0FbbGVuZ3RoXSA9PSBhKSB7XG4gICAgICAgICAgcmV0dXJuIHN0YWNrQltsZW5ndGhdID09IGI7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHZhciBzaXplID0gMDtcbiAgICAgIHJlc3VsdCA9IHRydWU7XG5cbiAgICAgIC8vIGFkZCBgYWAgYW5kIGBiYCB0byB0aGUgc3RhY2sgb2YgdHJhdmVyc2VkIG9iamVjdHNcbiAgICAgIHN0YWNrQS5wdXNoKGEpO1xuICAgICAgc3RhY2tCLnB1c2goYik7XG5cbiAgICAgIC8vIHJlY3Vyc2l2ZWx5IGNvbXBhcmUgb2JqZWN0cyBhbmQgYXJyYXlzIChzdXNjZXB0aWJsZSB0byBjYWxsIHN0YWNrIGxpbWl0cylcbiAgICAgIGlmIChpc0Fycikge1xuICAgICAgICBsZW5ndGggPSBhLmxlbmd0aDtcbiAgICAgICAgc2l6ZSA9IGIubGVuZ3RoO1xuXG4gICAgICAgIC8vIGNvbXBhcmUgbGVuZ3RocyB0byBkZXRlcm1pbmUgaWYgYSBkZWVwIGNvbXBhcmlzb24gaXMgbmVjZXNzYXJ5XG4gICAgICAgIHJlc3VsdCA9IHNpemUgPT0gYS5sZW5ndGg7XG4gICAgICAgIGlmICghcmVzdWx0ICYmICF3aGVyZUluZGljYXRvcikge1xuICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgIH1cbiAgICAgICAgLy8gZGVlcCBjb21wYXJlIHRoZSBjb250ZW50cywgaWdub3Jpbmcgbm9uLW51bWVyaWMgcHJvcGVydGllc1xuICAgICAgICB3aGlsZSAoc2l6ZS0tKSB7XG4gICAgICAgICAgdmFyIGluZGV4ID0gbGVuZ3RoLFxuICAgICAgICAgICAgICB2YWx1ZSA9IGJbc2l6ZV07XG5cbiAgICAgICAgICBpZiAod2hlcmVJbmRpY2F0b3IpIHtcbiAgICAgICAgICAgIHdoaWxlIChpbmRleC0tKSB7XG4gICAgICAgICAgICAgIGlmICgocmVzdWx0ID0gaXNFcXVhbChhW2luZGV4XSwgdmFsdWUsIGNhbGxiYWNrLCB0aGlzQXJnLCBzdGFja0EsIHN0YWNrQikpKSB7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2UgaWYgKCEocmVzdWx0ID0gaXNFcXVhbChhW3NpemVdLCB2YWx1ZSwgY2FsbGJhY2ssIHRoaXNBcmcsIHN0YWNrQSwgc3RhY2tCKSkpIHtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgfVxuICAgICAgLy8gZGVlcCBjb21wYXJlIG9iamVjdHMgdXNpbmcgYGZvckluYCwgaW5zdGVhZCBvZiBgZm9yT3duYCwgdG8gYXZvaWQgYE9iamVjdC5rZXlzYFxuICAgICAgLy8gd2hpY2gsIGluIHRoaXMgY2FzZSwgaXMgbW9yZSBjb3N0bHlcbiAgICAgIGZvckluKGIsIGZ1bmN0aW9uKHZhbHVlLCBrZXksIGIpIHtcbiAgICAgICAgaWYgKGhhc093blByb3BlcnR5LmNhbGwoYiwga2V5KSkge1xuICAgICAgICAgIC8vIGNvdW50IHRoZSBudW1iZXIgb2YgcHJvcGVydGllcy5cbiAgICAgICAgICBzaXplKys7XG4gICAgICAgICAgLy8gZGVlcCBjb21wYXJlIGVhY2ggcHJvcGVydHkgdmFsdWUuXG4gICAgICAgICAgcmV0dXJuIChyZXN1bHQgPSBoYXNPd25Qcm9wZXJ0eS5jYWxsKGEsIGtleSkgJiYgaXNFcXVhbChhW2tleV0sIHZhbHVlLCBjYWxsYmFjaywgdGhpc0FyZywgc3RhY2tBLCBzdGFja0IpKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG5cbiAgICAgIGlmIChyZXN1bHQgJiYgIXdoZXJlSW5kaWNhdG9yKSB7XG4gICAgICAgIC8vIGVuc3VyZSBib3RoIG9iamVjdHMgaGF2ZSB0aGUgc2FtZSBudW1iZXIgb2YgcHJvcGVydGllc1xuICAgICAgICBmb3JJbihhLCBmdW5jdGlvbih2YWx1ZSwga2V5LCBhKSB7XG4gICAgICAgICAgaWYgKGhhc093blByb3BlcnR5LmNhbGwoYSwga2V5KSkge1xuICAgICAgICAgICAgLy8gYHNpemVgIHdpbGwgYmUgYC0xYCBpZiBgYWAgaGFzIG1vcmUgcHJvcGVydGllcyB0aGFuIGBiYFxuICAgICAgICAgICAgcmV0dXJuIChyZXN1bHQgPSAtLXNpemUgPiAtMSk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIGlmIChpbml0ZWRTdGFjaykge1xuICAgICAgICByZWxlYXNlQXJyYXkoc3RhY2tBKTtcbiAgICAgICAgcmVsZWFzZUFycmF5KHN0YWNrQik7XG4gICAgICB9XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENoZWNrcyBpZiBgdmFsdWVgIGlzLCBvciBjYW4gYmUgY29lcmNlZCB0bywgYSBmaW5pdGUgbnVtYmVyLlxuICAgICAqXG4gICAgICogTm90ZTogVGhpcyBpcyBub3QgdGhlIHNhbWUgYXMgbmF0aXZlIGBpc0Zpbml0ZWAsIHdoaWNoIHdpbGwgcmV0dXJuIHRydWUgZm9yXG4gICAgICogYm9vbGVhbnMgYW5kIGVtcHR5IHN0cmluZ3MuIFNlZSBodHRwOi8vZXM1LmdpdGh1Yi5jb20vI3gxNS4xLjIuNS5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBPYmplY3RzXG4gICAgICogQHBhcmFtIHtNaXhlZH0gdmFsdWUgVGhlIHZhbHVlIHRvIGNoZWNrLlxuICAgICAqIEByZXR1cm5zIHtCb29sZWFufSBSZXR1cm5zIGB0cnVlYCwgaWYgdGhlIGB2YWx1ZWAgaXMgZmluaXRlLCBlbHNlIGBmYWxzZWAuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8uaXNGaW5pdGUoLTEwMSk7XG4gICAgICogLy8gPT4gdHJ1ZVxuICAgICAqXG4gICAgICogXy5pc0Zpbml0ZSgnMTAnKTtcbiAgICAgKiAvLyA9PiB0cnVlXG4gICAgICpcbiAgICAgKiBfLmlzRmluaXRlKHRydWUpO1xuICAgICAqIC8vID0+IGZhbHNlXG4gICAgICpcbiAgICAgKiBfLmlzRmluaXRlKCcnKTtcbiAgICAgKiAvLyA9PiBmYWxzZVxuICAgICAqXG4gICAgICogXy5pc0Zpbml0ZShJbmZpbml0eSk7XG4gICAgICogLy8gPT4gZmFsc2VcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBpc0Zpbml0ZSh2YWx1ZSkge1xuICAgICAgcmV0dXJuIG5hdGl2ZUlzRmluaXRlKHZhbHVlKSAmJiAhbmF0aXZlSXNOYU4ocGFyc2VGbG9hdCh2YWx1ZSkpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENoZWNrcyBpZiBgdmFsdWVgIGlzIGEgZnVuY3Rpb24uXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgT2JqZWN0c1xuICAgICAqIEBwYXJhbSB7TWl4ZWR9IHZhbHVlIFRoZSB2YWx1ZSB0byBjaGVjay5cbiAgICAgKiBAcmV0dXJucyB7Qm9vbGVhbn0gUmV0dXJucyBgdHJ1ZWAsIGlmIHRoZSBgdmFsdWVgIGlzIGEgZnVuY3Rpb24sIGVsc2UgYGZhbHNlYC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5pc0Z1bmN0aW9uKF8pO1xuICAgICAqIC8vID0+IHRydWVcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBpc0Z1bmN0aW9uKHZhbHVlKSB7XG4gICAgICByZXR1cm4gdHlwZW9mIHZhbHVlID09ICdmdW5jdGlvbic7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2hlY2tzIGlmIGB2YWx1ZWAgaXMgdGhlIGxhbmd1YWdlIHR5cGUgb2YgT2JqZWN0LlxuICAgICAqIChlLmcuIGFycmF5cywgZnVuY3Rpb25zLCBvYmplY3RzLCByZWdleGVzLCBgbmV3IE51bWJlcigwKWAsIGFuZCBgbmV3IFN0cmluZygnJylgKVxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IE9iamVjdHNcbiAgICAgKiBAcGFyYW0ge01peGVkfSB2YWx1ZSBUaGUgdmFsdWUgdG8gY2hlY2suXG4gICAgICogQHJldHVybnMge0Jvb2xlYW59IFJldHVybnMgYHRydWVgLCBpZiB0aGUgYHZhbHVlYCBpcyBhbiBvYmplY3QsIGVsc2UgYGZhbHNlYC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5pc09iamVjdCh7fSk7XG4gICAgICogLy8gPT4gdHJ1ZVxuICAgICAqXG4gICAgICogXy5pc09iamVjdChbMSwgMiwgM10pO1xuICAgICAqIC8vID0+IHRydWVcbiAgICAgKlxuICAgICAqIF8uaXNPYmplY3QoMSk7XG4gICAgICogLy8gPT4gZmFsc2VcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBpc09iamVjdCh2YWx1ZSkge1xuICAgICAgLy8gY2hlY2sgaWYgdGhlIHZhbHVlIGlzIHRoZSBFQ01BU2NyaXB0IGxhbmd1YWdlIHR5cGUgb2YgT2JqZWN0XG4gICAgICAvLyBodHRwOi8vZXM1LmdpdGh1Yi5jb20vI3g4XG4gICAgICAvLyBhbmQgYXZvaWQgYSBWOCBidWdcbiAgICAgIC8vIGh0dHA6Ly9jb2RlLmdvb2dsZS5jb20vcC92OC9pc3N1ZXMvZGV0YWlsP2lkPTIyOTFcbiAgICAgIHJldHVybiAhISh2YWx1ZSAmJiBvYmplY3RUeXBlc1t0eXBlb2YgdmFsdWVdKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDaGVja3MgaWYgYHZhbHVlYCBpcyBgTmFOYC5cbiAgICAgKlxuICAgICAqIE5vdGU6IFRoaXMgaXMgbm90IHRoZSBzYW1lIGFzIG5hdGl2ZSBgaXNOYU5gLCB3aGljaCB3aWxsIHJldHVybiBgdHJ1ZWAgZm9yXG4gICAgICogYHVuZGVmaW5lZGAgYW5kIG90aGVyIHZhbHVlcy4gU2VlIGh0dHA6Ly9lczUuZ2l0aHViLmNvbS8jeDE1LjEuMi40LlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IE9iamVjdHNcbiAgICAgKiBAcGFyYW0ge01peGVkfSB2YWx1ZSBUaGUgdmFsdWUgdG8gY2hlY2suXG4gICAgICogQHJldHVybnMge0Jvb2xlYW59IFJldHVybnMgYHRydWVgLCBpZiB0aGUgYHZhbHVlYCBpcyBgTmFOYCwgZWxzZSBgZmFsc2VgLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLmlzTmFOKE5hTik7XG4gICAgICogLy8gPT4gdHJ1ZVxuICAgICAqXG4gICAgICogXy5pc05hTihuZXcgTnVtYmVyKE5hTikpO1xuICAgICAqIC8vID0+IHRydWVcbiAgICAgKlxuICAgICAqIGlzTmFOKHVuZGVmaW5lZCk7XG4gICAgICogLy8gPT4gdHJ1ZVxuICAgICAqXG4gICAgICogXy5pc05hTih1bmRlZmluZWQpO1xuICAgICAqIC8vID0+IGZhbHNlXG4gICAgICovXG4gICAgZnVuY3Rpb24gaXNOYU4odmFsdWUpIHtcbiAgICAgIC8vIGBOYU5gIGFzIGEgcHJpbWl0aXZlIGlzIHRoZSBvbmx5IHZhbHVlIHRoYXQgaXMgbm90IGVxdWFsIHRvIGl0c2VsZlxuICAgICAgLy8gKHBlcmZvcm0gdGhlIFtbQ2xhc3NdXSBjaGVjayBmaXJzdCB0byBhdm9pZCBlcnJvcnMgd2l0aCBzb21lIGhvc3Qgb2JqZWN0cyBpbiBJRSlcbiAgICAgIHJldHVybiBpc051bWJlcih2YWx1ZSkgJiYgdmFsdWUgIT0gK3ZhbHVlXG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2hlY2tzIGlmIGB2YWx1ZWAgaXMgYG51bGxgLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IE9iamVjdHNcbiAgICAgKiBAcGFyYW0ge01peGVkfSB2YWx1ZSBUaGUgdmFsdWUgdG8gY2hlY2suXG4gICAgICogQHJldHVybnMge0Jvb2xlYW59IFJldHVybnMgYHRydWVgLCBpZiB0aGUgYHZhbHVlYCBpcyBgbnVsbGAsIGVsc2UgYGZhbHNlYC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5pc051bGwobnVsbCk7XG4gICAgICogLy8gPT4gdHJ1ZVxuICAgICAqXG4gICAgICogXy5pc051bGwodW5kZWZpbmVkKTtcbiAgICAgKiAvLyA9PiBmYWxzZVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGlzTnVsbCh2YWx1ZSkge1xuICAgICAgcmV0dXJuIHZhbHVlID09PSBudWxsO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENoZWNrcyBpZiBgdmFsdWVgIGlzIGEgbnVtYmVyLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IE9iamVjdHNcbiAgICAgKiBAcGFyYW0ge01peGVkfSB2YWx1ZSBUaGUgdmFsdWUgdG8gY2hlY2suXG4gICAgICogQHJldHVybnMge0Jvb2xlYW59IFJldHVybnMgYHRydWVgLCBpZiB0aGUgYHZhbHVlYCBpcyBhIG51bWJlciwgZWxzZSBgZmFsc2VgLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLmlzTnVtYmVyKDguNCAqIDUpO1xuICAgICAqIC8vID0+IHRydWVcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBpc051bWJlcih2YWx1ZSkge1xuICAgICAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PSAnbnVtYmVyJyB8fCB0b1N0cmluZy5jYWxsKHZhbHVlKSA9PSBudW1iZXJDbGFzcztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDaGVja3MgaWYgYSBnaXZlbiBgdmFsdWVgIGlzIGFuIG9iamVjdCBjcmVhdGVkIGJ5IHRoZSBgT2JqZWN0YCBjb25zdHJ1Y3Rvci5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBPYmplY3RzXG4gICAgICogQHBhcmFtIHtNaXhlZH0gdmFsdWUgVGhlIHZhbHVlIHRvIGNoZWNrLlxuICAgICAqIEByZXR1cm5zIHtCb29sZWFufSBSZXR1cm5zIGB0cnVlYCwgaWYgYHZhbHVlYCBpcyBhIHBsYWluIG9iamVjdCwgZWxzZSBgZmFsc2VgLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBmdW5jdGlvbiBTdG9vZ2UobmFtZSwgYWdlKSB7XG4gICAgICogICB0aGlzLm5hbWUgPSBuYW1lO1xuICAgICAqICAgdGhpcy5hZ2UgPSBhZ2U7XG4gICAgICogfVxuICAgICAqXG4gICAgICogXy5pc1BsYWluT2JqZWN0KG5ldyBTdG9vZ2UoJ21vZScsIDQwKSk7XG4gICAgICogLy8gPT4gZmFsc2VcbiAgICAgKlxuICAgICAqIF8uaXNQbGFpbk9iamVjdChbMSwgMiwgM10pO1xuICAgICAqIC8vID0+IGZhbHNlXG4gICAgICpcbiAgICAgKiBfLmlzUGxhaW5PYmplY3QoeyAnbmFtZSc6ICdtb2UnLCAnYWdlJzogNDAgfSk7XG4gICAgICogLy8gPT4gdHJ1ZVxuICAgICAqL1xuICAgIHZhciBpc1BsYWluT2JqZWN0ID0gZnVuY3Rpb24odmFsdWUpIHtcbiAgICAgIGlmICghKHZhbHVlICYmIHRvU3RyaW5nLmNhbGwodmFsdWUpID09IG9iamVjdENsYXNzKSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgICB2YXIgdmFsdWVPZiA9IHZhbHVlLnZhbHVlT2YsXG4gICAgICAgICAgb2JqUHJvdG8gPSB0eXBlb2YgdmFsdWVPZiA9PSAnZnVuY3Rpb24nICYmIChvYmpQcm90byA9IGdldFByb3RvdHlwZU9mKHZhbHVlT2YpKSAmJiBnZXRQcm90b3R5cGVPZihvYmpQcm90byk7XG5cbiAgICAgIHJldHVybiBvYmpQcm90b1xuICAgICAgICA/ICh2YWx1ZSA9PSBvYmpQcm90byB8fCBnZXRQcm90b3R5cGVPZih2YWx1ZSkgPT0gb2JqUHJvdG8pXG4gICAgICAgIDogc2hpbUlzUGxhaW5PYmplY3QodmFsdWUpO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBDaGVja3MgaWYgYHZhbHVlYCBpcyBhIHJlZ3VsYXIgZXhwcmVzc2lvbi5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBPYmplY3RzXG4gICAgICogQHBhcmFtIHtNaXhlZH0gdmFsdWUgVGhlIHZhbHVlIHRvIGNoZWNrLlxuICAgICAqIEByZXR1cm5zIHtCb29sZWFufSBSZXR1cm5zIGB0cnVlYCwgaWYgdGhlIGB2YWx1ZWAgaXMgYSByZWd1bGFyIGV4cHJlc3Npb24sIGVsc2UgYGZhbHNlYC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5pc1JlZ0V4cCgvbW9lLyk7XG4gICAgICogLy8gPT4gdHJ1ZVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGlzUmVnRXhwKHZhbHVlKSB7XG4gICAgICByZXR1cm4gdmFsdWUgPyAodHlwZW9mIHZhbHVlID09ICdvYmplY3QnICYmIHRvU3RyaW5nLmNhbGwodmFsdWUpID09IHJlZ2V4cENsYXNzKSA6IGZhbHNlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENoZWNrcyBpZiBgdmFsdWVgIGlzIGEgc3RyaW5nLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IE9iamVjdHNcbiAgICAgKiBAcGFyYW0ge01peGVkfSB2YWx1ZSBUaGUgdmFsdWUgdG8gY2hlY2suXG4gICAgICogQHJldHVybnMge0Jvb2xlYW59IFJldHVybnMgYHRydWVgLCBpZiB0aGUgYHZhbHVlYCBpcyBhIHN0cmluZywgZWxzZSBgZmFsc2VgLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLmlzU3RyaW5nKCdtb2UnKTtcbiAgICAgKiAvLyA9PiB0cnVlXG4gICAgICovXG4gICAgZnVuY3Rpb24gaXNTdHJpbmcodmFsdWUpIHtcbiAgICAgIHJldHVybiB0eXBlb2YgdmFsdWUgPT0gJ3N0cmluZycgfHwgdG9TdHJpbmcuY2FsbCh2YWx1ZSkgPT0gc3RyaW5nQ2xhc3M7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2hlY2tzIGlmIGB2YWx1ZWAgaXMgYHVuZGVmaW5lZGAuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgT2JqZWN0c1xuICAgICAqIEBwYXJhbSB7TWl4ZWR9IHZhbHVlIFRoZSB2YWx1ZSB0byBjaGVjay5cbiAgICAgKiBAcmV0dXJucyB7Qm9vbGVhbn0gUmV0dXJucyBgdHJ1ZWAsIGlmIHRoZSBgdmFsdWVgIGlzIGB1bmRlZmluZWRgLCBlbHNlIGBmYWxzZWAuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8uaXNVbmRlZmluZWQodm9pZCAwKTtcbiAgICAgKiAvLyA9PiB0cnVlXG4gICAgICovXG4gICAgZnVuY3Rpb24gaXNVbmRlZmluZWQodmFsdWUpIHtcbiAgICAgIHJldHVybiB0eXBlb2YgdmFsdWUgPT0gJ3VuZGVmaW5lZCc7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVjdXJzaXZlbHkgbWVyZ2VzIG93biBlbnVtZXJhYmxlIHByb3BlcnRpZXMgb2YgdGhlIHNvdXJjZSBvYmplY3QocyksIHRoYXRcbiAgICAgKiBkb24ndCByZXNvbHZlIHRvIGB1bmRlZmluZWRgLCBpbnRvIHRoZSBkZXN0aW5hdGlvbiBvYmplY3QuIFN1YnNlcXVlbnQgc291cmNlc1xuICAgICAqIHdpbGwgb3ZlcndyaXRlIHByb3BlcnR5IGFzc2lnbm1lbnRzIG9mIHByZXZpb3VzIHNvdXJjZXMuIElmIGEgYGNhbGxiYWNrYCBmdW5jdGlvblxuICAgICAqIGlzIHBhc3NlZCwgaXQgd2lsbCBiZSBleGVjdXRlZCB0byBwcm9kdWNlIHRoZSBtZXJnZWQgdmFsdWVzIG9mIHRoZSBkZXN0aW5hdGlvblxuICAgICAqIGFuZCBzb3VyY2UgcHJvcGVydGllcy4gSWYgYGNhbGxiYWNrYCByZXR1cm5zIGB1bmRlZmluZWRgLCBtZXJnaW5nIHdpbGwgYmVcbiAgICAgKiBoYW5kbGVkIGJ5IHRoZSBtZXRob2QgaW5zdGVhZC4gVGhlIGBjYWxsYmFja2AgaXMgYm91bmQgdG8gYHRoaXNBcmdgIGFuZFxuICAgICAqIGludm9rZWQgd2l0aCB0d28gYXJndW1lbnRzOyAob2JqZWN0VmFsdWUsIHNvdXJjZVZhbHVlKS5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBPYmplY3RzXG4gICAgICogQHBhcmFtIHtPYmplY3R9IG9iamVjdCBUaGUgZGVzdGluYXRpb24gb2JqZWN0LlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBbc291cmNlMSwgc291cmNlMiwgLi4uXSBUaGUgc291cmNlIG9iamVjdHMuXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbn0gW2NhbGxiYWNrXSBUaGUgZnVuY3Rpb24gdG8gY3VzdG9taXplIG1lcmdpbmcgcHJvcGVydGllcy5cbiAgICAgKiBAcGFyYW0ge01peGVkfSBbdGhpc0FyZ10gVGhlIGB0aGlzYCBiaW5kaW5nIG9mIGBjYWxsYmFja2AuXG4gICAgICogQHBhcmFtLSB7T2JqZWN0fSBbZGVlcEluZGljYXRvcl0gSW5kaWNhdGVzIHRoYXQgYHN0YWNrQWAgYW5kIGBzdGFja0JgIGFyZVxuICAgICAqICBhcnJheXMgb2YgdHJhdmVyc2VkIG9iamVjdHMsIGluc3RlYWQgb2Ygc291cmNlIG9iamVjdHMuXG4gICAgICogQHBhcmFtLSB7QXJyYXl9IFtzdGFja0E9W11dIFRyYWNrcyB0cmF2ZXJzZWQgc291cmNlIG9iamVjdHMuXG4gICAgICogQHBhcmFtLSB7QXJyYXl9IFtzdGFja0I9W11dIEFzc29jaWF0ZXMgdmFsdWVzIHdpdGggc291cmNlIGNvdW50ZXJwYXJ0cy5cbiAgICAgKiBAcmV0dXJucyB7T2JqZWN0fSBSZXR1cm5zIHRoZSBkZXN0aW5hdGlvbiBvYmplY3QuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIHZhciBuYW1lcyA9IHtcbiAgICAgKiAgICdzdG9vZ2VzJzogW1xuICAgICAqICAgICB7ICduYW1lJzogJ21vZScgfSxcbiAgICAgKiAgICAgeyAnbmFtZSc6ICdsYXJyeScgfVxuICAgICAqICAgXVxuICAgICAqIH07XG4gICAgICpcbiAgICAgKiB2YXIgYWdlcyA9IHtcbiAgICAgKiAgICdzdG9vZ2VzJzogW1xuICAgICAqICAgICB7ICdhZ2UnOiA0MCB9LFxuICAgICAqICAgICB7ICdhZ2UnOiA1MCB9XG4gICAgICogICBdXG4gICAgICogfTtcbiAgICAgKlxuICAgICAqIF8ubWVyZ2UobmFtZXMsIGFnZXMpO1xuICAgICAqIC8vID0+IHsgJ3N0b29nZXMnOiBbeyAnbmFtZSc6ICdtb2UnLCAnYWdlJzogNDAgfSwgeyAnbmFtZSc6ICdsYXJyeScsICdhZ2UnOiA1MCB9XSB9XG4gICAgICpcbiAgICAgKiB2YXIgZm9vZCA9IHtcbiAgICAgKiAgICdmcnVpdHMnOiBbJ2FwcGxlJ10sXG4gICAgICogICAndmVnZXRhYmxlcyc6IFsnYmVldCddXG4gICAgICogfTtcbiAgICAgKlxuICAgICAqIHZhciBvdGhlckZvb2QgPSB7XG4gICAgICogICAnZnJ1aXRzJzogWydiYW5hbmEnXSxcbiAgICAgKiAgICd2ZWdldGFibGVzJzogWydjYXJyb3QnXVxuICAgICAqIH07XG4gICAgICpcbiAgICAgKiBfLm1lcmdlKGZvb2QsIG90aGVyRm9vZCwgZnVuY3Rpb24oYSwgYikge1xuICAgICAqICAgcmV0dXJuIF8uaXNBcnJheShhKSA/IGEuY29uY2F0KGIpIDogdW5kZWZpbmVkO1xuICAgICAqIH0pO1xuICAgICAqIC8vID0+IHsgJ2ZydWl0cyc6IFsnYXBwbGUnLCAnYmFuYW5hJ10sICd2ZWdldGFibGVzJzogWydiZWV0JywgJ2NhcnJvdF0gfVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIG1lcmdlKG9iamVjdCwgc291cmNlLCBkZWVwSW5kaWNhdG9yKSB7XG4gICAgICB2YXIgYXJncyA9IGFyZ3VtZW50cyxcbiAgICAgICAgICBpbmRleCA9IDAsXG4gICAgICAgICAgbGVuZ3RoID0gMjtcblxuICAgICAgaWYgKCFpc09iamVjdChvYmplY3QpKSB7XG4gICAgICAgIHJldHVybiBvYmplY3Q7XG4gICAgICB9XG4gICAgICBpZiAoZGVlcEluZGljYXRvciA9PT0gaW5kaWNhdG9yT2JqZWN0KSB7XG4gICAgICAgIHZhciBjYWxsYmFjayA9IGFyZ3NbM10sXG4gICAgICAgICAgICBzdGFja0EgPSBhcmdzWzRdLFxuICAgICAgICAgICAgc3RhY2tCID0gYXJnc1s1XTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHZhciBpbml0ZWRTdGFjayA9IHRydWU7XG4gICAgICAgIHN0YWNrQSA9IGdldEFycmF5KCk7XG4gICAgICAgIHN0YWNrQiA9IGdldEFycmF5KCk7XG5cbiAgICAgICAgLy8gYWxsb3dzIHdvcmtpbmcgd2l0aCBgXy5yZWR1Y2VgIGFuZCBgXy5yZWR1Y2VSaWdodGAgd2l0aG91dFxuICAgICAgICAvLyB1c2luZyB0aGVpciBgY2FsbGJhY2tgIGFyZ3VtZW50cywgYGluZGV4fGtleWAgYW5kIGBjb2xsZWN0aW9uYFxuICAgICAgICBpZiAodHlwZW9mIGRlZXBJbmRpY2F0b3IgIT0gJ251bWJlcicpIHtcbiAgICAgICAgICBsZW5ndGggPSBhcmdzLmxlbmd0aDtcbiAgICAgICAgfVxuICAgICAgICBpZiAobGVuZ3RoID4gMyAmJiB0eXBlb2YgYXJnc1tsZW5ndGggLSAyXSA9PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgY2FsbGJhY2sgPSBsb2Rhc2guY3JlYXRlQ2FsbGJhY2soYXJnc1stLWxlbmd0aCAtIDFdLCBhcmdzW2xlbmd0aC0tXSwgMik7XG4gICAgICAgIH0gZWxzZSBpZiAobGVuZ3RoID4gMiAmJiB0eXBlb2YgYXJnc1tsZW5ndGggLSAxXSA9PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgY2FsbGJhY2sgPSBhcmdzWy0tbGVuZ3RoXTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgd2hpbGUgKCsraW5kZXggPCBsZW5ndGgpIHtcbiAgICAgICAgKGlzQXJyYXkoYXJnc1tpbmRleF0pID8gZm9yRWFjaCA6IGZvck93bikoYXJnc1tpbmRleF0sIGZ1bmN0aW9uKHNvdXJjZSwga2V5KSB7XG4gICAgICAgICAgdmFyIGZvdW5kLFxuICAgICAgICAgICAgICBpc0FycixcbiAgICAgICAgICAgICAgcmVzdWx0ID0gc291cmNlLFxuICAgICAgICAgICAgICB2YWx1ZSA9IG9iamVjdFtrZXldO1xuXG4gICAgICAgICAgaWYgKHNvdXJjZSAmJiAoKGlzQXJyID0gaXNBcnJheShzb3VyY2UpKSB8fCBpc1BsYWluT2JqZWN0KHNvdXJjZSkpKSB7XG4gICAgICAgICAgICAvLyBhdm9pZCBtZXJnaW5nIHByZXZpb3VzbHkgbWVyZ2VkIGN5Y2xpYyBzb3VyY2VzXG4gICAgICAgICAgICB2YXIgc3RhY2tMZW5ndGggPSBzdGFja0EubGVuZ3RoO1xuICAgICAgICAgICAgd2hpbGUgKHN0YWNrTGVuZ3RoLS0pIHtcbiAgICAgICAgICAgICAgaWYgKChmb3VuZCA9IHN0YWNrQVtzdGFja0xlbmd0aF0gPT0gc291cmNlKSkge1xuICAgICAgICAgICAgICAgIHZhbHVlID0gc3RhY2tCW3N0YWNrTGVuZ3RoXTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFmb3VuZCkge1xuICAgICAgICAgICAgICB2YXIgaXNTaGFsbG93O1xuICAgICAgICAgICAgICBpZiAoY2FsbGJhY2spIHtcbiAgICAgICAgICAgICAgICByZXN1bHQgPSBjYWxsYmFjayh2YWx1ZSwgc291cmNlKTtcbiAgICAgICAgICAgICAgICBpZiAoKGlzU2hhbGxvdyA9IHR5cGVvZiByZXN1bHQgIT0gJ3VuZGVmaW5lZCcpKSB7XG4gICAgICAgICAgICAgICAgICB2YWx1ZSA9IHJlc3VsdDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgaWYgKCFpc1NoYWxsb3cpIHtcbiAgICAgICAgICAgICAgICB2YWx1ZSA9IGlzQXJyXG4gICAgICAgICAgICAgICAgICA/IChpc0FycmF5KHZhbHVlKSA/IHZhbHVlIDogW10pXG4gICAgICAgICAgICAgICAgICA6IChpc1BsYWluT2JqZWN0KHZhbHVlKSA/IHZhbHVlIDoge30pO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIC8vIGFkZCBgc291cmNlYCBhbmQgYXNzb2NpYXRlZCBgdmFsdWVgIHRvIHRoZSBzdGFjayBvZiB0cmF2ZXJzZWQgb2JqZWN0c1xuICAgICAgICAgICAgICBzdGFja0EucHVzaChzb3VyY2UpO1xuICAgICAgICAgICAgICBzdGFja0IucHVzaCh2YWx1ZSk7XG5cbiAgICAgICAgICAgICAgLy8gcmVjdXJzaXZlbHkgbWVyZ2Ugb2JqZWN0cyBhbmQgYXJyYXlzIChzdXNjZXB0aWJsZSB0byBjYWxsIHN0YWNrIGxpbWl0cylcbiAgICAgICAgICAgICAgaWYgKCFpc1NoYWxsb3cpIHtcbiAgICAgICAgICAgICAgICB2YWx1ZSA9IG1lcmdlKHZhbHVlLCBzb3VyY2UsIGluZGljYXRvck9iamVjdCwgY2FsbGJhY2ssIHN0YWNrQSwgc3RhY2tCKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGlmIChjYWxsYmFjaykge1xuICAgICAgICAgICAgICByZXN1bHQgPSBjYWxsYmFjayh2YWx1ZSwgc291cmNlKTtcbiAgICAgICAgICAgICAgaWYgKHR5cGVvZiByZXN1bHQgPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgICAgICByZXN1bHQgPSBzb3VyY2U7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICh0eXBlb2YgcmVzdWx0ICE9ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICAgIHZhbHVlID0gcmVzdWx0O1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBvYmplY3Rba2V5XSA9IHZhbHVlO1xuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKGluaXRlZFN0YWNrKSB7XG4gICAgICAgIHJlbGVhc2VBcnJheShzdGFja0EpO1xuICAgICAgICByZWxlYXNlQXJyYXkoc3RhY2tCKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBvYmplY3Q7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhIHNoYWxsb3cgY2xvbmUgb2YgYG9iamVjdGAgZXhjbHVkaW5nIHRoZSBzcGVjaWZpZWQgcHJvcGVydGllcy5cbiAgICAgKiBQcm9wZXJ0eSBuYW1lcyBtYXkgYmUgc3BlY2lmaWVkIGFzIGluZGl2aWR1YWwgYXJndW1lbnRzIG9yIGFzIGFycmF5cyBvZlxuICAgICAqIHByb3BlcnR5IG5hbWVzLiBJZiBhIGBjYWxsYmFja2AgZnVuY3Rpb24gaXMgcGFzc2VkLCBpdCB3aWxsIGJlIGV4ZWN1dGVkXG4gICAgICogZm9yIGVhY2ggcHJvcGVydHkgaW4gdGhlIGBvYmplY3RgLCBvbWl0dGluZyB0aGUgcHJvcGVydGllcyBgY2FsbGJhY2tgXG4gICAgICogcmV0dXJucyB0cnV0aHkgZm9yLiBUaGUgYGNhbGxiYWNrYCBpcyBib3VuZCB0byBgdGhpc0FyZ2AgYW5kIGludm9rZWRcbiAgICAgKiB3aXRoIHRocmVlIGFyZ3VtZW50czsgKHZhbHVlLCBrZXksIG9iamVjdCkuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgT2JqZWN0c1xuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3QgVGhlIHNvdXJjZSBvYmplY3QuXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbnxTdHJpbmd9IGNhbGxiYWNrfFtwcm9wMSwgcHJvcDIsIC4uLl0gVGhlIHByb3BlcnRpZXMgdG8gb21pdFxuICAgICAqICBvciB0aGUgZnVuY3Rpb24gY2FsbGVkIHBlciBpdGVyYXRpb24uXG4gICAgICogQHBhcmFtIHtNaXhlZH0gW3RoaXNBcmddIFRoZSBgdGhpc2AgYmluZGluZyBvZiBgY2FsbGJhY2tgLlxuICAgICAqIEByZXR1cm5zIHtPYmplY3R9IFJldHVybnMgYW4gb2JqZWN0IHdpdGhvdXQgdGhlIG9taXR0ZWQgcHJvcGVydGllcy5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5vbWl0KHsgJ25hbWUnOiAnbW9lJywgJ2FnZSc6IDQwIH0sICdhZ2UnKTtcbiAgICAgKiAvLyA9PiB7ICduYW1lJzogJ21vZScgfVxuICAgICAqXG4gICAgICogXy5vbWl0KHsgJ25hbWUnOiAnbW9lJywgJ2FnZSc6IDQwIH0sIGZ1bmN0aW9uKHZhbHVlKSB7XG4gICAgICogICByZXR1cm4gdHlwZW9mIHZhbHVlID09ICdudW1iZXInO1xuICAgICAqIH0pO1xuICAgICAqIC8vID0+IHsgJ25hbWUnOiAnbW9lJyB9XG4gICAgICovXG4gICAgZnVuY3Rpb24gb21pdChvYmplY3QsIGNhbGxiYWNrLCB0aGlzQXJnKSB7XG4gICAgICB2YXIgaW5kZXhPZiA9IGdldEluZGV4T2YoKSxcbiAgICAgICAgICBpc0Z1bmMgPSB0eXBlb2YgY2FsbGJhY2sgPT0gJ2Z1bmN0aW9uJyxcbiAgICAgICAgICByZXN1bHQgPSB7fTtcblxuICAgICAgaWYgKGlzRnVuYykge1xuICAgICAgICBjYWxsYmFjayA9IGxvZGFzaC5jcmVhdGVDYWxsYmFjayhjYWxsYmFjaywgdGhpc0FyZyk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB2YXIgcHJvcHMgPSBjb25jYXQuYXBwbHkoYXJyYXlSZWYsIG5hdGl2ZVNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKSk7XG4gICAgICB9XG4gICAgICBmb3JJbihvYmplY3QsIGZ1bmN0aW9uKHZhbHVlLCBrZXksIG9iamVjdCkge1xuICAgICAgICBpZiAoaXNGdW5jXG4gICAgICAgICAgICAgID8gIWNhbGxiYWNrKHZhbHVlLCBrZXksIG9iamVjdClcbiAgICAgICAgICAgICAgOiBpbmRleE9mKHByb3BzLCBrZXkpIDwgMFxuICAgICAgICAgICAgKSB7XG4gICAgICAgICAgcmVzdWx0W2tleV0gPSB2YWx1ZTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYSB0d28gZGltZW5zaW9uYWwgYXJyYXkgb2YgdGhlIGdpdmVuIG9iamVjdCdzIGtleS12YWx1ZSBwYWlycyxcbiAgICAgKiBpLmUuIGBbW2tleTEsIHZhbHVlMV0sIFtrZXkyLCB2YWx1ZTJdXWAuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgT2JqZWN0c1xuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3QgVGhlIG9iamVjdCB0byBpbnNwZWN0LlxuICAgICAqIEByZXR1cm5zIHtBcnJheX0gUmV0dXJucyBuZXcgYXJyYXkgb2Yga2V5LXZhbHVlIHBhaXJzLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLnBhaXJzKHsgJ21vZSc6IDMwLCAnbGFycnknOiA0MCB9KTtcbiAgICAgKiAvLyA9PiBbWydtb2UnLCAzMF0sIFsnbGFycnknLCA0MF1dIChvcmRlciBpcyBub3QgZ3VhcmFudGVlZClcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBwYWlycyhvYmplY3QpIHtcbiAgICAgIHZhciBpbmRleCA9IC0xLFxuICAgICAgICAgIHByb3BzID0ga2V5cyhvYmplY3QpLFxuICAgICAgICAgIGxlbmd0aCA9IHByb3BzLmxlbmd0aCxcbiAgICAgICAgICByZXN1bHQgPSBBcnJheShsZW5ndGgpO1xuXG4gICAgICB3aGlsZSAoKytpbmRleCA8IGxlbmd0aCkge1xuICAgICAgICB2YXIga2V5ID0gcHJvcHNbaW5kZXhdO1xuICAgICAgICByZXN1bHRbaW5kZXhdID0gW2tleSwgb2JqZWN0W2tleV1dO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGEgc2hhbGxvdyBjbG9uZSBvZiBgb2JqZWN0YCBjb21wb3NlZCBvZiB0aGUgc3BlY2lmaWVkIHByb3BlcnRpZXMuXG4gICAgICogUHJvcGVydHkgbmFtZXMgbWF5IGJlIHNwZWNpZmllZCBhcyBpbmRpdmlkdWFsIGFyZ3VtZW50cyBvciBhcyBhcnJheXMgb2YgcHJvcGVydHlcbiAgICAgKiBuYW1lcy4gSWYgYGNhbGxiYWNrYCBpcyBwYXNzZWQsIGl0IHdpbGwgYmUgZXhlY3V0ZWQgZm9yIGVhY2ggcHJvcGVydHkgaW4gdGhlXG4gICAgICogYG9iamVjdGAsIHBpY2tpbmcgdGhlIHByb3BlcnRpZXMgYGNhbGxiYWNrYCByZXR1cm5zIHRydXRoeSBmb3IuIFRoZSBgY2FsbGJhY2tgXG4gICAgICogaXMgYm91bmQgdG8gYHRoaXNBcmdgIGFuZCBpbnZva2VkIHdpdGggdGhyZWUgYXJndW1lbnRzOyAodmFsdWUsIGtleSwgb2JqZWN0KS5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBPYmplY3RzXG4gICAgICogQHBhcmFtIHtPYmplY3R9IG9iamVjdCBUaGUgc291cmNlIG9iamVjdC5cbiAgICAgKiBAcGFyYW0ge0FycmF5fEZ1bmN0aW9ufFN0cmluZ30gY2FsbGJhY2t8W3Byb3AxLCBwcm9wMiwgLi4uXSBUaGUgZnVuY3Rpb24gY2FsbGVkXG4gICAgICogIHBlciBpdGVyYXRpb24gb3IgcHJvcGVydGllcyB0byBwaWNrLCBlaXRoZXIgYXMgaW5kaXZpZHVhbCBhcmd1bWVudHMgb3IgYXJyYXlzLlxuICAgICAqIEBwYXJhbSB7TWl4ZWR9IFt0aGlzQXJnXSBUaGUgYHRoaXNgIGJpbmRpbmcgb2YgYGNhbGxiYWNrYC5cbiAgICAgKiBAcmV0dXJucyB7T2JqZWN0fSBSZXR1cm5zIGFuIG9iamVjdCBjb21wb3NlZCBvZiB0aGUgcGlja2VkIHByb3BlcnRpZXMuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8ucGljayh7ICduYW1lJzogJ21vZScsICdfdXNlcmlkJzogJ21vZTEnIH0sICduYW1lJyk7XG4gICAgICogLy8gPT4geyAnbmFtZSc6ICdtb2UnIH1cbiAgICAgKlxuICAgICAqIF8ucGljayh7ICduYW1lJzogJ21vZScsICdfdXNlcmlkJzogJ21vZTEnIH0sIGZ1bmN0aW9uKHZhbHVlLCBrZXkpIHtcbiAgICAgKiAgIHJldHVybiBrZXkuY2hhckF0KDApICE9ICdfJztcbiAgICAgKiB9KTtcbiAgICAgKiAvLyA9PiB7ICduYW1lJzogJ21vZScgfVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIHBpY2sob2JqZWN0LCBjYWxsYmFjaywgdGhpc0FyZykge1xuICAgICAgdmFyIHJlc3VsdCA9IHt9O1xuICAgICAgaWYgKHR5cGVvZiBjYWxsYmFjayAhPSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHZhciBpbmRleCA9IC0xLFxuICAgICAgICAgICAgcHJvcHMgPSBjb25jYXQuYXBwbHkoYXJyYXlSZWYsIG5hdGl2ZVNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKSksXG4gICAgICAgICAgICBsZW5ndGggPSBpc09iamVjdChvYmplY3QpID8gcHJvcHMubGVuZ3RoIDogMDtcblxuICAgICAgICB3aGlsZSAoKytpbmRleCA8IGxlbmd0aCkge1xuICAgICAgICAgIHZhciBrZXkgPSBwcm9wc1tpbmRleF07XG4gICAgICAgICAgaWYgKGtleSBpbiBvYmplY3QpIHtcbiAgICAgICAgICAgIHJlc3VsdFtrZXldID0gb2JqZWN0W2tleV07XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjYWxsYmFjayA9IGxvZGFzaC5jcmVhdGVDYWxsYmFjayhjYWxsYmFjaywgdGhpc0FyZyk7XG4gICAgICAgIGZvckluKG9iamVjdCwgZnVuY3Rpb24odmFsdWUsIGtleSwgb2JqZWN0KSB7XG4gICAgICAgICAgaWYgKGNhbGxiYWNrKHZhbHVlLCBrZXksIG9iamVjdCkpIHtcbiAgICAgICAgICAgIHJlc3VsdFtrZXldID0gdmFsdWU7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQW4gYWx0ZXJuYXRpdmUgdG8gYF8ucmVkdWNlYCwgdGhpcyBtZXRob2QgdHJhbnNmb3JtcyBhbiBgb2JqZWN0YCB0byBhIG5ld1xuICAgICAqIGBhY2N1bXVsYXRvcmAgb2JqZWN0IHdoaWNoIGlzIHRoZSByZXN1bHQgb2YgcnVubmluZyBlYWNoIG9mIGl0cyBlbGVtZW50c1xuICAgICAqIHRocm91Z2ggdGhlIGBjYWxsYmFja2AsIHdpdGggZWFjaCBgY2FsbGJhY2tgIGV4ZWN1dGlvbiBwb3RlbnRpYWxseSBtdXRhdGluZ1xuICAgICAqIHRoZSBgYWNjdW11bGF0b3JgIG9iamVjdC4gVGhlIGBjYWxsYmFja2AgaXMgYm91bmQgdG8gYHRoaXNBcmdgIGFuZCBpbnZva2VkXG4gICAgICogd2l0aCBmb3VyIGFyZ3VtZW50czsgKGFjY3VtdWxhdG9yLCB2YWx1ZSwga2V5LCBvYmplY3QpLiBDYWxsYmFja3MgbWF5IGV4aXRcbiAgICAgKiBpdGVyYXRpb24gZWFybHkgYnkgZXhwbGljaXRseSByZXR1cm5pbmcgYGZhbHNlYC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBPYmplY3RzXG4gICAgICogQHBhcmFtIHtBcnJheXxPYmplY3R9IGNvbGxlY3Rpb24gVGhlIGNvbGxlY3Rpb24gdG8gaXRlcmF0ZSBvdmVyLlxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb259IFtjYWxsYmFjaz1pZGVudGl0eV0gVGhlIGZ1bmN0aW9uIGNhbGxlZCBwZXIgaXRlcmF0aW9uLlxuICAgICAqIEBwYXJhbSB7TWl4ZWR9IFthY2N1bXVsYXRvcl0gVGhlIGN1c3RvbSBhY2N1bXVsYXRvciB2YWx1ZS5cbiAgICAgKiBAcGFyYW0ge01peGVkfSBbdGhpc0FyZ10gVGhlIGB0aGlzYCBiaW5kaW5nIG9mIGBjYWxsYmFja2AuXG4gICAgICogQHJldHVybnMge01peGVkfSBSZXR1cm5zIHRoZSBhY2N1bXVsYXRlZCB2YWx1ZS5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogdmFyIHNxdWFyZXMgPSBfLnRyYW5zZm9ybShbMSwgMiwgMywgNCwgNSwgNiwgNywgOCwgOSwgMTBdLCBmdW5jdGlvbihyZXN1bHQsIG51bSkge1xuICAgICAqICAgbnVtICo9IG51bTtcbiAgICAgKiAgIGlmIChudW0gJSAyKSB7XG4gICAgICogICAgIHJldHVybiByZXN1bHQucHVzaChudW0pIDwgMztcbiAgICAgKiAgIH1cbiAgICAgKiB9KTtcbiAgICAgKiAvLyA9PiBbMSwgOSwgMjVdXG4gICAgICpcbiAgICAgKiB2YXIgbWFwcGVkID0gXy50cmFuc2Zvcm0oeyAnYSc6IDEsICdiJzogMiwgJ2MnOiAzIH0sIGZ1bmN0aW9uKHJlc3VsdCwgbnVtLCBrZXkpIHtcbiAgICAgKiAgIHJlc3VsdFtrZXldID0gbnVtICogMztcbiAgICAgKiB9KTtcbiAgICAgKiAvLyA9PiB7ICdhJzogMywgJ2InOiA2LCAnYyc6IDkgfVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIHRyYW5zZm9ybShvYmplY3QsIGNhbGxiYWNrLCBhY2N1bXVsYXRvciwgdGhpc0FyZykge1xuICAgICAgdmFyIGlzQXJyID0gaXNBcnJheShvYmplY3QpO1xuICAgICAgY2FsbGJhY2sgPSBsb2Rhc2guY3JlYXRlQ2FsbGJhY2soY2FsbGJhY2ssIHRoaXNBcmcsIDQpO1xuXG4gICAgICBpZiAoYWNjdW11bGF0b3IgPT0gbnVsbCkge1xuICAgICAgICBpZiAoaXNBcnIpIHtcbiAgICAgICAgICBhY2N1bXVsYXRvciA9IFtdO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHZhciBjdG9yID0gb2JqZWN0ICYmIG9iamVjdC5jb25zdHJ1Y3RvcixcbiAgICAgICAgICAgICAgcHJvdG8gPSBjdG9yICYmIGN0b3IucHJvdG90eXBlO1xuXG4gICAgICAgICAgYWNjdW11bGF0b3IgPSBjcmVhdGVPYmplY3QocHJvdG8pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICAoaXNBcnIgPyBmb3JFYWNoIDogZm9yT3duKShvYmplY3QsIGZ1bmN0aW9uKHZhbHVlLCBpbmRleCwgb2JqZWN0KSB7XG4gICAgICAgIHJldHVybiBjYWxsYmFjayhhY2N1bXVsYXRvciwgdmFsdWUsIGluZGV4LCBvYmplY3QpO1xuICAgICAgfSk7XG4gICAgICByZXR1cm4gYWNjdW11bGF0b3I7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhbiBhcnJheSBjb21wb3NlZCBvZiB0aGUgb3duIGVudW1lcmFibGUgcHJvcGVydHkgdmFsdWVzIG9mIGBvYmplY3RgLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IE9iamVjdHNcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0IFRoZSBvYmplY3QgdG8gaW5zcGVjdC5cbiAgICAgKiBAcmV0dXJucyB7QXJyYXl9IFJldHVybnMgYSBuZXcgYXJyYXkgb2YgcHJvcGVydHkgdmFsdWVzLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLnZhbHVlcyh7ICdvbmUnOiAxLCAndHdvJzogMiwgJ3RocmVlJzogMyB9KTtcbiAgICAgKiAvLyA9PiBbMSwgMiwgM10gKG9yZGVyIGlzIG5vdCBndWFyYW50ZWVkKVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIHZhbHVlcyhvYmplY3QpIHtcbiAgICAgIHZhciBpbmRleCA9IC0xLFxuICAgICAgICAgIHByb3BzID0ga2V5cyhvYmplY3QpLFxuICAgICAgICAgIGxlbmd0aCA9IHByb3BzLmxlbmd0aCxcbiAgICAgICAgICByZXN1bHQgPSBBcnJheShsZW5ndGgpO1xuXG4gICAgICB3aGlsZSAoKytpbmRleCA8IGxlbmd0aCkge1xuICAgICAgICByZXN1bHRbaW5kZXhdID0gb2JqZWN0W3Byb3BzW2luZGV4XV07XG4gICAgICB9XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIC8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhbiBhcnJheSBvZiBlbGVtZW50cyBmcm9tIHRoZSBzcGVjaWZpZWQgaW5kZXhlcywgb3Iga2V5cywgb2YgdGhlXG4gICAgICogYGNvbGxlY3Rpb25gLiBJbmRleGVzIG1heSBiZSBzcGVjaWZpZWQgYXMgaW5kaXZpZHVhbCBhcmd1bWVudHMgb3IgYXMgYXJyYXlzXG4gICAgICogb2YgaW5kZXhlcy5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBDb2xsZWN0aW9uc1xuICAgICAqIEBwYXJhbSB7QXJyYXl8T2JqZWN0fFN0cmluZ30gY29sbGVjdGlvbiBUaGUgY29sbGVjdGlvbiB0byBpdGVyYXRlIG92ZXIuXG4gICAgICogQHBhcmFtIHtBcnJheXxOdW1iZXJ8U3RyaW5nfSBbaW5kZXgxLCBpbmRleDIsIC4uLl0gVGhlIGluZGV4ZXMgb2ZcbiAgICAgKiAgYGNvbGxlY3Rpb25gIHRvIHJldHJpZXZlLCBlaXRoZXIgYXMgaW5kaXZpZHVhbCBhcmd1bWVudHMgb3IgYXJyYXlzLlxuICAgICAqIEByZXR1cm5zIHtBcnJheX0gUmV0dXJucyBhIG5ldyBhcnJheSBvZiBlbGVtZW50cyBjb3JyZXNwb25kaW5nIHRvIHRoZVxuICAgICAqICBwcm92aWRlZCBpbmRleGVzLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLmF0KFsnYScsICdiJywgJ2MnLCAnZCcsICdlJ10sIFswLCAyLCA0XSk7XG4gICAgICogLy8gPT4gWydhJywgJ2MnLCAnZSddXG4gICAgICpcbiAgICAgKiBfLmF0KFsnbW9lJywgJ2xhcnJ5JywgJ2N1cmx5J10sIDAsIDIpO1xuICAgICAqIC8vID0+IFsnbW9lJywgJ2N1cmx5J11cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBhdChjb2xsZWN0aW9uKSB7XG4gICAgICB2YXIgaW5kZXggPSAtMSxcbiAgICAgICAgICBwcm9wcyA9IGNvbmNhdC5hcHBseShhcnJheVJlZiwgbmF0aXZlU2xpY2UuY2FsbChhcmd1bWVudHMsIDEpKSxcbiAgICAgICAgICBsZW5ndGggPSBwcm9wcy5sZW5ndGgsXG4gICAgICAgICAgcmVzdWx0ID0gQXJyYXkobGVuZ3RoKTtcblxuICAgICAgd2hpbGUoKytpbmRleCA8IGxlbmd0aCkge1xuICAgICAgICByZXN1bHRbaW5kZXhdID0gY29sbGVjdGlvbltwcm9wc1tpbmRleF1dO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDaGVja3MgaWYgYSBnaXZlbiBgdGFyZ2V0YCBlbGVtZW50IGlzIHByZXNlbnQgaW4gYSBgY29sbGVjdGlvbmAgdXNpbmcgc3RyaWN0XG4gICAgICogZXF1YWxpdHkgZm9yIGNvbXBhcmlzb25zLCBpLmUuIGA9PT1gLiBJZiBgZnJvbUluZGV4YCBpcyBuZWdhdGl2ZSwgaXQgaXMgdXNlZFxuICAgICAqIGFzIHRoZSBvZmZzZXQgZnJvbSB0aGUgZW5kIG9mIHRoZSBjb2xsZWN0aW9uLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGFsaWFzIGluY2x1ZGVcbiAgICAgKiBAY2F0ZWdvcnkgQ29sbGVjdGlvbnNcbiAgICAgKiBAcGFyYW0ge0FycmF5fE9iamVjdHxTdHJpbmd9IGNvbGxlY3Rpb24gVGhlIGNvbGxlY3Rpb24gdG8gaXRlcmF0ZSBvdmVyLlxuICAgICAqIEBwYXJhbSB7TWl4ZWR9IHRhcmdldCBUaGUgdmFsdWUgdG8gY2hlY2sgZm9yLlxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSBbZnJvbUluZGV4PTBdIFRoZSBpbmRleCB0byBzZWFyY2ggZnJvbS5cbiAgICAgKiBAcmV0dXJucyB7Qm9vbGVhbn0gUmV0dXJucyBgdHJ1ZWAgaWYgdGhlIGB0YXJnZXRgIGVsZW1lbnQgaXMgZm91bmQsIGVsc2UgYGZhbHNlYC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5jb250YWlucyhbMSwgMiwgM10sIDEpO1xuICAgICAqIC8vID0+IHRydWVcbiAgICAgKlxuICAgICAqIF8uY29udGFpbnMoWzEsIDIsIDNdLCAxLCAyKTtcbiAgICAgKiAvLyA9PiBmYWxzZVxuICAgICAqXG4gICAgICogXy5jb250YWlucyh7ICduYW1lJzogJ21vZScsICdhZ2UnOiA0MCB9LCAnbW9lJyk7XG4gICAgICogLy8gPT4gdHJ1ZVxuICAgICAqXG4gICAgICogXy5jb250YWlucygnY3VybHknLCAndXInKTtcbiAgICAgKiAvLyA9PiB0cnVlXG4gICAgICovXG4gICAgZnVuY3Rpb24gY29udGFpbnMoY29sbGVjdGlvbiwgdGFyZ2V0LCBmcm9tSW5kZXgpIHtcbiAgICAgIHZhciBpbmRleCA9IC0xLFxuICAgICAgICAgIGluZGV4T2YgPSBnZXRJbmRleE9mKCksXG4gICAgICAgICAgbGVuZ3RoID0gY29sbGVjdGlvbiA/IGNvbGxlY3Rpb24ubGVuZ3RoIDogMCxcbiAgICAgICAgICByZXN1bHQgPSBmYWxzZTtcblxuICAgICAgZnJvbUluZGV4ID0gKGZyb21JbmRleCA8IDAgPyBuYXRpdmVNYXgoMCwgbGVuZ3RoICsgZnJvbUluZGV4KSA6IGZyb21JbmRleCkgfHwgMDtcbiAgICAgIGlmIChsZW5ndGggJiYgdHlwZW9mIGxlbmd0aCA9PSAnbnVtYmVyJykge1xuICAgICAgICByZXN1bHQgPSAoaXNTdHJpbmcoY29sbGVjdGlvbilcbiAgICAgICAgICA/IGNvbGxlY3Rpb24uaW5kZXhPZih0YXJnZXQsIGZyb21JbmRleClcbiAgICAgICAgICA6IGluZGV4T2YoY29sbGVjdGlvbiwgdGFyZ2V0LCBmcm9tSW5kZXgpXG4gICAgICAgICkgPiAtMTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGZvck93bihjb2xsZWN0aW9uLCBmdW5jdGlvbih2YWx1ZSkge1xuICAgICAgICAgIGlmICgrK2luZGV4ID49IGZyb21JbmRleCkge1xuICAgICAgICAgICAgcmV0dXJuICEocmVzdWx0ID0gdmFsdWUgPT09IHRhcmdldCk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhbiBvYmplY3QgY29tcG9zZWQgb2Yga2V5cyByZXR1cm5lZCBmcm9tIHJ1bm5pbmcgZWFjaCBlbGVtZW50IG9mIHRoZVxuICAgICAqIGBjb2xsZWN0aW9uYCB0aHJvdWdoIHRoZSBnaXZlbiBgY2FsbGJhY2tgLiBUaGUgY29ycmVzcG9uZGluZyB2YWx1ZSBvZiBlYWNoIGtleVxuICAgICAqIGlzIHRoZSBudW1iZXIgb2YgdGltZXMgdGhlIGtleSB3YXMgcmV0dXJuZWQgYnkgdGhlIGBjYWxsYmFja2AuIFRoZSBgY2FsbGJhY2tgXG4gICAgICogaXMgYm91bmQgdG8gYHRoaXNBcmdgIGFuZCBpbnZva2VkIHdpdGggdGhyZWUgYXJndW1lbnRzOyAodmFsdWUsIGluZGV4fGtleSwgY29sbGVjdGlvbikuXG4gICAgICpcbiAgICAgKiBJZiBhIHByb3BlcnR5IG5hbWUgaXMgcGFzc2VkIGZvciBgY2FsbGJhY2tgLCB0aGUgY3JlYXRlZCBcIl8ucGx1Y2tcIiBzdHlsZVxuICAgICAqIGNhbGxiYWNrIHdpbGwgcmV0dXJuIHRoZSBwcm9wZXJ0eSB2YWx1ZSBvZiB0aGUgZ2l2ZW4gZWxlbWVudC5cbiAgICAgKlxuICAgICAqIElmIGFuIG9iamVjdCBpcyBwYXNzZWQgZm9yIGBjYWxsYmFja2AsIHRoZSBjcmVhdGVkIFwiXy53aGVyZVwiIHN0eWxlIGNhbGxiYWNrXG4gICAgICogd2lsbCByZXR1cm4gYHRydWVgIGZvciBlbGVtZW50cyB0aGF0IGhhdmUgdGhlIHByb3BlcnRpZXMgb2YgdGhlIGdpdmVuIG9iamVjdCxcbiAgICAgKiBlbHNlIGBmYWxzZWAuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgQ29sbGVjdGlvbnNcbiAgICAgKiBAcGFyYW0ge0FycmF5fE9iamVjdHxTdHJpbmd9IGNvbGxlY3Rpb24gVGhlIGNvbGxlY3Rpb24gdG8gaXRlcmF0ZSBvdmVyLlxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb258T2JqZWN0fFN0cmluZ30gW2NhbGxiYWNrPWlkZW50aXR5XSBUaGUgZnVuY3Rpb24gY2FsbGVkIHBlclxuICAgICAqICBpdGVyYXRpb24uIElmIGEgcHJvcGVydHkgbmFtZSBvciBvYmplY3QgaXMgcGFzc2VkLCBpdCB3aWxsIGJlIHVzZWQgdG8gY3JlYXRlXG4gICAgICogIGEgXCJfLnBsdWNrXCIgb3IgXCJfLndoZXJlXCIgc3R5bGUgY2FsbGJhY2ssIHJlc3BlY3RpdmVseS5cbiAgICAgKiBAcGFyYW0ge01peGVkfSBbdGhpc0FyZ10gVGhlIGB0aGlzYCBiaW5kaW5nIG9mIGBjYWxsYmFja2AuXG4gICAgICogQHJldHVybnMge09iamVjdH0gUmV0dXJucyB0aGUgY29tcG9zZWQgYWdncmVnYXRlIG9iamVjdC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5jb3VudEJ5KFs0LjMsIDYuMSwgNi40XSwgZnVuY3Rpb24obnVtKSB7IHJldHVybiBNYXRoLmZsb29yKG51bSk7IH0pO1xuICAgICAqIC8vID0+IHsgJzQnOiAxLCAnNic6IDIgfVxuICAgICAqXG4gICAgICogXy5jb3VudEJ5KFs0LjMsIDYuMSwgNi40XSwgZnVuY3Rpb24obnVtKSB7IHJldHVybiB0aGlzLmZsb29yKG51bSk7IH0sIE1hdGgpO1xuICAgICAqIC8vID0+IHsgJzQnOiAxLCAnNic6IDIgfVxuICAgICAqXG4gICAgICogXy5jb3VudEJ5KFsnb25lJywgJ3R3bycsICd0aHJlZSddLCAnbGVuZ3RoJyk7XG4gICAgICogLy8gPT4geyAnMyc6IDIsICc1JzogMSB9XG4gICAgICovXG4gICAgZnVuY3Rpb24gY291bnRCeShjb2xsZWN0aW9uLCBjYWxsYmFjaywgdGhpc0FyZykge1xuICAgICAgdmFyIHJlc3VsdCA9IHt9O1xuICAgICAgY2FsbGJhY2sgPSBsb2Rhc2guY3JlYXRlQ2FsbGJhY2soY2FsbGJhY2ssIHRoaXNBcmcpO1xuXG4gICAgICBmb3JFYWNoKGNvbGxlY3Rpb24sIGZ1bmN0aW9uKHZhbHVlLCBrZXksIGNvbGxlY3Rpb24pIHtcbiAgICAgICAga2V5ID0gU3RyaW5nKGNhbGxiYWNrKHZhbHVlLCBrZXksIGNvbGxlY3Rpb24pKTtcbiAgICAgICAgKGhhc093blByb3BlcnR5LmNhbGwocmVzdWx0LCBrZXkpID8gcmVzdWx0W2tleV0rKyA6IHJlc3VsdFtrZXldID0gMSk7XG4gICAgICB9KTtcbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2hlY2tzIGlmIHRoZSBgY2FsbGJhY2tgIHJldHVybnMgYSB0cnV0aHkgdmFsdWUgZm9yICoqYWxsKiogZWxlbWVudHMgb2YgYVxuICAgICAqIGBjb2xsZWN0aW9uYC4gVGhlIGBjYWxsYmFja2AgaXMgYm91bmQgdG8gYHRoaXNBcmdgIGFuZCBpbnZva2VkIHdpdGggdGhyZWVcbiAgICAgKiBhcmd1bWVudHM7ICh2YWx1ZSwgaW5kZXh8a2V5LCBjb2xsZWN0aW9uKS5cbiAgICAgKlxuICAgICAqIElmIGEgcHJvcGVydHkgbmFtZSBpcyBwYXNzZWQgZm9yIGBjYWxsYmFja2AsIHRoZSBjcmVhdGVkIFwiXy5wbHVja1wiIHN0eWxlXG4gICAgICogY2FsbGJhY2sgd2lsbCByZXR1cm4gdGhlIHByb3BlcnR5IHZhbHVlIG9mIHRoZSBnaXZlbiBlbGVtZW50LlxuICAgICAqXG4gICAgICogSWYgYW4gb2JqZWN0IGlzIHBhc3NlZCBmb3IgYGNhbGxiYWNrYCwgdGhlIGNyZWF0ZWQgXCJfLndoZXJlXCIgc3R5bGUgY2FsbGJhY2tcbiAgICAgKiB3aWxsIHJldHVybiBgdHJ1ZWAgZm9yIGVsZW1lbnRzIHRoYXQgaGF2ZSB0aGUgcHJvcGVydGllcyBvZiB0aGUgZ2l2ZW4gb2JqZWN0LFxuICAgICAqIGVsc2UgYGZhbHNlYC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBhbGlhcyBhbGxcbiAgICAgKiBAY2F0ZWdvcnkgQ29sbGVjdGlvbnNcbiAgICAgKiBAcGFyYW0ge0FycmF5fE9iamVjdHxTdHJpbmd9IGNvbGxlY3Rpb24gVGhlIGNvbGxlY3Rpb24gdG8gaXRlcmF0ZSBvdmVyLlxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb258T2JqZWN0fFN0cmluZ30gW2NhbGxiYWNrPWlkZW50aXR5XSBUaGUgZnVuY3Rpb24gY2FsbGVkIHBlclxuICAgICAqICBpdGVyYXRpb24uIElmIGEgcHJvcGVydHkgbmFtZSBvciBvYmplY3QgaXMgcGFzc2VkLCBpdCB3aWxsIGJlIHVzZWQgdG8gY3JlYXRlXG4gICAgICogIGEgXCJfLnBsdWNrXCIgb3IgXCJfLndoZXJlXCIgc3R5bGUgY2FsbGJhY2ssIHJlc3BlY3RpdmVseS5cbiAgICAgKiBAcGFyYW0ge01peGVkfSBbdGhpc0FyZ10gVGhlIGB0aGlzYCBiaW5kaW5nIG9mIGBjYWxsYmFja2AuXG4gICAgICogQHJldHVybnMge0Jvb2xlYW59IFJldHVybnMgYHRydWVgIGlmIGFsbCBlbGVtZW50cyBwYXNzIHRoZSBjYWxsYmFjayBjaGVjayxcbiAgICAgKiAgZWxzZSBgZmFsc2VgLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLmV2ZXJ5KFt0cnVlLCAxLCBudWxsLCAneWVzJ10sIEJvb2xlYW4pO1xuICAgICAqIC8vID0+IGZhbHNlXG4gICAgICpcbiAgICAgKiB2YXIgc3Rvb2dlcyA9IFtcbiAgICAgKiAgIHsgJ25hbWUnOiAnbW9lJywgJ2FnZSc6IDQwIH0sXG4gICAgICogICB7ICduYW1lJzogJ2xhcnJ5JywgJ2FnZSc6IDUwIH1cbiAgICAgKiBdO1xuICAgICAqXG4gICAgICogLy8gdXNpbmcgXCJfLnBsdWNrXCIgY2FsbGJhY2sgc2hvcnRoYW5kXG4gICAgICogXy5ldmVyeShzdG9vZ2VzLCAnYWdlJyk7XG4gICAgICogLy8gPT4gdHJ1ZVxuICAgICAqXG4gICAgICogLy8gdXNpbmcgXCJfLndoZXJlXCIgY2FsbGJhY2sgc2hvcnRoYW5kXG4gICAgICogXy5ldmVyeShzdG9vZ2VzLCB7ICdhZ2UnOiA1MCB9KTtcbiAgICAgKiAvLyA9PiBmYWxzZVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGV2ZXJ5KGNvbGxlY3Rpb24sIGNhbGxiYWNrLCB0aGlzQXJnKSB7XG4gICAgICB2YXIgcmVzdWx0ID0gdHJ1ZTtcbiAgICAgIGNhbGxiYWNrID0gbG9kYXNoLmNyZWF0ZUNhbGxiYWNrKGNhbGxiYWNrLCB0aGlzQXJnKTtcblxuICAgICAgdmFyIGluZGV4ID0gLTEsXG4gICAgICAgICAgbGVuZ3RoID0gY29sbGVjdGlvbiA/IGNvbGxlY3Rpb24ubGVuZ3RoIDogMDtcblxuICAgICAgaWYgKHR5cGVvZiBsZW5ndGggPT0gJ251bWJlcicpIHtcbiAgICAgICAgd2hpbGUgKCsraW5kZXggPCBsZW5ndGgpIHtcbiAgICAgICAgICBpZiAoIShyZXN1bHQgPSAhIWNhbGxiYWNrKGNvbGxlY3Rpb25baW5kZXhdLCBpbmRleCwgY29sbGVjdGlvbikpKSB7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGZvck93bihjb2xsZWN0aW9uLCBmdW5jdGlvbih2YWx1ZSwgaW5kZXgsIGNvbGxlY3Rpb24pIHtcbiAgICAgICAgICByZXR1cm4gKHJlc3VsdCA9ICEhY2FsbGJhY2sodmFsdWUsIGluZGV4LCBjb2xsZWN0aW9uKSk7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBFeGFtaW5lcyBlYWNoIGVsZW1lbnQgaW4gYSBgY29sbGVjdGlvbmAsIHJldHVybmluZyBhbiBhcnJheSBvZiBhbGwgZWxlbWVudHNcbiAgICAgKiB0aGUgYGNhbGxiYWNrYCByZXR1cm5zIHRydXRoeSBmb3IuIFRoZSBgY2FsbGJhY2tgIGlzIGJvdW5kIHRvIGB0aGlzQXJnYCBhbmRcbiAgICAgKiBpbnZva2VkIHdpdGggdGhyZWUgYXJndW1lbnRzOyAodmFsdWUsIGluZGV4fGtleSwgY29sbGVjdGlvbikuXG4gICAgICpcbiAgICAgKiBJZiBhIHByb3BlcnR5IG5hbWUgaXMgcGFzc2VkIGZvciBgY2FsbGJhY2tgLCB0aGUgY3JlYXRlZCBcIl8ucGx1Y2tcIiBzdHlsZVxuICAgICAqIGNhbGxiYWNrIHdpbGwgcmV0dXJuIHRoZSBwcm9wZXJ0eSB2YWx1ZSBvZiB0aGUgZ2l2ZW4gZWxlbWVudC5cbiAgICAgKlxuICAgICAqIElmIGFuIG9iamVjdCBpcyBwYXNzZWQgZm9yIGBjYWxsYmFja2AsIHRoZSBjcmVhdGVkIFwiXy53aGVyZVwiIHN0eWxlIGNhbGxiYWNrXG4gICAgICogd2lsbCByZXR1cm4gYHRydWVgIGZvciBlbGVtZW50cyB0aGF0IGhhdmUgdGhlIHByb3BlcnRpZXMgb2YgdGhlIGdpdmVuIG9iamVjdCxcbiAgICAgKiBlbHNlIGBmYWxzZWAuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAYWxpYXMgc2VsZWN0XG4gICAgICogQGNhdGVnb3J5IENvbGxlY3Rpb25zXG4gICAgICogQHBhcmFtIHtBcnJheXxPYmplY3R8U3RyaW5nfSBjb2xsZWN0aW9uIFRoZSBjb2xsZWN0aW9uIHRvIGl0ZXJhdGUgb3Zlci5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufE9iamVjdHxTdHJpbmd9IFtjYWxsYmFjaz1pZGVudGl0eV0gVGhlIGZ1bmN0aW9uIGNhbGxlZCBwZXJcbiAgICAgKiAgaXRlcmF0aW9uLiBJZiBhIHByb3BlcnR5IG5hbWUgb3Igb2JqZWN0IGlzIHBhc3NlZCwgaXQgd2lsbCBiZSB1c2VkIHRvIGNyZWF0ZVxuICAgICAqICBhIFwiXy5wbHVja1wiIG9yIFwiXy53aGVyZVwiIHN0eWxlIGNhbGxiYWNrLCByZXNwZWN0aXZlbHkuXG4gICAgICogQHBhcmFtIHtNaXhlZH0gW3RoaXNBcmddIFRoZSBgdGhpc2AgYmluZGluZyBvZiBgY2FsbGJhY2tgLlxuICAgICAqIEByZXR1cm5zIHtBcnJheX0gUmV0dXJucyBhIG5ldyBhcnJheSBvZiBlbGVtZW50cyB0aGF0IHBhc3NlZCB0aGUgY2FsbGJhY2sgY2hlY2suXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIHZhciBldmVucyA9IF8uZmlsdGVyKFsxLCAyLCAzLCA0LCA1LCA2XSwgZnVuY3Rpb24obnVtKSB7IHJldHVybiBudW0gJSAyID09IDA7IH0pO1xuICAgICAqIC8vID0+IFsyLCA0LCA2XVxuICAgICAqXG4gICAgICogdmFyIGZvb2QgPSBbXG4gICAgICogICB7ICduYW1lJzogJ2FwcGxlJywgICdvcmdhbmljJzogZmFsc2UsICd0eXBlJzogJ2ZydWl0JyB9LFxuICAgICAqICAgeyAnbmFtZSc6ICdjYXJyb3QnLCAnb3JnYW5pYyc6IHRydWUsICAndHlwZSc6ICd2ZWdldGFibGUnIH1cbiAgICAgKiBdO1xuICAgICAqXG4gICAgICogLy8gdXNpbmcgXCJfLnBsdWNrXCIgY2FsbGJhY2sgc2hvcnRoYW5kXG4gICAgICogXy5maWx0ZXIoZm9vZCwgJ29yZ2FuaWMnKTtcbiAgICAgKiAvLyA9PiBbeyAnbmFtZSc6ICdjYXJyb3QnLCAnb3JnYW5pYyc6IHRydWUsICd0eXBlJzogJ3ZlZ2V0YWJsZScgfV1cbiAgICAgKlxuICAgICAqIC8vIHVzaW5nIFwiXy53aGVyZVwiIGNhbGxiYWNrIHNob3J0aGFuZFxuICAgICAqIF8uZmlsdGVyKGZvb2QsIHsgJ3R5cGUnOiAnZnJ1aXQnIH0pO1xuICAgICAqIC8vID0+IFt7ICduYW1lJzogJ2FwcGxlJywgJ29yZ2FuaWMnOiBmYWxzZSwgJ3R5cGUnOiAnZnJ1aXQnIH1dXG4gICAgICovXG4gICAgZnVuY3Rpb24gZmlsdGVyKGNvbGxlY3Rpb24sIGNhbGxiYWNrLCB0aGlzQXJnKSB7XG4gICAgICB2YXIgcmVzdWx0ID0gW107XG4gICAgICBjYWxsYmFjayA9IGxvZGFzaC5jcmVhdGVDYWxsYmFjayhjYWxsYmFjaywgdGhpc0FyZyk7XG5cbiAgICAgIHZhciBpbmRleCA9IC0xLFxuICAgICAgICAgIGxlbmd0aCA9IGNvbGxlY3Rpb24gPyBjb2xsZWN0aW9uLmxlbmd0aCA6IDA7XG5cbiAgICAgIGlmICh0eXBlb2YgbGVuZ3RoID09ICdudW1iZXInKSB7XG4gICAgICAgIHdoaWxlICgrK2luZGV4IDwgbGVuZ3RoKSB7XG4gICAgICAgICAgdmFyIHZhbHVlID0gY29sbGVjdGlvbltpbmRleF07XG4gICAgICAgICAgaWYgKGNhbGxiYWNrKHZhbHVlLCBpbmRleCwgY29sbGVjdGlvbikpIHtcbiAgICAgICAgICAgIHJlc3VsdC5wdXNoKHZhbHVlKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGZvck93bihjb2xsZWN0aW9uLCBmdW5jdGlvbih2YWx1ZSwgaW5kZXgsIGNvbGxlY3Rpb24pIHtcbiAgICAgICAgICBpZiAoY2FsbGJhY2sodmFsdWUsIGluZGV4LCBjb2xsZWN0aW9uKSkge1xuICAgICAgICAgICAgcmVzdWx0LnB1c2godmFsdWUpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEV4YW1pbmVzIGVhY2ggZWxlbWVudCBpbiBhIGBjb2xsZWN0aW9uYCwgcmV0dXJuaW5nIHRoZSBmaXJzdCB0aGF0IHRoZSBgY2FsbGJhY2tgXG4gICAgICogcmV0dXJucyB0cnV0aHkgZm9yLiBUaGUgYGNhbGxiYWNrYCBpcyBib3VuZCB0byBgdGhpc0FyZ2AgYW5kIGludm9rZWQgd2l0aCB0aHJlZVxuICAgICAqIGFyZ3VtZW50czsgKHZhbHVlLCBpbmRleHxrZXksIGNvbGxlY3Rpb24pLlxuICAgICAqXG4gICAgICogSWYgYSBwcm9wZXJ0eSBuYW1lIGlzIHBhc3NlZCBmb3IgYGNhbGxiYWNrYCwgdGhlIGNyZWF0ZWQgXCJfLnBsdWNrXCIgc3R5bGVcbiAgICAgKiBjYWxsYmFjayB3aWxsIHJldHVybiB0aGUgcHJvcGVydHkgdmFsdWUgb2YgdGhlIGdpdmVuIGVsZW1lbnQuXG4gICAgICpcbiAgICAgKiBJZiBhbiBvYmplY3QgaXMgcGFzc2VkIGZvciBgY2FsbGJhY2tgLCB0aGUgY3JlYXRlZCBcIl8ud2hlcmVcIiBzdHlsZSBjYWxsYmFja1xuICAgICAqIHdpbGwgcmV0dXJuIGB0cnVlYCBmb3IgZWxlbWVudHMgdGhhdCBoYXZlIHRoZSBwcm9wZXJ0aWVzIG9mIHRoZSBnaXZlbiBvYmplY3QsXG4gICAgICogZWxzZSBgZmFsc2VgLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGFsaWFzIGRldGVjdCwgZmluZFdoZXJlXG4gICAgICogQGNhdGVnb3J5IENvbGxlY3Rpb25zXG4gICAgICogQHBhcmFtIHtBcnJheXxPYmplY3R8U3RyaW5nfSBjb2xsZWN0aW9uIFRoZSBjb2xsZWN0aW9uIHRvIGl0ZXJhdGUgb3Zlci5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufE9iamVjdHxTdHJpbmd9IFtjYWxsYmFjaz1pZGVudGl0eV0gVGhlIGZ1bmN0aW9uIGNhbGxlZCBwZXJcbiAgICAgKiAgaXRlcmF0aW9uLiBJZiBhIHByb3BlcnR5IG5hbWUgb3Igb2JqZWN0IGlzIHBhc3NlZCwgaXQgd2lsbCBiZSB1c2VkIHRvIGNyZWF0ZVxuICAgICAqICBhIFwiXy5wbHVja1wiIG9yIFwiXy53aGVyZVwiIHN0eWxlIGNhbGxiYWNrLCByZXNwZWN0aXZlbHkuXG4gICAgICogQHBhcmFtIHtNaXhlZH0gW3RoaXNBcmddIFRoZSBgdGhpc2AgYmluZGluZyBvZiBgY2FsbGJhY2tgLlxuICAgICAqIEByZXR1cm5zIHtNaXhlZH0gUmV0dXJucyB0aGUgZm91bmQgZWxlbWVudCwgZWxzZSBgdW5kZWZpbmVkYC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5maW5kKFsxLCAyLCAzLCA0XSwgZnVuY3Rpb24obnVtKSB7XG4gICAgICogICByZXR1cm4gbnVtICUgMiA9PSAwO1xuICAgICAqIH0pO1xuICAgICAqIC8vID0+IDJcbiAgICAgKlxuICAgICAqIHZhciBmb29kID0gW1xuICAgICAqICAgeyAnbmFtZSc6ICdhcHBsZScsICAnb3JnYW5pYyc6IGZhbHNlLCAndHlwZSc6ICdmcnVpdCcgfSxcbiAgICAgKiAgIHsgJ25hbWUnOiAnYmFuYW5hJywgJ29yZ2FuaWMnOiB0cnVlLCAgJ3R5cGUnOiAnZnJ1aXQnIH0sXG4gICAgICogICB7ICduYW1lJzogJ2JlZXQnLCAgICdvcmdhbmljJzogZmFsc2UsICd0eXBlJzogJ3ZlZ2V0YWJsZScgfVxuICAgICAqIF07XG4gICAgICpcbiAgICAgKiAvLyB1c2luZyBcIl8ud2hlcmVcIiBjYWxsYmFjayBzaG9ydGhhbmRcbiAgICAgKiBfLmZpbmQoZm9vZCwgeyAndHlwZSc6ICd2ZWdldGFibGUnIH0pO1xuICAgICAqIC8vID0+IHsgJ25hbWUnOiAnYmVldCcsICdvcmdhbmljJzogZmFsc2UsICd0eXBlJzogJ3ZlZ2V0YWJsZScgfVxuICAgICAqXG4gICAgICogLy8gdXNpbmcgXCJfLnBsdWNrXCIgY2FsbGJhY2sgc2hvcnRoYW5kXG4gICAgICogXy5maW5kKGZvb2QsICdvcmdhbmljJyk7XG4gICAgICogLy8gPT4geyAnbmFtZSc6ICdiYW5hbmEnLCAnb3JnYW5pYyc6IHRydWUsICd0eXBlJzogJ2ZydWl0JyB9XG4gICAgICovXG4gICAgZnVuY3Rpb24gZmluZChjb2xsZWN0aW9uLCBjYWxsYmFjaywgdGhpc0FyZykge1xuICAgICAgY2FsbGJhY2sgPSBsb2Rhc2guY3JlYXRlQ2FsbGJhY2soY2FsbGJhY2ssIHRoaXNBcmcpO1xuXG4gICAgICB2YXIgaW5kZXggPSAtMSxcbiAgICAgICAgICBsZW5ndGggPSBjb2xsZWN0aW9uID8gY29sbGVjdGlvbi5sZW5ndGggOiAwO1xuXG4gICAgICBpZiAodHlwZW9mIGxlbmd0aCA9PSAnbnVtYmVyJykge1xuICAgICAgICB3aGlsZSAoKytpbmRleCA8IGxlbmd0aCkge1xuICAgICAgICAgIHZhciB2YWx1ZSA9IGNvbGxlY3Rpb25baW5kZXhdO1xuICAgICAgICAgIGlmIChjYWxsYmFjayh2YWx1ZSwgaW5kZXgsIGNvbGxlY3Rpb24pKSB7XG4gICAgICAgICAgICByZXR1cm4gdmFsdWU7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB2YXIgcmVzdWx0O1xuICAgICAgICBmb3JPd24oY29sbGVjdGlvbiwgZnVuY3Rpb24odmFsdWUsIGluZGV4LCBjb2xsZWN0aW9uKSB7XG4gICAgICAgICAgaWYgKGNhbGxiYWNrKHZhbHVlLCBpbmRleCwgY29sbGVjdGlvbikpIHtcbiAgICAgICAgICAgIHJlc3VsdCA9IHZhbHVlO1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSXRlcmF0ZXMgb3ZlciBhIGBjb2xsZWN0aW9uYCwgZXhlY3V0aW5nIHRoZSBgY2FsbGJhY2tgIGZvciBlYWNoIGVsZW1lbnQgaW5cbiAgICAgKiB0aGUgYGNvbGxlY3Rpb25gLiBUaGUgYGNhbGxiYWNrYCBpcyBib3VuZCB0byBgdGhpc0FyZ2AgYW5kIGludm9rZWQgd2l0aCB0aHJlZVxuICAgICAqIGFyZ3VtZW50czsgKHZhbHVlLCBpbmRleHxrZXksIGNvbGxlY3Rpb24pLiBDYWxsYmFja3MgbWF5IGV4aXQgaXRlcmF0aW9uIGVhcmx5XG4gICAgICogYnkgZXhwbGljaXRseSByZXR1cm5pbmcgYGZhbHNlYC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBhbGlhcyBlYWNoXG4gICAgICogQGNhdGVnb3J5IENvbGxlY3Rpb25zXG4gICAgICogQHBhcmFtIHtBcnJheXxPYmplY3R8U3RyaW5nfSBjb2xsZWN0aW9uIFRoZSBjb2xsZWN0aW9uIHRvIGl0ZXJhdGUgb3Zlci5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBbY2FsbGJhY2s9aWRlbnRpdHldIFRoZSBmdW5jdGlvbiBjYWxsZWQgcGVyIGl0ZXJhdGlvbi5cbiAgICAgKiBAcGFyYW0ge01peGVkfSBbdGhpc0FyZ10gVGhlIGB0aGlzYCBiaW5kaW5nIG9mIGBjYWxsYmFja2AuXG4gICAgICogQHJldHVybnMge0FycmF5fE9iamVjdHxTdHJpbmd9IFJldHVybnMgYGNvbGxlY3Rpb25gLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfKFsxLCAyLCAzXSkuZm9yRWFjaChhbGVydCkuam9pbignLCcpO1xuICAgICAqIC8vID0+IGFsZXJ0cyBlYWNoIG51bWJlciBhbmQgcmV0dXJucyAnMSwyLDMnXG4gICAgICpcbiAgICAgKiBfLmZvckVhY2goeyAnb25lJzogMSwgJ3R3byc6IDIsICd0aHJlZSc6IDMgfSwgYWxlcnQpO1xuICAgICAqIC8vID0+IGFsZXJ0cyBlYWNoIG51bWJlciB2YWx1ZSAob3JkZXIgaXMgbm90IGd1YXJhbnRlZWQpXG4gICAgICovXG4gICAgZnVuY3Rpb24gZm9yRWFjaChjb2xsZWN0aW9uLCBjYWxsYmFjaywgdGhpc0FyZykge1xuICAgICAgdmFyIGluZGV4ID0gLTEsXG4gICAgICAgICAgbGVuZ3RoID0gY29sbGVjdGlvbiA/IGNvbGxlY3Rpb24ubGVuZ3RoIDogMDtcblxuICAgICAgY2FsbGJhY2sgPSBjYWxsYmFjayAmJiB0eXBlb2YgdGhpc0FyZyA9PSAndW5kZWZpbmVkJyA/IGNhbGxiYWNrIDogbG9kYXNoLmNyZWF0ZUNhbGxiYWNrKGNhbGxiYWNrLCB0aGlzQXJnKTtcbiAgICAgIGlmICh0eXBlb2YgbGVuZ3RoID09ICdudW1iZXInKSB7XG4gICAgICAgIHdoaWxlICgrK2luZGV4IDwgbGVuZ3RoKSB7XG4gICAgICAgICAgaWYgKGNhbGxiYWNrKGNvbGxlY3Rpb25baW5kZXhdLCBpbmRleCwgY29sbGVjdGlvbikgPT09IGZhbHNlKSB7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGZvck93bihjb2xsZWN0aW9uLCBjYWxsYmFjayk7XG4gICAgICB9XG4gICAgICByZXR1cm4gY29sbGVjdGlvbjtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuIG9iamVjdCBjb21wb3NlZCBvZiBrZXlzIHJldHVybmVkIGZyb20gcnVubmluZyBlYWNoIGVsZW1lbnQgb2YgdGhlXG4gICAgICogYGNvbGxlY3Rpb25gIHRocm91Z2ggdGhlIGBjYWxsYmFja2AuIFRoZSBjb3JyZXNwb25kaW5nIHZhbHVlIG9mIGVhY2gga2V5IGlzXG4gICAgICogYW4gYXJyYXkgb2YgZWxlbWVudHMgcGFzc2VkIHRvIGBjYWxsYmFja2AgdGhhdCByZXR1cm5lZCB0aGUga2V5LiBUaGUgYGNhbGxiYWNrYFxuICAgICAqIGlzIGJvdW5kIHRvIGB0aGlzQXJnYCBhbmQgaW52b2tlZCB3aXRoIHRocmVlIGFyZ3VtZW50czsgKHZhbHVlLCBpbmRleHxrZXksIGNvbGxlY3Rpb24pLlxuICAgICAqXG4gICAgICogSWYgYSBwcm9wZXJ0eSBuYW1lIGlzIHBhc3NlZCBmb3IgYGNhbGxiYWNrYCwgdGhlIGNyZWF0ZWQgXCJfLnBsdWNrXCIgc3R5bGVcbiAgICAgKiBjYWxsYmFjayB3aWxsIHJldHVybiB0aGUgcHJvcGVydHkgdmFsdWUgb2YgdGhlIGdpdmVuIGVsZW1lbnQuXG4gICAgICpcbiAgICAgKiBJZiBhbiBvYmplY3QgaXMgcGFzc2VkIGZvciBgY2FsbGJhY2tgLCB0aGUgY3JlYXRlZCBcIl8ud2hlcmVcIiBzdHlsZSBjYWxsYmFja1xuICAgICAqIHdpbGwgcmV0dXJuIGB0cnVlYCBmb3IgZWxlbWVudHMgdGhhdCBoYXZlIHRoZSBwcm9wZXJ0aWVzIG9mIHRoZSBnaXZlbiBvYmplY3QsXG4gICAgICogZWxzZSBgZmFsc2VgXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgQ29sbGVjdGlvbnNcbiAgICAgKiBAcGFyYW0ge0FycmF5fE9iamVjdHxTdHJpbmd9IGNvbGxlY3Rpb24gVGhlIGNvbGxlY3Rpb24gdG8gaXRlcmF0ZSBvdmVyLlxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb258T2JqZWN0fFN0cmluZ30gW2NhbGxiYWNrPWlkZW50aXR5XSBUaGUgZnVuY3Rpb24gY2FsbGVkIHBlclxuICAgICAqICBpdGVyYXRpb24uIElmIGEgcHJvcGVydHkgbmFtZSBvciBvYmplY3QgaXMgcGFzc2VkLCBpdCB3aWxsIGJlIHVzZWQgdG8gY3JlYXRlXG4gICAgICogIGEgXCJfLnBsdWNrXCIgb3IgXCJfLndoZXJlXCIgc3R5bGUgY2FsbGJhY2ssIHJlc3BlY3RpdmVseS5cbiAgICAgKiBAcGFyYW0ge01peGVkfSBbdGhpc0FyZ10gVGhlIGB0aGlzYCBiaW5kaW5nIG9mIGBjYWxsYmFja2AuXG4gICAgICogQHJldHVybnMge09iamVjdH0gUmV0dXJucyB0aGUgY29tcG9zZWQgYWdncmVnYXRlIG9iamVjdC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5ncm91cEJ5KFs0LjIsIDYuMSwgNi40XSwgZnVuY3Rpb24obnVtKSB7IHJldHVybiBNYXRoLmZsb29yKG51bSk7IH0pO1xuICAgICAqIC8vID0+IHsgJzQnOiBbNC4yXSwgJzYnOiBbNi4xLCA2LjRdIH1cbiAgICAgKlxuICAgICAqIF8uZ3JvdXBCeShbNC4yLCA2LjEsIDYuNF0sIGZ1bmN0aW9uKG51bSkgeyByZXR1cm4gdGhpcy5mbG9vcihudW0pOyB9LCBNYXRoKTtcbiAgICAgKiAvLyA9PiB7ICc0JzogWzQuMl0sICc2JzogWzYuMSwgNi40XSB9XG4gICAgICpcbiAgICAgKiAvLyB1c2luZyBcIl8ucGx1Y2tcIiBjYWxsYmFjayBzaG9ydGhhbmRcbiAgICAgKiBfLmdyb3VwQnkoWydvbmUnLCAndHdvJywgJ3RocmVlJ10sICdsZW5ndGgnKTtcbiAgICAgKiAvLyA9PiB7ICczJzogWydvbmUnLCAndHdvJ10sICc1JzogWyd0aHJlZSddIH1cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBncm91cEJ5KGNvbGxlY3Rpb24sIGNhbGxiYWNrLCB0aGlzQXJnKSB7XG4gICAgICB2YXIgcmVzdWx0ID0ge307XG4gICAgICBjYWxsYmFjayA9IGxvZGFzaC5jcmVhdGVDYWxsYmFjayhjYWxsYmFjaywgdGhpc0FyZyk7XG5cbiAgICAgIGZvckVhY2goY29sbGVjdGlvbiwgZnVuY3Rpb24odmFsdWUsIGtleSwgY29sbGVjdGlvbikge1xuICAgICAgICBrZXkgPSBTdHJpbmcoY2FsbGJhY2sodmFsdWUsIGtleSwgY29sbGVjdGlvbikpO1xuICAgICAgICAoaGFzT3duUHJvcGVydHkuY2FsbChyZXN1bHQsIGtleSkgPyByZXN1bHRba2V5XSA6IHJlc3VsdFtrZXldID0gW10pLnB1c2godmFsdWUpO1xuICAgICAgfSk7XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEludm9rZXMgdGhlIG1ldGhvZCBuYW1lZCBieSBgbWV0aG9kTmFtZWAgb24gZWFjaCBlbGVtZW50IGluIHRoZSBgY29sbGVjdGlvbmAsXG4gICAgICogcmV0dXJuaW5nIGFuIGFycmF5IG9mIHRoZSByZXN1bHRzIG9mIGVhY2ggaW52b2tlZCBtZXRob2QuIEFkZGl0aW9uYWwgYXJndW1lbnRzXG4gICAgICogd2lsbCBiZSBwYXNzZWQgdG8gZWFjaCBpbnZva2VkIG1ldGhvZC4gSWYgYG1ldGhvZE5hbWVgIGlzIGEgZnVuY3Rpb24sIGl0IHdpbGxcbiAgICAgKiBiZSBpbnZva2VkIGZvciwgYW5kIGB0aGlzYCBib3VuZCB0bywgZWFjaCBlbGVtZW50IGluIHRoZSBgY29sbGVjdGlvbmAuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgQ29sbGVjdGlvbnNcbiAgICAgKiBAcGFyYW0ge0FycmF5fE9iamVjdHxTdHJpbmd9IGNvbGxlY3Rpb24gVGhlIGNvbGxlY3Rpb24gdG8gaXRlcmF0ZSBvdmVyLlxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb258U3RyaW5nfSBtZXRob2ROYW1lIFRoZSBuYW1lIG9mIHRoZSBtZXRob2QgdG8gaW52b2tlIG9yXG4gICAgICogIHRoZSBmdW5jdGlvbiBpbnZva2VkIHBlciBpdGVyYXRpb24uXG4gICAgICogQHBhcmFtIHtNaXhlZH0gW2FyZzEsIGFyZzIsIC4uLl0gQXJndW1lbnRzIHRvIGludm9rZSB0aGUgbWV0aG9kIHdpdGguXG4gICAgICogQHJldHVybnMge0FycmF5fSBSZXR1cm5zIGEgbmV3IGFycmF5IG9mIHRoZSByZXN1bHRzIG9mIGVhY2ggaW52b2tlZCBtZXRob2QuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8uaW52b2tlKFtbNSwgMSwgN10sIFszLCAyLCAxXV0sICdzb3J0Jyk7XG4gICAgICogLy8gPT4gW1sxLCA1LCA3XSwgWzEsIDIsIDNdXVxuICAgICAqXG4gICAgICogXy5pbnZva2UoWzEyMywgNDU2XSwgU3RyaW5nLnByb3RvdHlwZS5zcGxpdCwgJycpO1xuICAgICAqIC8vID0+IFtbJzEnLCAnMicsICczJ10sIFsnNCcsICc1JywgJzYnXV1cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBpbnZva2UoY29sbGVjdGlvbiwgbWV0aG9kTmFtZSkge1xuICAgICAgdmFyIGFyZ3MgPSBuYXRpdmVTbGljZS5jYWxsKGFyZ3VtZW50cywgMiksXG4gICAgICAgICAgaW5kZXggPSAtMSxcbiAgICAgICAgICBpc0Z1bmMgPSB0eXBlb2YgbWV0aG9kTmFtZSA9PSAnZnVuY3Rpb24nLFxuICAgICAgICAgIGxlbmd0aCA9IGNvbGxlY3Rpb24gPyBjb2xsZWN0aW9uLmxlbmd0aCA6IDAsXG4gICAgICAgICAgcmVzdWx0ID0gQXJyYXkodHlwZW9mIGxlbmd0aCA9PSAnbnVtYmVyJyA/IGxlbmd0aCA6IDApO1xuXG4gICAgICBmb3JFYWNoKGNvbGxlY3Rpb24sIGZ1bmN0aW9uKHZhbHVlKSB7XG4gICAgICAgIHJlc3VsdFsrK2luZGV4XSA9IChpc0Z1bmMgPyBtZXRob2ROYW1lIDogdmFsdWVbbWV0aG9kTmFtZV0pLmFwcGx5KHZhbHVlLCBhcmdzKTtcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuIGFycmF5IG9mIHZhbHVlcyBieSBydW5uaW5nIGVhY2ggZWxlbWVudCBpbiB0aGUgYGNvbGxlY3Rpb25gXG4gICAgICogdGhyb3VnaCB0aGUgYGNhbGxiYWNrYC4gVGhlIGBjYWxsYmFja2AgaXMgYm91bmQgdG8gYHRoaXNBcmdgIGFuZCBpbnZva2VkIHdpdGhcbiAgICAgKiB0aHJlZSBhcmd1bWVudHM7ICh2YWx1ZSwgaW5kZXh8a2V5LCBjb2xsZWN0aW9uKS5cbiAgICAgKlxuICAgICAqIElmIGEgcHJvcGVydHkgbmFtZSBpcyBwYXNzZWQgZm9yIGBjYWxsYmFja2AsIHRoZSBjcmVhdGVkIFwiXy5wbHVja1wiIHN0eWxlXG4gICAgICogY2FsbGJhY2sgd2lsbCByZXR1cm4gdGhlIHByb3BlcnR5IHZhbHVlIG9mIHRoZSBnaXZlbiBlbGVtZW50LlxuICAgICAqXG4gICAgICogSWYgYW4gb2JqZWN0IGlzIHBhc3NlZCBmb3IgYGNhbGxiYWNrYCwgdGhlIGNyZWF0ZWQgXCJfLndoZXJlXCIgc3R5bGUgY2FsbGJhY2tcbiAgICAgKiB3aWxsIHJldHVybiBgdHJ1ZWAgZm9yIGVsZW1lbnRzIHRoYXQgaGF2ZSB0aGUgcHJvcGVydGllcyBvZiB0aGUgZ2l2ZW4gb2JqZWN0LFxuICAgICAqIGVsc2UgYGZhbHNlYC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBhbGlhcyBjb2xsZWN0XG4gICAgICogQGNhdGVnb3J5IENvbGxlY3Rpb25zXG4gICAgICogQHBhcmFtIHtBcnJheXxPYmplY3R8U3RyaW5nfSBjb2xsZWN0aW9uIFRoZSBjb2xsZWN0aW9uIHRvIGl0ZXJhdGUgb3Zlci5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufE9iamVjdHxTdHJpbmd9IFtjYWxsYmFjaz1pZGVudGl0eV0gVGhlIGZ1bmN0aW9uIGNhbGxlZCBwZXJcbiAgICAgKiAgaXRlcmF0aW9uLiBJZiBhIHByb3BlcnR5IG5hbWUgb3Igb2JqZWN0IGlzIHBhc3NlZCwgaXQgd2lsbCBiZSB1c2VkIHRvIGNyZWF0ZVxuICAgICAqICBhIFwiXy5wbHVja1wiIG9yIFwiXy53aGVyZVwiIHN0eWxlIGNhbGxiYWNrLCByZXNwZWN0aXZlbHkuXG4gICAgICogQHBhcmFtIHtNaXhlZH0gW3RoaXNBcmddIFRoZSBgdGhpc2AgYmluZGluZyBvZiBgY2FsbGJhY2tgLlxuICAgICAqIEByZXR1cm5zIHtBcnJheX0gUmV0dXJucyBhIG5ldyBhcnJheSBvZiB0aGUgcmVzdWx0cyBvZiBlYWNoIGBjYWxsYmFja2AgZXhlY3V0aW9uLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLm1hcChbMSwgMiwgM10sIGZ1bmN0aW9uKG51bSkgeyByZXR1cm4gbnVtICogMzsgfSk7XG4gICAgICogLy8gPT4gWzMsIDYsIDldXG4gICAgICpcbiAgICAgKiBfLm1hcCh7ICdvbmUnOiAxLCAndHdvJzogMiwgJ3RocmVlJzogMyB9LCBmdW5jdGlvbihudW0pIHsgcmV0dXJuIG51bSAqIDM7IH0pO1xuICAgICAqIC8vID0+IFszLCA2LCA5XSAob3JkZXIgaXMgbm90IGd1YXJhbnRlZWQpXG4gICAgICpcbiAgICAgKiB2YXIgc3Rvb2dlcyA9IFtcbiAgICAgKiAgIHsgJ25hbWUnOiAnbW9lJywgJ2FnZSc6IDQwIH0sXG4gICAgICogICB7ICduYW1lJzogJ2xhcnJ5JywgJ2FnZSc6IDUwIH1cbiAgICAgKiBdO1xuICAgICAqXG4gICAgICogLy8gdXNpbmcgXCJfLnBsdWNrXCIgY2FsbGJhY2sgc2hvcnRoYW5kXG4gICAgICogXy5tYXAoc3Rvb2dlcywgJ25hbWUnKTtcbiAgICAgKiAvLyA9PiBbJ21vZScsICdsYXJyeSddXG4gICAgICovXG4gICAgZnVuY3Rpb24gbWFwKGNvbGxlY3Rpb24sIGNhbGxiYWNrLCB0aGlzQXJnKSB7XG4gICAgICB2YXIgaW5kZXggPSAtMSxcbiAgICAgICAgICBsZW5ndGggPSBjb2xsZWN0aW9uID8gY29sbGVjdGlvbi5sZW5ndGggOiAwO1xuXG4gICAgICBjYWxsYmFjayA9IGxvZGFzaC5jcmVhdGVDYWxsYmFjayhjYWxsYmFjaywgdGhpc0FyZyk7XG4gICAgICBpZiAodHlwZW9mIGxlbmd0aCA9PSAnbnVtYmVyJykge1xuICAgICAgICB2YXIgcmVzdWx0ID0gQXJyYXkobGVuZ3RoKTtcbiAgICAgICAgd2hpbGUgKCsraW5kZXggPCBsZW5ndGgpIHtcbiAgICAgICAgICByZXN1bHRbaW5kZXhdID0gY2FsbGJhY2soY29sbGVjdGlvbltpbmRleF0sIGluZGV4LCBjb2xsZWN0aW9uKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmVzdWx0ID0gW107XG4gICAgICAgIGZvck93bihjb2xsZWN0aW9uLCBmdW5jdGlvbih2YWx1ZSwga2V5LCBjb2xsZWN0aW9uKSB7XG4gICAgICAgICAgcmVzdWx0WysraW5kZXhdID0gY2FsbGJhY2sodmFsdWUsIGtleSwgY29sbGVjdGlvbik7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXRyaWV2ZXMgdGhlIG1heGltdW0gdmFsdWUgb2YgYW4gYGFycmF5YC4gSWYgYGNhbGxiYWNrYCBpcyBwYXNzZWQsXG4gICAgICogaXQgd2lsbCBiZSBleGVjdXRlZCBmb3IgZWFjaCB2YWx1ZSBpbiB0aGUgYGFycmF5YCB0byBnZW5lcmF0ZSB0aGVcbiAgICAgKiBjcml0ZXJpb24gYnkgd2hpY2ggdGhlIHZhbHVlIGlzIHJhbmtlZC4gVGhlIGBjYWxsYmFja2AgaXMgYm91bmQgdG9cbiAgICAgKiBgdGhpc0FyZ2AgYW5kIGludm9rZWQgd2l0aCB0aHJlZSBhcmd1bWVudHM7ICh2YWx1ZSwgaW5kZXgsIGNvbGxlY3Rpb24pLlxuICAgICAqXG4gICAgICogSWYgYSBwcm9wZXJ0eSBuYW1lIGlzIHBhc3NlZCBmb3IgYGNhbGxiYWNrYCwgdGhlIGNyZWF0ZWQgXCJfLnBsdWNrXCIgc3R5bGVcbiAgICAgKiBjYWxsYmFjayB3aWxsIHJldHVybiB0aGUgcHJvcGVydHkgdmFsdWUgb2YgdGhlIGdpdmVuIGVsZW1lbnQuXG4gICAgICpcbiAgICAgKiBJZiBhbiBvYmplY3QgaXMgcGFzc2VkIGZvciBgY2FsbGJhY2tgLCB0aGUgY3JlYXRlZCBcIl8ud2hlcmVcIiBzdHlsZSBjYWxsYmFja1xuICAgICAqIHdpbGwgcmV0dXJuIGB0cnVlYCBmb3IgZWxlbWVudHMgdGhhdCBoYXZlIHRoZSBwcm9wZXJ0aWVzIG9mIHRoZSBnaXZlbiBvYmplY3QsXG4gICAgICogZWxzZSBgZmFsc2VgLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IENvbGxlY3Rpb25zXG4gICAgICogQHBhcmFtIHtBcnJheXxPYmplY3R8U3RyaW5nfSBjb2xsZWN0aW9uIFRoZSBjb2xsZWN0aW9uIHRvIGl0ZXJhdGUgb3Zlci5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufE9iamVjdHxTdHJpbmd9IFtjYWxsYmFjaz1pZGVudGl0eV0gVGhlIGZ1bmN0aW9uIGNhbGxlZCBwZXJcbiAgICAgKiAgaXRlcmF0aW9uLiBJZiBhIHByb3BlcnR5IG5hbWUgb3Igb2JqZWN0IGlzIHBhc3NlZCwgaXQgd2lsbCBiZSB1c2VkIHRvIGNyZWF0ZVxuICAgICAqICBhIFwiXy5wbHVja1wiIG9yIFwiXy53aGVyZVwiIHN0eWxlIGNhbGxiYWNrLCByZXNwZWN0aXZlbHkuXG4gICAgICogQHBhcmFtIHtNaXhlZH0gW3RoaXNBcmddIFRoZSBgdGhpc2AgYmluZGluZyBvZiBgY2FsbGJhY2tgLlxuICAgICAqIEByZXR1cm5zIHtNaXhlZH0gUmV0dXJucyB0aGUgbWF4aW11bSB2YWx1ZS5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5tYXgoWzQsIDIsIDgsIDZdKTtcbiAgICAgKiAvLyA9PiA4XG4gICAgICpcbiAgICAgKiB2YXIgc3Rvb2dlcyA9IFtcbiAgICAgKiAgIHsgJ25hbWUnOiAnbW9lJywgJ2FnZSc6IDQwIH0sXG4gICAgICogICB7ICduYW1lJzogJ2xhcnJ5JywgJ2FnZSc6IDUwIH1cbiAgICAgKiBdO1xuICAgICAqXG4gICAgICogXy5tYXgoc3Rvb2dlcywgZnVuY3Rpb24oc3Rvb2dlKSB7IHJldHVybiBzdG9vZ2UuYWdlOyB9KTtcbiAgICAgKiAvLyA9PiB7ICduYW1lJzogJ2xhcnJ5JywgJ2FnZSc6IDUwIH07XG4gICAgICpcbiAgICAgKiAvLyB1c2luZyBcIl8ucGx1Y2tcIiBjYWxsYmFjayBzaG9ydGhhbmRcbiAgICAgKiBfLm1heChzdG9vZ2VzLCAnYWdlJyk7XG4gICAgICogLy8gPT4geyAnbmFtZSc6ICdsYXJyeScsICdhZ2UnOiA1MCB9O1xuICAgICAqL1xuICAgIGZ1bmN0aW9uIG1heChjb2xsZWN0aW9uLCBjYWxsYmFjaywgdGhpc0FyZykge1xuICAgICAgdmFyIGNvbXB1dGVkID0gLUluZmluaXR5LFxuICAgICAgICAgIHJlc3VsdCA9IGNvbXB1dGVkO1xuXG4gICAgICBpZiAoIWNhbGxiYWNrICYmIGlzQXJyYXkoY29sbGVjdGlvbikpIHtcbiAgICAgICAgdmFyIGluZGV4ID0gLTEsXG4gICAgICAgICAgICBsZW5ndGggPSBjb2xsZWN0aW9uLmxlbmd0aDtcblxuICAgICAgICB3aGlsZSAoKytpbmRleCA8IGxlbmd0aCkge1xuICAgICAgICAgIHZhciB2YWx1ZSA9IGNvbGxlY3Rpb25baW5kZXhdO1xuICAgICAgICAgIGlmICh2YWx1ZSA+IHJlc3VsdCkge1xuICAgICAgICAgICAgcmVzdWx0ID0gdmFsdWU7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjYWxsYmFjayA9ICghY2FsbGJhY2sgJiYgaXNTdHJpbmcoY29sbGVjdGlvbikpXG4gICAgICAgICAgPyBjaGFyQXRDYWxsYmFja1xuICAgICAgICAgIDogbG9kYXNoLmNyZWF0ZUNhbGxiYWNrKGNhbGxiYWNrLCB0aGlzQXJnKTtcblxuICAgICAgICBmb3JFYWNoKGNvbGxlY3Rpb24sIGZ1bmN0aW9uKHZhbHVlLCBpbmRleCwgY29sbGVjdGlvbikge1xuICAgICAgICAgIHZhciBjdXJyZW50ID0gY2FsbGJhY2sodmFsdWUsIGluZGV4LCBjb2xsZWN0aW9uKTtcbiAgICAgICAgICBpZiAoY3VycmVudCA+IGNvbXB1dGVkKSB7XG4gICAgICAgICAgICBjb21wdXRlZCA9IGN1cnJlbnQ7XG4gICAgICAgICAgICByZXN1bHQgPSB2YWx1ZTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXRyaWV2ZXMgdGhlIG1pbmltdW0gdmFsdWUgb2YgYW4gYGFycmF5YC4gSWYgYGNhbGxiYWNrYCBpcyBwYXNzZWQsXG4gICAgICogaXQgd2lsbCBiZSBleGVjdXRlZCBmb3IgZWFjaCB2YWx1ZSBpbiB0aGUgYGFycmF5YCB0byBnZW5lcmF0ZSB0aGVcbiAgICAgKiBjcml0ZXJpb24gYnkgd2hpY2ggdGhlIHZhbHVlIGlzIHJhbmtlZC4gVGhlIGBjYWxsYmFja2AgaXMgYm91bmQgdG8gYHRoaXNBcmdgXG4gICAgICogYW5kIGludm9rZWQgd2l0aCB0aHJlZSBhcmd1bWVudHM7ICh2YWx1ZSwgaW5kZXgsIGNvbGxlY3Rpb24pLlxuICAgICAqXG4gICAgICogSWYgYSBwcm9wZXJ0eSBuYW1lIGlzIHBhc3NlZCBmb3IgYGNhbGxiYWNrYCwgdGhlIGNyZWF0ZWQgXCJfLnBsdWNrXCIgc3R5bGVcbiAgICAgKiBjYWxsYmFjayB3aWxsIHJldHVybiB0aGUgcHJvcGVydHkgdmFsdWUgb2YgdGhlIGdpdmVuIGVsZW1lbnQuXG4gICAgICpcbiAgICAgKiBJZiBhbiBvYmplY3QgaXMgcGFzc2VkIGZvciBgY2FsbGJhY2tgLCB0aGUgY3JlYXRlZCBcIl8ud2hlcmVcIiBzdHlsZSBjYWxsYmFja1xuICAgICAqIHdpbGwgcmV0dXJuIGB0cnVlYCBmb3IgZWxlbWVudHMgdGhhdCBoYXZlIHRoZSBwcm9wZXJ0aWVzIG9mIHRoZSBnaXZlbiBvYmplY3QsXG4gICAgICogZWxzZSBgZmFsc2VgLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IENvbGxlY3Rpb25zXG4gICAgICogQHBhcmFtIHtBcnJheXxPYmplY3R8U3RyaW5nfSBjb2xsZWN0aW9uIFRoZSBjb2xsZWN0aW9uIHRvIGl0ZXJhdGUgb3Zlci5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufE9iamVjdHxTdHJpbmd9IFtjYWxsYmFjaz1pZGVudGl0eV0gVGhlIGZ1bmN0aW9uIGNhbGxlZCBwZXJcbiAgICAgKiAgaXRlcmF0aW9uLiBJZiBhIHByb3BlcnR5IG5hbWUgb3Igb2JqZWN0IGlzIHBhc3NlZCwgaXQgd2lsbCBiZSB1c2VkIHRvIGNyZWF0ZVxuICAgICAqICBhIFwiXy5wbHVja1wiIG9yIFwiXy53aGVyZVwiIHN0eWxlIGNhbGxiYWNrLCByZXNwZWN0aXZlbHkuXG4gICAgICogQHBhcmFtIHtNaXhlZH0gW3RoaXNBcmddIFRoZSBgdGhpc2AgYmluZGluZyBvZiBgY2FsbGJhY2tgLlxuICAgICAqIEByZXR1cm5zIHtNaXhlZH0gUmV0dXJucyB0aGUgbWluaW11bSB2YWx1ZS5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5taW4oWzQsIDIsIDgsIDZdKTtcbiAgICAgKiAvLyA9PiAyXG4gICAgICpcbiAgICAgKiB2YXIgc3Rvb2dlcyA9IFtcbiAgICAgKiAgIHsgJ25hbWUnOiAnbW9lJywgJ2FnZSc6IDQwIH0sXG4gICAgICogICB7ICduYW1lJzogJ2xhcnJ5JywgJ2FnZSc6IDUwIH1cbiAgICAgKiBdO1xuICAgICAqXG4gICAgICogXy5taW4oc3Rvb2dlcywgZnVuY3Rpb24oc3Rvb2dlKSB7IHJldHVybiBzdG9vZ2UuYWdlOyB9KTtcbiAgICAgKiAvLyA9PiB7ICduYW1lJzogJ21vZScsICdhZ2UnOiA0MCB9O1xuICAgICAqXG4gICAgICogLy8gdXNpbmcgXCJfLnBsdWNrXCIgY2FsbGJhY2sgc2hvcnRoYW5kXG4gICAgICogXy5taW4oc3Rvb2dlcywgJ2FnZScpO1xuICAgICAqIC8vID0+IHsgJ25hbWUnOiAnbW9lJywgJ2FnZSc6IDQwIH07XG4gICAgICovXG4gICAgZnVuY3Rpb24gbWluKGNvbGxlY3Rpb24sIGNhbGxiYWNrLCB0aGlzQXJnKSB7XG4gICAgICB2YXIgY29tcHV0ZWQgPSBJbmZpbml0eSxcbiAgICAgICAgICByZXN1bHQgPSBjb21wdXRlZDtcblxuICAgICAgaWYgKCFjYWxsYmFjayAmJiBpc0FycmF5KGNvbGxlY3Rpb24pKSB7XG4gICAgICAgIHZhciBpbmRleCA9IC0xLFxuICAgICAgICAgICAgbGVuZ3RoID0gY29sbGVjdGlvbi5sZW5ndGg7XG5cbiAgICAgICAgd2hpbGUgKCsraW5kZXggPCBsZW5ndGgpIHtcbiAgICAgICAgICB2YXIgdmFsdWUgPSBjb2xsZWN0aW9uW2luZGV4XTtcbiAgICAgICAgICBpZiAodmFsdWUgPCByZXN1bHQpIHtcbiAgICAgICAgICAgIHJlc3VsdCA9IHZhbHVlO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY2FsbGJhY2sgPSAoIWNhbGxiYWNrICYmIGlzU3RyaW5nKGNvbGxlY3Rpb24pKVxuICAgICAgICAgID8gY2hhckF0Q2FsbGJhY2tcbiAgICAgICAgICA6IGxvZGFzaC5jcmVhdGVDYWxsYmFjayhjYWxsYmFjaywgdGhpc0FyZyk7XG5cbiAgICAgICAgZm9yRWFjaChjb2xsZWN0aW9uLCBmdW5jdGlvbih2YWx1ZSwgaW5kZXgsIGNvbGxlY3Rpb24pIHtcbiAgICAgICAgICB2YXIgY3VycmVudCA9IGNhbGxiYWNrKHZhbHVlLCBpbmRleCwgY29sbGVjdGlvbik7XG4gICAgICAgICAgaWYgKGN1cnJlbnQgPCBjb21wdXRlZCkge1xuICAgICAgICAgICAgY29tcHV0ZWQgPSBjdXJyZW50O1xuICAgICAgICAgICAgcmVzdWx0ID0gdmFsdWU7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0cmlldmVzIHRoZSB2YWx1ZSBvZiBhIHNwZWNpZmllZCBwcm9wZXJ0eSBmcm9tIGFsbCBlbGVtZW50cyBpbiB0aGUgYGNvbGxlY3Rpb25gLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQHR5cGUgRnVuY3Rpb25cbiAgICAgKiBAY2F0ZWdvcnkgQ29sbGVjdGlvbnNcbiAgICAgKiBAcGFyYW0ge0FycmF5fE9iamVjdHxTdHJpbmd9IGNvbGxlY3Rpb24gVGhlIGNvbGxlY3Rpb24gdG8gaXRlcmF0ZSBvdmVyLlxuICAgICAqIEBwYXJhbSB7U3RyaW5nfSBwcm9wZXJ0eSBUaGUgcHJvcGVydHkgdG8gcGx1Y2suXG4gICAgICogQHJldHVybnMge0FycmF5fSBSZXR1cm5zIGEgbmV3IGFycmF5IG9mIHByb3BlcnR5IHZhbHVlcy5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogdmFyIHN0b29nZXMgPSBbXG4gICAgICogICB7ICduYW1lJzogJ21vZScsICdhZ2UnOiA0MCB9LFxuICAgICAqICAgeyAnbmFtZSc6ICdsYXJyeScsICdhZ2UnOiA1MCB9XG4gICAgICogXTtcbiAgICAgKlxuICAgICAqIF8ucGx1Y2soc3Rvb2dlcywgJ25hbWUnKTtcbiAgICAgKiAvLyA9PiBbJ21vZScsICdsYXJyeSddXG4gICAgICovXG4gICAgZnVuY3Rpb24gcGx1Y2soY29sbGVjdGlvbiwgcHJvcGVydHkpIHtcbiAgICAgIHZhciBpbmRleCA9IC0xLFxuICAgICAgICAgIGxlbmd0aCA9IGNvbGxlY3Rpb24gPyBjb2xsZWN0aW9uLmxlbmd0aCA6IDA7XG5cbiAgICAgIGlmICh0eXBlb2YgbGVuZ3RoID09ICdudW1iZXInKSB7XG4gICAgICAgIHZhciByZXN1bHQgPSBBcnJheShsZW5ndGgpO1xuICAgICAgICB3aGlsZSAoKytpbmRleCA8IGxlbmd0aCkge1xuICAgICAgICAgIHJlc3VsdFtpbmRleF0gPSBjb2xsZWN0aW9uW2luZGV4XVtwcm9wZXJ0eV07XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiByZXN1bHQgfHwgbWFwKGNvbGxlY3Rpb24sIHByb3BlcnR5KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZWR1Y2VzIGEgYGNvbGxlY3Rpb25gIHRvIGEgdmFsdWUgd2hpY2ggaXMgdGhlIGFjY3VtdWxhdGVkIHJlc3VsdCBvZiBydW5uaW5nXG4gICAgICogZWFjaCBlbGVtZW50IGluIHRoZSBgY29sbGVjdGlvbmAgdGhyb3VnaCB0aGUgYGNhbGxiYWNrYCwgd2hlcmUgZWFjaCBzdWNjZXNzaXZlXG4gICAgICogYGNhbGxiYWNrYCBleGVjdXRpb24gY29uc3VtZXMgdGhlIHJldHVybiB2YWx1ZSBvZiB0aGUgcHJldmlvdXMgZXhlY3V0aW9uLlxuICAgICAqIElmIGBhY2N1bXVsYXRvcmAgaXMgbm90IHBhc3NlZCwgdGhlIGZpcnN0IGVsZW1lbnQgb2YgdGhlIGBjb2xsZWN0aW9uYCB3aWxsIGJlXG4gICAgICogdXNlZCBhcyB0aGUgaW5pdGlhbCBgYWNjdW11bGF0b3JgIHZhbHVlLiBUaGUgYGNhbGxiYWNrYCBpcyBib3VuZCB0byBgdGhpc0FyZ2BcbiAgICAgKiBhbmQgaW52b2tlZCB3aXRoIGZvdXIgYXJndW1lbnRzOyAoYWNjdW11bGF0b3IsIHZhbHVlLCBpbmRleHxrZXksIGNvbGxlY3Rpb24pLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGFsaWFzIGZvbGRsLCBpbmplY3RcbiAgICAgKiBAY2F0ZWdvcnkgQ29sbGVjdGlvbnNcbiAgICAgKiBAcGFyYW0ge0FycmF5fE9iamVjdHxTdHJpbmd9IGNvbGxlY3Rpb24gVGhlIGNvbGxlY3Rpb24gdG8gaXRlcmF0ZSBvdmVyLlxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb259IFtjYWxsYmFjaz1pZGVudGl0eV0gVGhlIGZ1bmN0aW9uIGNhbGxlZCBwZXIgaXRlcmF0aW9uLlxuICAgICAqIEBwYXJhbSB7TWl4ZWR9IFthY2N1bXVsYXRvcl0gSW5pdGlhbCB2YWx1ZSBvZiB0aGUgYWNjdW11bGF0b3IuXG4gICAgICogQHBhcmFtIHtNaXhlZH0gW3RoaXNBcmddIFRoZSBgdGhpc2AgYmluZGluZyBvZiBgY2FsbGJhY2tgLlxuICAgICAqIEByZXR1cm5zIHtNaXhlZH0gUmV0dXJucyB0aGUgYWNjdW11bGF0ZWQgdmFsdWUuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIHZhciBzdW0gPSBfLnJlZHVjZShbMSwgMiwgM10sIGZ1bmN0aW9uKHN1bSwgbnVtKSB7XG4gICAgICogICByZXR1cm4gc3VtICsgbnVtO1xuICAgICAqIH0pO1xuICAgICAqIC8vID0+IDZcbiAgICAgKlxuICAgICAqIHZhciBtYXBwZWQgPSBfLnJlZHVjZSh7ICdhJzogMSwgJ2InOiAyLCAnYyc6IDMgfSwgZnVuY3Rpb24ocmVzdWx0LCBudW0sIGtleSkge1xuICAgICAqICAgcmVzdWx0W2tleV0gPSBudW0gKiAzO1xuICAgICAqICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgKiB9LCB7fSk7XG4gICAgICogLy8gPT4geyAnYSc6IDMsICdiJzogNiwgJ2MnOiA5IH1cbiAgICAgKi9cbiAgICBmdW5jdGlvbiByZWR1Y2UoY29sbGVjdGlvbiwgY2FsbGJhY2ssIGFjY3VtdWxhdG9yLCB0aGlzQXJnKSB7XG4gICAgICBpZiAoIWNvbGxlY3Rpb24pIHJldHVybiBhY2N1bXVsYXRvcjtcbiAgICAgIHZhciBub2FjY3VtID0gYXJndW1lbnRzLmxlbmd0aCA8IDM7XG4gICAgICBjYWxsYmFjayA9IGxvZGFzaC5jcmVhdGVDYWxsYmFjayhjYWxsYmFjaywgdGhpc0FyZywgNCk7XG5cbiAgICAgIHZhciBpbmRleCA9IC0xLFxuICAgICAgICAgIGxlbmd0aCA9IGNvbGxlY3Rpb24ubGVuZ3RoO1xuXG4gICAgICBpZiAodHlwZW9mIGxlbmd0aCA9PSAnbnVtYmVyJykge1xuICAgICAgICBpZiAobm9hY2N1bSkge1xuICAgICAgICAgIGFjY3VtdWxhdG9yID0gY29sbGVjdGlvblsrK2luZGV4XTtcbiAgICAgICAgfVxuICAgICAgICB3aGlsZSAoKytpbmRleCA8IGxlbmd0aCkge1xuICAgICAgICAgIGFjY3VtdWxhdG9yID0gY2FsbGJhY2soYWNjdW11bGF0b3IsIGNvbGxlY3Rpb25baW5kZXhdLCBpbmRleCwgY29sbGVjdGlvbik7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGZvck93bihjb2xsZWN0aW9uLCBmdW5jdGlvbih2YWx1ZSwgaW5kZXgsIGNvbGxlY3Rpb24pIHtcbiAgICAgICAgICBhY2N1bXVsYXRvciA9IG5vYWNjdW1cbiAgICAgICAgICAgID8gKG5vYWNjdW0gPSBmYWxzZSwgdmFsdWUpXG4gICAgICAgICAgICA6IGNhbGxiYWNrKGFjY3VtdWxhdG9yLCB2YWx1ZSwgaW5kZXgsIGNvbGxlY3Rpb24pXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGFjY3VtdWxhdG9yO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRoaXMgbWV0aG9kIGlzIHNpbWlsYXIgdG8gYF8ucmVkdWNlYCwgZXhjZXB0IHRoYXQgaXQgaXRlcmF0ZXMgb3ZlciBhXG4gICAgICogYGNvbGxlY3Rpb25gIGZyb20gcmlnaHQgdG8gbGVmdC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBhbGlhcyBmb2xkclxuICAgICAqIEBjYXRlZ29yeSBDb2xsZWN0aW9uc1xuICAgICAqIEBwYXJhbSB7QXJyYXl8T2JqZWN0fFN0cmluZ30gY29sbGVjdGlvbiBUaGUgY29sbGVjdGlvbiB0byBpdGVyYXRlIG92ZXIuXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbn0gW2NhbGxiYWNrPWlkZW50aXR5XSBUaGUgZnVuY3Rpb24gY2FsbGVkIHBlciBpdGVyYXRpb24uXG4gICAgICogQHBhcmFtIHtNaXhlZH0gW2FjY3VtdWxhdG9yXSBJbml0aWFsIHZhbHVlIG9mIHRoZSBhY2N1bXVsYXRvci5cbiAgICAgKiBAcGFyYW0ge01peGVkfSBbdGhpc0FyZ10gVGhlIGB0aGlzYCBiaW5kaW5nIG9mIGBjYWxsYmFja2AuXG4gICAgICogQHJldHVybnMge01peGVkfSBSZXR1cm5zIHRoZSBhY2N1bXVsYXRlZCB2YWx1ZS5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogdmFyIGxpc3QgPSBbWzAsIDFdLCBbMiwgM10sIFs0LCA1XV07XG4gICAgICogdmFyIGZsYXQgPSBfLnJlZHVjZVJpZ2h0KGxpc3QsIGZ1bmN0aW9uKGEsIGIpIHsgcmV0dXJuIGEuY29uY2F0KGIpOyB9LCBbXSk7XG4gICAgICogLy8gPT4gWzQsIDUsIDIsIDMsIDAsIDFdXG4gICAgICovXG4gICAgZnVuY3Rpb24gcmVkdWNlUmlnaHQoY29sbGVjdGlvbiwgY2FsbGJhY2ssIGFjY3VtdWxhdG9yLCB0aGlzQXJnKSB7XG4gICAgICB2YXIgaXRlcmFibGUgPSBjb2xsZWN0aW9uLFxuICAgICAgICAgIGxlbmd0aCA9IGNvbGxlY3Rpb24gPyBjb2xsZWN0aW9uLmxlbmd0aCA6IDAsXG4gICAgICAgICAgbm9hY2N1bSA9IGFyZ3VtZW50cy5sZW5ndGggPCAzO1xuXG4gICAgICBpZiAodHlwZW9mIGxlbmd0aCAhPSAnbnVtYmVyJykge1xuICAgICAgICB2YXIgcHJvcHMgPSBrZXlzKGNvbGxlY3Rpb24pO1xuICAgICAgICBsZW5ndGggPSBwcm9wcy5sZW5ndGg7XG4gICAgICB9XG4gICAgICBjYWxsYmFjayA9IGxvZGFzaC5jcmVhdGVDYWxsYmFjayhjYWxsYmFjaywgdGhpc0FyZywgNCk7XG4gICAgICBmb3JFYWNoKGNvbGxlY3Rpb24sIGZ1bmN0aW9uKHZhbHVlLCBpbmRleCwgY29sbGVjdGlvbikge1xuICAgICAgICBpbmRleCA9IHByb3BzID8gcHJvcHNbLS1sZW5ndGhdIDogLS1sZW5ndGg7XG4gICAgICAgIGFjY3VtdWxhdG9yID0gbm9hY2N1bVxuICAgICAgICAgID8gKG5vYWNjdW0gPSBmYWxzZSwgaXRlcmFibGVbaW5kZXhdKVxuICAgICAgICAgIDogY2FsbGJhY2soYWNjdW11bGF0b3IsIGl0ZXJhYmxlW2luZGV4XSwgaW5kZXgsIGNvbGxlY3Rpb24pO1xuICAgICAgfSk7XG4gICAgICByZXR1cm4gYWNjdW11bGF0b3I7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVGhlIG9wcG9zaXRlIG9mIGBfLmZpbHRlcmAsIHRoaXMgbWV0aG9kIHJldHVybnMgdGhlIGVsZW1lbnRzIG9mIGFcbiAgICAgKiBgY29sbGVjdGlvbmAgdGhhdCBgY2FsbGJhY2tgIGRvZXMgKipub3QqKiByZXR1cm4gdHJ1dGh5IGZvci5cbiAgICAgKlxuICAgICAqIElmIGEgcHJvcGVydHkgbmFtZSBpcyBwYXNzZWQgZm9yIGBjYWxsYmFja2AsIHRoZSBjcmVhdGVkIFwiXy5wbHVja1wiIHN0eWxlXG4gICAgICogY2FsbGJhY2sgd2lsbCByZXR1cm4gdGhlIHByb3BlcnR5IHZhbHVlIG9mIHRoZSBnaXZlbiBlbGVtZW50LlxuICAgICAqXG4gICAgICogSWYgYW4gb2JqZWN0IGlzIHBhc3NlZCBmb3IgYGNhbGxiYWNrYCwgdGhlIGNyZWF0ZWQgXCJfLndoZXJlXCIgc3R5bGUgY2FsbGJhY2tcbiAgICAgKiB3aWxsIHJldHVybiBgdHJ1ZWAgZm9yIGVsZW1lbnRzIHRoYXQgaGF2ZSB0aGUgcHJvcGVydGllcyBvZiB0aGUgZ2l2ZW4gb2JqZWN0LFxuICAgICAqIGVsc2UgYGZhbHNlYC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBDb2xsZWN0aW9uc1xuICAgICAqIEBwYXJhbSB7QXJyYXl8T2JqZWN0fFN0cmluZ30gY29sbGVjdGlvbiBUaGUgY29sbGVjdGlvbiB0byBpdGVyYXRlIG92ZXIuXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbnxPYmplY3R8U3RyaW5nfSBbY2FsbGJhY2s9aWRlbnRpdHldIFRoZSBmdW5jdGlvbiBjYWxsZWQgcGVyXG4gICAgICogIGl0ZXJhdGlvbi4gSWYgYSBwcm9wZXJ0eSBuYW1lIG9yIG9iamVjdCBpcyBwYXNzZWQsIGl0IHdpbGwgYmUgdXNlZCB0byBjcmVhdGVcbiAgICAgKiAgYSBcIl8ucGx1Y2tcIiBvciBcIl8ud2hlcmVcIiBzdHlsZSBjYWxsYmFjaywgcmVzcGVjdGl2ZWx5LlxuICAgICAqIEBwYXJhbSB7TWl4ZWR9IFt0aGlzQXJnXSBUaGUgYHRoaXNgIGJpbmRpbmcgb2YgYGNhbGxiYWNrYC5cbiAgICAgKiBAcmV0dXJucyB7QXJyYXl9IFJldHVybnMgYSBuZXcgYXJyYXkgb2YgZWxlbWVudHMgdGhhdCBkaWQgKipub3QqKiBwYXNzIHRoZVxuICAgICAqICBjYWxsYmFjayBjaGVjay5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogdmFyIG9kZHMgPSBfLnJlamVjdChbMSwgMiwgMywgNCwgNSwgNl0sIGZ1bmN0aW9uKG51bSkgeyByZXR1cm4gbnVtICUgMiA9PSAwOyB9KTtcbiAgICAgKiAvLyA9PiBbMSwgMywgNV1cbiAgICAgKlxuICAgICAqIHZhciBmb29kID0gW1xuICAgICAqICAgeyAnbmFtZSc6ICdhcHBsZScsICAnb3JnYW5pYyc6IGZhbHNlLCAndHlwZSc6ICdmcnVpdCcgfSxcbiAgICAgKiAgIHsgJ25hbWUnOiAnY2Fycm90JywgJ29yZ2FuaWMnOiB0cnVlLCAgJ3R5cGUnOiAndmVnZXRhYmxlJyB9XG4gICAgICogXTtcbiAgICAgKlxuICAgICAqIC8vIHVzaW5nIFwiXy5wbHVja1wiIGNhbGxiYWNrIHNob3J0aGFuZFxuICAgICAqIF8ucmVqZWN0KGZvb2QsICdvcmdhbmljJyk7XG4gICAgICogLy8gPT4gW3sgJ25hbWUnOiAnYXBwbGUnLCAnb3JnYW5pYyc6IGZhbHNlLCAndHlwZSc6ICdmcnVpdCcgfV1cbiAgICAgKlxuICAgICAqIC8vIHVzaW5nIFwiXy53aGVyZVwiIGNhbGxiYWNrIHNob3J0aGFuZFxuICAgICAqIF8ucmVqZWN0KGZvb2QsIHsgJ3R5cGUnOiAnZnJ1aXQnIH0pO1xuICAgICAqIC8vID0+IFt7ICduYW1lJzogJ2NhcnJvdCcsICdvcmdhbmljJzogdHJ1ZSwgJ3R5cGUnOiAndmVnZXRhYmxlJyB9XVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIHJlamVjdChjb2xsZWN0aW9uLCBjYWxsYmFjaywgdGhpc0FyZykge1xuICAgICAgY2FsbGJhY2sgPSBsb2Rhc2guY3JlYXRlQ2FsbGJhY2soY2FsbGJhY2ssIHRoaXNBcmcpO1xuICAgICAgcmV0dXJuIGZpbHRlcihjb2xsZWN0aW9uLCBmdW5jdGlvbih2YWx1ZSwgaW5kZXgsIGNvbGxlY3Rpb24pIHtcbiAgICAgICAgcmV0dXJuICFjYWxsYmFjayh2YWx1ZSwgaW5kZXgsIGNvbGxlY3Rpb24pO1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhbiBhcnJheSBvZiBzaHVmZmxlZCBgYXJyYXlgIHZhbHVlcywgdXNpbmcgYSB2ZXJzaW9uIG9mIHRoZVxuICAgICAqIEZpc2hlci1ZYXRlcyBzaHVmZmxlLiBTZWUgaHR0cDovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9GaXNoZXItWWF0ZXNfc2h1ZmZsZS5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBDb2xsZWN0aW9uc1xuICAgICAqIEBwYXJhbSB7QXJyYXl8T2JqZWN0fFN0cmluZ30gY29sbGVjdGlvbiBUaGUgY29sbGVjdGlvbiB0byBzaHVmZmxlLlxuICAgICAqIEByZXR1cm5zIHtBcnJheX0gUmV0dXJucyBhIG5ldyBzaHVmZmxlZCBjb2xsZWN0aW9uLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLnNodWZmbGUoWzEsIDIsIDMsIDQsIDUsIDZdKTtcbiAgICAgKiAvLyA9PiBbNCwgMSwgNiwgMywgNSwgMl1cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBzaHVmZmxlKGNvbGxlY3Rpb24pIHtcbiAgICAgIHZhciBpbmRleCA9IC0xLFxuICAgICAgICAgIGxlbmd0aCA9IGNvbGxlY3Rpb24gPyBjb2xsZWN0aW9uLmxlbmd0aCA6IDAsXG4gICAgICAgICAgcmVzdWx0ID0gQXJyYXkodHlwZW9mIGxlbmd0aCA9PSAnbnVtYmVyJyA/IGxlbmd0aCA6IDApO1xuXG4gICAgICBmb3JFYWNoKGNvbGxlY3Rpb24sIGZ1bmN0aW9uKHZhbHVlKSB7XG4gICAgICAgIHZhciByYW5kID0gZmxvb3IobmF0aXZlUmFuZG9tKCkgKiAoKytpbmRleCArIDEpKTtcbiAgICAgICAgcmVzdWx0W2luZGV4XSA9IHJlc3VsdFtyYW5kXTtcbiAgICAgICAgcmVzdWx0W3JhbmRdID0gdmFsdWU7XG4gICAgICB9KTtcbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0cyB0aGUgc2l6ZSBvZiB0aGUgYGNvbGxlY3Rpb25gIGJ5IHJldHVybmluZyBgY29sbGVjdGlvbi5sZW5ndGhgIGZvciBhcnJheXNcbiAgICAgKiBhbmQgYXJyYXktbGlrZSBvYmplY3RzIG9yIHRoZSBudW1iZXIgb2Ygb3duIGVudW1lcmFibGUgcHJvcGVydGllcyBmb3Igb2JqZWN0cy5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBDb2xsZWN0aW9uc1xuICAgICAqIEBwYXJhbSB7QXJyYXl8T2JqZWN0fFN0cmluZ30gY29sbGVjdGlvbiBUaGUgY29sbGVjdGlvbiB0byBpbnNwZWN0LlxuICAgICAqIEByZXR1cm5zIHtOdW1iZXJ9IFJldHVybnMgYGNvbGxlY3Rpb24ubGVuZ3RoYCBvciBudW1iZXIgb2Ygb3duIGVudW1lcmFibGUgcHJvcGVydGllcy5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5zaXplKFsxLCAyXSk7XG4gICAgICogLy8gPT4gMlxuICAgICAqXG4gICAgICogXy5zaXplKHsgJ29uZSc6IDEsICd0d28nOiAyLCAndGhyZWUnOiAzIH0pO1xuICAgICAqIC8vID0+IDNcbiAgICAgKlxuICAgICAqIF8uc2l6ZSgnY3VybHknKTtcbiAgICAgKiAvLyA9PiA1XG4gICAgICovXG4gICAgZnVuY3Rpb24gc2l6ZShjb2xsZWN0aW9uKSB7XG4gICAgICB2YXIgbGVuZ3RoID0gY29sbGVjdGlvbiA/IGNvbGxlY3Rpb24ubGVuZ3RoIDogMDtcbiAgICAgIHJldHVybiB0eXBlb2YgbGVuZ3RoID09ICdudW1iZXInID8gbGVuZ3RoIDoga2V5cyhjb2xsZWN0aW9uKS5sZW5ndGg7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2hlY2tzIGlmIHRoZSBgY2FsbGJhY2tgIHJldHVybnMgYSB0cnV0aHkgdmFsdWUgZm9yICoqYW55KiogZWxlbWVudCBvZiBhXG4gICAgICogYGNvbGxlY3Rpb25gLiBUaGUgZnVuY3Rpb24gcmV0dXJucyBhcyBzb29uIGFzIGl0IGZpbmRzIHBhc3NpbmcgdmFsdWUsIGFuZFxuICAgICAqIGRvZXMgbm90IGl0ZXJhdGUgb3ZlciB0aGUgZW50aXJlIGBjb2xsZWN0aW9uYC4gVGhlIGBjYWxsYmFja2AgaXMgYm91bmQgdG9cbiAgICAgKiBgdGhpc0FyZ2AgYW5kIGludm9rZWQgd2l0aCB0aHJlZSBhcmd1bWVudHM7ICh2YWx1ZSwgaW5kZXh8a2V5LCBjb2xsZWN0aW9uKS5cbiAgICAgKlxuICAgICAqIElmIGEgcHJvcGVydHkgbmFtZSBpcyBwYXNzZWQgZm9yIGBjYWxsYmFja2AsIHRoZSBjcmVhdGVkIFwiXy5wbHVja1wiIHN0eWxlXG4gICAgICogY2FsbGJhY2sgd2lsbCByZXR1cm4gdGhlIHByb3BlcnR5IHZhbHVlIG9mIHRoZSBnaXZlbiBlbGVtZW50LlxuICAgICAqXG4gICAgICogSWYgYW4gb2JqZWN0IGlzIHBhc3NlZCBmb3IgYGNhbGxiYWNrYCwgdGhlIGNyZWF0ZWQgXCJfLndoZXJlXCIgc3R5bGUgY2FsbGJhY2tcbiAgICAgKiB3aWxsIHJldHVybiBgdHJ1ZWAgZm9yIGVsZW1lbnRzIHRoYXQgaGF2ZSB0aGUgcHJvcGVydGllcyBvZiB0aGUgZ2l2ZW4gb2JqZWN0LFxuICAgICAqIGVsc2UgYGZhbHNlYC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBhbGlhcyBhbnlcbiAgICAgKiBAY2F0ZWdvcnkgQ29sbGVjdGlvbnNcbiAgICAgKiBAcGFyYW0ge0FycmF5fE9iamVjdHxTdHJpbmd9IGNvbGxlY3Rpb24gVGhlIGNvbGxlY3Rpb24gdG8gaXRlcmF0ZSBvdmVyLlxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb258T2JqZWN0fFN0cmluZ30gW2NhbGxiYWNrPWlkZW50aXR5XSBUaGUgZnVuY3Rpb24gY2FsbGVkIHBlclxuICAgICAqICBpdGVyYXRpb24uIElmIGEgcHJvcGVydHkgbmFtZSBvciBvYmplY3QgaXMgcGFzc2VkLCBpdCB3aWxsIGJlIHVzZWQgdG8gY3JlYXRlXG4gICAgICogIGEgXCJfLnBsdWNrXCIgb3IgXCJfLndoZXJlXCIgc3R5bGUgY2FsbGJhY2ssIHJlc3BlY3RpdmVseS5cbiAgICAgKiBAcGFyYW0ge01peGVkfSBbdGhpc0FyZ10gVGhlIGB0aGlzYCBiaW5kaW5nIG9mIGBjYWxsYmFja2AuXG4gICAgICogQHJldHVybnMge0Jvb2xlYW59IFJldHVybnMgYHRydWVgIGlmIGFueSBlbGVtZW50IHBhc3NlcyB0aGUgY2FsbGJhY2sgY2hlY2ssXG4gICAgICogIGVsc2UgYGZhbHNlYC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5zb21lKFtudWxsLCAwLCAneWVzJywgZmFsc2VdLCBCb29sZWFuKTtcbiAgICAgKiAvLyA9PiB0cnVlXG4gICAgICpcbiAgICAgKiB2YXIgZm9vZCA9IFtcbiAgICAgKiAgIHsgJ25hbWUnOiAnYXBwbGUnLCAgJ29yZ2FuaWMnOiBmYWxzZSwgJ3R5cGUnOiAnZnJ1aXQnIH0sXG4gICAgICogICB7ICduYW1lJzogJ2NhcnJvdCcsICdvcmdhbmljJzogdHJ1ZSwgICd0eXBlJzogJ3ZlZ2V0YWJsZScgfVxuICAgICAqIF07XG4gICAgICpcbiAgICAgKiAvLyB1c2luZyBcIl8ucGx1Y2tcIiBjYWxsYmFjayBzaG9ydGhhbmRcbiAgICAgKiBfLnNvbWUoZm9vZCwgJ29yZ2FuaWMnKTtcbiAgICAgKiAvLyA9PiB0cnVlXG4gICAgICpcbiAgICAgKiAvLyB1c2luZyBcIl8ud2hlcmVcIiBjYWxsYmFjayBzaG9ydGhhbmRcbiAgICAgKiBfLnNvbWUoZm9vZCwgeyAndHlwZSc6ICdtZWF0JyB9KTtcbiAgICAgKiAvLyA9PiBmYWxzZVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIHNvbWUoY29sbGVjdGlvbiwgY2FsbGJhY2ssIHRoaXNBcmcpIHtcbiAgICAgIHZhciByZXN1bHQ7XG4gICAgICBjYWxsYmFjayA9IGxvZGFzaC5jcmVhdGVDYWxsYmFjayhjYWxsYmFjaywgdGhpc0FyZyk7XG5cbiAgICAgIHZhciBpbmRleCA9IC0xLFxuICAgICAgICAgIGxlbmd0aCA9IGNvbGxlY3Rpb24gPyBjb2xsZWN0aW9uLmxlbmd0aCA6IDA7XG5cbiAgICAgIGlmICh0eXBlb2YgbGVuZ3RoID09ICdudW1iZXInKSB7XG4gICAgICAgIHdoaWxlICgrK2luZGV4IDwgbGVuZ3RoKSB7XG4gICAgICAgICAgaWYgKChyZXN1bHQgPSBjYWxsYmFjayhjb2xsZWN0aW9uW2luZGV4XSwgaW5kZXgsIGNvbGxlY3Rpb24pKSkge1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBmb3JPd24oY29sbGVjdGlvbiwgZnVuY3Rpb24odmFsdWUsIGluZGV4LCBjb2xsZWN0aW9uKSB7XG4gICAgICAgICAgcmV0dXJuICEocmVzdWx0ID0gY2FsbGJhY2sodmFsdWUsIGluZGV4LCBjb2xsZWN0aW9uKSk7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgICAgcmV0dXJuICEhcmVzdWx0O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYW4gYXJyYXkgb2YgZWxlbWVudHMsIHNvcnRlZCBpbiBhc2NlbmRpbmcgb3JkZXIgYnkgdGhlIHJlc3VsdHMgb2ZcbiAgICAgKiBydW5uaW5nIGVhY2ggZWxlbWVudCBpbiB0aGUgYGNvbGxlY3Rpb25gIHRocm91Z2ggdGhlIGBjYWxsYmFja2AuIFRoaXMgbWV0aG9kXG4gICAgICogcGVyZm9ybXMgYSBzdGFibGUgc29ydCwgdGhhdCBpcywgaXQgd2lsbCBwcmVzZXJ2ZSB0aGUgb3JpZ2luYWwgc29ydCBvcmRlciBvZlxuICAgICAqIGVxdWFsIGVsZW1lbnRzLiBUaGUgYGNhbGxiYWNrYCBpcyBib3VuZCB0byBgdGhpc0FyZ2AgYW5kIGludm9rZWQgd2l0aCB0aHJlZVxuICAgICAqIGFyZ3VtZW50czsgKHZhbHVlLCBpbmRleHxrZXksIGNvbGxlY3Rpb24pLlxuICAgICAqXG4gICAgICogSWYgYSBwcm9wZXJ0eSBuYW1lIGlzIHBhc3NlZCBmb3IgYGNhbGxiYWNrYCwgdGhlIGNyZWF0ZWQgXCJfLnBsdWNrXCIgc3R5bGVcbiAgICAgKiBjYWxsYmFjayB3aWxsIHJldHVybiB0aGUgcHJvcGVydHkgdmFsdWUgb2YgdGhlIGdpdmVuIGVsZW1lbnQuXG4gICAgICpcbiAgICAgKiBJZiBhbiBvYmplY3QgaXMgcGFzc2VkIGZvciBgY2FsbGJhY2tgLCB0aGUgY3JlYXRlZCBcIl8ud2hlcmVcIiBzdHlsZSBjYWxsYmFja1xuICAgICAqIHdpbGwgcmV0dXJuIGB0cnVlYCBmb3IgZWxlbWVudHMgdGhhdCBoYXZlIHRoZSBwcm9wZXJ0aWVzIG9mIHRoZSBnaXZlbiBvYmplY3QsXG4gICAgICogZWxzZSBgZmFsc2VgLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IENvbGxlY3Rpb25zXG4gICAgICogQHBhcmFtIHtBcnJheXxPYmplY3R8U3RyaW5nfSBjb2xsZWN0aW9uIFRoZSBjb2xsZWN0aW9uIHRvIGl0ZXJhdGUgb3Zlci5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufE9iamVjdHxTdHJpbmd9IFtjYWxsYmFjaz1pZGVudGl0eV0gVGhlIGZ1bmN0aW9uIGNhbGxlZCBwZXJcbiAgICAgKiAgaXRlcmF0aW9uLiBJZiBhIHByb3BlcnR5IG5hbWUgb3Igb2JqZWN0IGlzIHBhc3NlZCwgaXQgd2lsbCBiZSB1c2VkIHRvIGNyZWF0ZVxuICAgICAqICBhIFwiXy5wbHVja1wiIG9yIFwiXy53aGVyZVwiIHN0eWxlIGNhbGxiYWNrLCByZXNwZWN0aXZlbHkuXG4gICAgICogQHBhcmFtIHtNaXhlZH0gW3RoaXNBcmddIFRoZSBgdGhpc2AgYmluZGluZyBvZiBgY2FsbGJhY2tgLlxuICAgICAqIEByZXR1cm5zIHtBcnJheX0gUmV0dXJucyBhIG5ldyBhcnJheSBvZiBzb3J0ZWQgZWxlbWVudHMuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8uc29ydEJ5KFsxLCAyLCAzXSwgZnVuY3Rpb24obnVtKSB7IHJldHVybiBNYXRoLnNpbihudW0pOyB9KTtcbiAgICAgKiAvLyA9PiBbMywgMSwgMl1cbiAgICAgKlxuICAgICAqIF8uc29ydEJ5KFsxLCAyLCAzXSwgZnVuY3Rpb24obnVtKSB7IHJldHVybiB0aGlzLnNpbihudW0pOyB9LCBNYXRoKTtcbiAgICAgKiAvLyA9PiBbMywgMSwgMl1cbiAgICAgKlxuICAgICAqIC8vIHVzaW5nIFwiXy5wbHVja1wiIGNhbGxiYWNrIHNob3J0aGFuZFxuICAgICAqIF8uc29ydEJ5KFsnYmFuYW5hJywgJ3N0cmF3YmVycnknLCAnYXBwbGUnXSwgJ2xlbmd0aCcpO1xuICAgICAqIC8vID0+IFsnYXBwbGUnLCAnYmFuYW5hJywgJ3N0cmF3YmVycnknXVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIHNvcnRCeShjb2xsZWN0aW9uLCBjYWxsYmFjaywgdGhpc0FyZykge1xuICAgICAgdmFyIGluZGV4ID0gLTEsXG4gICAgICAgICAgbGVuZ3RoID0gY29sbGVjdGlvbiA/IGNvbGxlY3Rpb24ubGVuZ3RoIDogMCxcbiAgICAgICAgICByZXN1bHQgPSBBcnJheSh0eXBlb2YgbGVuZ3RoID09ICdudW1iZXInID8gbGVuZ3RoIDogMCk7XG5cbiAgICAgIGNhbGxiYWNrID0gbG9kYXNoLmNyZWF0ZUNhbGxiYWNrKGNhbGxiYWNrLCB0aGlzQXJnKTtcbiAgICAgIGZvckVhY2goY29sbGVjdGlvbiwgZnVuY3Rpb24odmFsdWUsIGtleSwgY29sbGVjdGlvbikge1xuICAgICAgICB2YXIgb2JqZWN0ID0gcmVzdWx0WysraW5kZXhdID0gZ2V0T2JqZWN0KCk7XG4gICAgICAgIG9iamVjdC5jcml0ZXJpYSA9IGNhbGxiYWNrKHZhbHVlLCBrZXksIGNvbGxlY3Rpb24pO1xuICAgICAgICBvYmplY3QuaW5kZXggPSBpbmRleDtcbiAgICAgICAgb2JqZWN0LnZhbHVlID0gdmFsdWU7XG4gICAgICB9KTtcblxuICAgICAgbGVuZ3RoID0gcmVzdWx0Lmxlbmd0aDtcbiAgICAgIHJlc3VsdC5zb3J0KGNvbXBhcmVBc2NlbmRpbmcpO1xuICAgICAgd2hpbGUgKGxlbmd0aC0tKSB7XG4gICAgICAgIHZhciBvYmplY3QgPSByZXN1bHRbbGVuZ3RoXTtcbiAgICAgICAgcmVzdWx0W2xlbmd0aF0gPSBvYmplY3QudmFsdWU7XG4gICAgICAgIHJlbGVhc2VPYmplY3Qob2JqZWN0KTtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ29udmVydHMgdGhlIGBjb2xsZWN0aW9uYCB0byBhbiBhcnJheS5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBDb2xsZWN0aW9uc1xuICAgICAqIEBwYXJhbSB7QXJyYXl8T2JqZWN0fFN0cmluZ30gY29sbGVjdGlvbiBUaGUgY29sbGVjdGlvbiB0byBjb252ZXJ0LlxuICAgICAqIEByZXR1cm5zIHtBcnJheX0gUmV0dXJucyB0aGUgbmV3IGNvbnZlcnRlZCBhcnJheS5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogKGZ1bmN0aW9uKCkgeyByZXR1cm4gXy50b0FycmF5KGFyZ3VtZW50cykuc2xpY2UoMSk7IH0pKDEsIDIsIDMsIDQpO1xuICAgICAqIC8vID0+IFsyLCAzLCA0XVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIHRvQXJyYXkoY29sbGVjdGlvbikge1xuICAgICAgaWYgKGNvbGxlY3Rpb24gJiYgdHlwZW9mIGNvbGxlY3Rpb24ubGVuZ3RoID09ICdudW1iZXInKSB7XG4gICAgICAgIHJldHVybiBzbGljZShjb2xsZWN0aW9uKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB2YWx1ZXMoY29sbGVjdGlvbik7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRXhhbWluZXMgZWFjaCBlbGVtZW50IGluIGEgYGNvbGxlY3Rpb25gLCByZXR1cm5pbmcgYW4gYXJyYXkgb2YgYWxsIGVsZW1lbnRzXG4gICAgICogdGhhdCBoYXZlIHRoZSBnaXZlbiBgcHJvcGVydGllc2AuIFdoZW4gY2hlY2tpbmcgYHByb3BlcnRpZXNgLCB0aGlzIG1ldGhvZFxuICAgICAqIHBlcmZvcm1zIGEgZGVlcCBjb21wYXJpc29uIGJldHdlZW4gdmFsdWVzIHRvIGRldGVybWluZSBpZiB0aGV5IGFyZSBlcXVpdmFsZW50XG4gICAgICogdG8gZWFjaCBvdGhlci5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEB0eXBlIEZ1bmN0aW9uXG4gICAgICogQGNhdGVnb3J5IENvbGxlY3Rpb25zXG4gICAgICogQHBhcmFtIHtBcnJheXxPYmplY3R8U3RyaW5nfSBjb2xsZWN0aW9uIFRoZSBjb2xsZWN0aW9uIHRvIGl0ZXJhdGUgb3Zlci5cbiAgICAgKiBAcGFyYW0ge09iamVjdH0gcHJvcGVydGllcyBUaGUgb2JqZWN0IG9mIHByb3BlcnR5IHZhbHVlcyB0byBmaWx0ZXIgYnkuXG4gICAgICogQHJldHVybnMge0FycmF5fSBSZXR1cm5zIGEgbmV3IGFycmF5IG9mIGVsZW1lbnRzIHRoYXQgaGF2ZSB0aGUgZ2l2ZW4gYHByb3BlcnRpZXNgLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiB2YXIgc3Rvb2dlcyA9IFtcbiAgICAgKiAgIHsgJ25hbWUnOiAnbW9lJywgJ2FnZSc6IDQwIH0sXG4gICAgICogICB7ICduYW1lJzogJ2xhcnJ5JywgJ2FnZSc6IDUwIH1cbiAgICAgKiBdO1xuICAgICAqXG4gICAgICogXy53aGVyZShzdG9vZ2VzLCB7ICdhZ2UnOiA0MCB9KTtcbiAgICAgKiAvLyA9PiBbeyAnbmFtZSc6ICdtb2UnLCAnYWdlJzogNDAgfV1cbiAgICAgKi9cbiAgICB2YXIgd2hlcmUgPSBmaWx0ZXI7XG5cbiAgICAvKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYW4gYXJyYXkgd2l0aCBhbGwgZmFsc2V5IHZhbHVlcyBvZiBgYXJyYXlgIHJlbW92ZWQuIFRoZSB2YWx1ZXNcbiAgICAgKiBgZmFsc2VgLCBgbnVsbGAsIGAwYCwgYFwiXCJgLCBgdW5kZWZpbmVkYCBhbmQgYE5hTmAgYXJlIGFsbCBmYWxzZXkuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgQXJyYXlzXG4gICAgICogQHBhcmFtIHtBcnJheX0gYXJyYXkgVGhlIGFycmF5IHRvIGNvbXBhY3QuXG4gICAgICogQHJldHVybnMge0FycmF5fSBSZXR1cm5zIGEgbmV3IGZpbHRlcmVkIGFycmF5LlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLmNvbXBhY3QoWzAsIDEsIGZhbHNlLCAyLCAnJywgM10pO1xuICAgICAqIC8vID0+IFsxLCAyLCAzXVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGNvbXBhY3QoYXJyYXkpIHtcbiAgICAgIHZhciBpbmRleCA9IC0xLFxuICAgICAgICAgIGxlbmd0aCA9IGFycmF5ID8gYXJyYXkubGVuZ3RoIDogMCxcbiAgICAgICAgICByZXN1bHQgPSBbXTtcblxuICAgICAgd2hpbGUgKCsraW5kZXggPCBsZW5ndGgpIHtcbiAgICAgICAgdmFyIHZhbHVlID0gYXJyYXlbaW5kZXhdO1xuICAgICAgICBpZiAodmFsdWUpIHtcbiAgICAgICAgICByZXN1bHQucHVzaCh2YWx1ZSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhbiBhcnJheSBvZiBgYXJyYXlgIGVsZW1lbnRzIG5vdCBwcmVzZW50IGluIHRoZSBvdGhlciBhcnJheXNcbiAgICAgKiB1c2luZyBzdHJpY3QgZXF1YWxpdHkgZm9yIGNvbXBhcmlzb25zLCBpLmUuIGA9PT1gLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IEFycmF5c1xuICAgICAqIEBwYXJhbSB7QXJyYXl9IGFycmF5IFRoZSBhcnJheSB0byBwcm9jZXNzLlxuICAgICAqIEBwYXJhbSB7QXJyYXl9IFthcnJheTEsIGFycmF5MiwgLi4uXSBBcnJheXMgdG8gY2hlY2suXG4gICAgICogQHJldHVybnMge0FycmF5fSBSZXR1cm5zIGEgbmV3IGFycmF5IG9mIGBhcnJheWAgZWxlbWVudHMgbm90IHByZXNlbnQgaW4gdGhlXG4gICAgICogIG90aGVyIGFycmF5cy5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5kaWZmZXJlbmNlKFsxLCAyLCAzLCA0LCA1XSwgWzUsIDIsIDEwXSk7XG4gICAgICogLy8gPT4gWzEsIDMsIDRdXG4gICAgICovXG4gICAgZnVuY3Rpb24gZGlmZmVyZW5jZShhcnJheSkge1xuICAgICAgdmFyIGluZGV4ID0gLTEsXG4gICAgICAgICAgaW5kZXhPZiA9IGdldEluZGV4T2YoKSxcbiAgICAgICAgICBsZW5ndGggPSBhcnJheSA/IGFycmF5Lmxlbmd0aCA6IDAsXG4gICAgICAgICAgc2VlbiA9IGNvbmNhdC5hcHBseShhcnJheVJlZiwgbmF0aXZlU2xpY2UuY2FsbChhcmd1bWVudHMsIDEpKSxcbiAgICAgICAgICByZXN1bHQgPSBbXTtcblxuICAgICAgdmFyIGlzTGFyZ2UgPSBsZW5ndGggPj0gbGFyZ2VBcnJheVNpemUgJiYgaW5kZXhPZiA9PT0gYmFzaWNJbmRleE9mO1xuXG4gICAgICBpZiAoaXNMYXJnZSkge1xuICAgICAgICB2YXIgY2FjaGUgPSBjcmVhdGVDYWNoZShzZWVuKTtcbiAgICAgICAgaWYgKGNhY2hlKSB7XG4gICAgICAgICAgaW5kZXhPZiA9IGNhY2hlSW5kZXhPZjtcbiAgICAgICAgICBzZWVuID0gY2FjaGU7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgaXNMYXJnZSA9IGZhbHNlO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICB3aGlsZSAoKytpbmRleCA8IGxlbmd0aCkge1xuICAgICAgICB2YXIgdmFsdWUgPSBhcnJheVtpbmRleF07XG4gICAgICAgIGlmIChpbmRleE9mKHNlZW4sIHZhbHVlKSA8IDApIHtcbiAgICAgICAgICByZXN1bHQucHVzaCh2YWx1ZSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGlmIChpc0xhcmdlKSB7XG4gICAgICAgIHJlbGVhc2VPYmplY3Qoc2Vlbik7XG4gICAgICB9XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRoaXMgbWV0aG9kIGlzIHNpbWlsYXIgdG8gYF8uZmluZGAsIGV4Y2VwdCB0aGF0IGl0IHJldHVybnMgdGhlIGluZGV4IG9mXG4gICAgICogdGhlIGVsZW1lbnQgdGhhdCBwYXNzZXMgdGhlIGNhbGxiYWNrIGNoZWNrLCBpbnN0ZWFkIG9mIHRoZSBlbGVtZW50IGl0c2VsZi5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBBcnJheXNcbiAgICAgKiBAcGFyYW0ge0FycmF5fSBhcnJheSBUaGUgYXJyYXkgdG8gc2VhcmNoLlxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb258T2JqZWN0fFN0cmluZ30gW2NhbGxiYWNrPWlkZW50aXR5XSBUaGUgZnVuY3Rpb24gY2FsbGVkIHBlclxuICAgICAqICBpdGVyYXRpb24uIElmIGEgcHJvcGVydHkgbmFtZSBvciBvYmplY3QgaXMgcGFzc2VkLCBpdCB3aWxsIGJlIHVzZWQgdG8gY3JlYXRlXG4gICAgICogIGEgXCJfLnBsdWNrXCIgb3IgXCJfLndoZXJlXCIgc3R5bGUgY2FsbGJhY2ssIHJlc3BlY3RpdmVseS5cbiAgICAgKiBAcGFyYW0ge01peGVkfSBbdGhpc0FyZ10gVGhlIGB0aGlzYCBiaW5kaW5nIG9mIGBjYWxsYmFja2AuXG4gICAgICogQHJldHVybnMge01peGVkfSBSZXR1cm5zIHRoZSBpbmRleCBvZiB0aGUgZm91bmQgZWxlbWVudCwgZWxzZSBgLTFgLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLmZpbmRJbmRleChbJ2FwcGxlJywgJ2JhbmFuYScsICdiZWV0J10sIGZ1bmN0aW9uKGZvb2QpIHtcbiAgICAgKiAgIHJldHVybiAvXmIvLnRlc3QoZm9vZCk7XG4gICAgICogfSk7XG4gICAgICogLy8gPT4gMVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGZpbmRJbmRleChhcnJheSwgY2FsbGJhY2ssIHRoaXNBcmcpIHtcbiAgICAgIHZhciBpbmRleCA9IC0xLFxuICAgICAgICAgIGxlbmd0aCA9IGFycmF5ID8gYXJyYXkubGVuZ3RoIDogMDtcblxuICAgICAgY2FsbGJhY2sgPSBsb2Rhc2guY3JlYXRlQ2FsbGJhY2soY2FsbGJhY2ssIHRoaXNBcmcpO1xuICAgICAgd2hpbGUgKCsraW5kZXggPCBsZW5ndGgpIHtcbiAgICAgICAgaWYgKGNhbGxiYWNrKGFycmF5W2luZGV4XSwgaW5kZXgsIGFycmF5KSkge1xuICAgICAgICAgIHJldHVybiBpbmRleDtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgcmV0dXJuIC0xO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldHMgdGhlIGZpcnN0IGVsZW1lbnQgb2YgdGhlIGBhcnJheWAuIElmIGEgbnVtYmVyIGBuYCBpcyBwYXNzZWQsIHRoZSBmaXJzdFxuICAgICAqIGBuYCBlbGVtZW50cyBvZiB0aGUgYGFycmF5YCBhcmUgcmV0dXJuZWQuIElmIGEgYGNhbGxiYWNrYCBmdW5jdGlvbiBpcyBwYXNzZWQsXG4gICAgICogZWxlbWVudHMgYXQgdGhlIGJlZ2lubmluZyBvZiB0aGUgYXJyYXkgYXJlIHJldHVybmVkIGFzIGxvbmcgYXMgdGhlIGBjYWxsYmFja2BcbiAgICAgKiByZXR1cm5zIHRydXRoeS4gVGhlIGBjYWxsYmFja2AgaXMgYm91bmQgdG8gYHRoaXNBcmdgIGFuZCBpbnZva2VkIHdpdGggdGhyZWVcbiAgICAgKiBhcmd1bWVudHM7ICh2YWx1ZSwgaW5kZXgsIGFycmF5KS5cbiAgICAgKlxuICAgICAqIElmIGEgcHJvcGVydHkgbmFtZSBpcyBwYXNzZWQgZm9yIGBjYWxsYmFja2AsIHRoZSBjcmVhdGVkIFwiXy5wbHVja1wiIHN0eWxlXG4gICAgICogY2FsbGJhY2sgd2lsbCByZXR1cm4gdGhlIHByb3BlcnR5IHZhbHVlIG9mIHRoZSBnaXZlbiBlbGVtZW50LlxuICAgICAqXG4gICAgICogSWYgYW4gb2JqZWN0IGlzIHBhc3NlZCBmb3IgYGNhbGxiYWNrYCwgdGhlIGNyZWF0ZWQgXCJfLndoZXJlXCIgc3R5bGUgY2FsbGJhY2tcbiAgICAgKiB3aWxsIHJldHVybiBgdHJ1ZWAgZm9yIGVsZW1lbnRzIHRoYXQgaGF2ZSB0aGUgcHJvcGVydGllcyBvZiB0aGUgZ2l2ZW4gb2JqZWN0LFxuICAgICAqIGVsc2UgYGZhbHNlYC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBhbGlhcyBoZWFkLCB0YWtlXG4gICAgICogQGNhdGVnb3J5IEFycmF5c1xuICAgICAqIEBwYXJhbSB7QXJyYXl9IGFycmF5IFRoZSBhcnJheSB0byBxdWVyeS5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufE9iamVjdHxOdW1iZXJ8U3RyaW5nfSBbY2FsbGJhY2t8bl0gVGhlIGZ1bmN0aW9uIGNhbGxlZFxuICAgICAqICBwZXIgZWxlbWVudCBvciB0aGUgbnVtYmVyIG9mIGVsZW1lbnRzIHRvIHJldHVybi4gSWYgYSBwcm9wZXJ0eSBuYW1lIG9yXG4gICAgICogIG9iamVjdCBpcyBwYXNzZWQsIGl0IHdpbGwgYmUgdXNlZCB0byBjcmVhdGUgYSBcIl8ucGx1Y2tcIiBvciBcIl8ud2hlcmVcIlxuICAgICAqICBzdHlsZSBjYWxsYmFjaywgcmVzcGVjdGl2ZWx5LlxuICAgICAqIEBwYXJhbSB7TWl4ZWR9IFt0aGlzQXJnXSBUaGUgYHRoaXNgIGJpbmRpbmcgb2YgYGNhbGxiYWNrYC5cbiAgICAgKiBAcmV0dXJucyB7TWl4ZWR9IFJldHVybnMgdGhlIGZpcnN0IGVsZW1lbnQocykgb2YgYGFycmF5YC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5maXJzdChbMSwgMiwgM10pO1xuICAgICAqIC8vID0+IDFcbiAgICAgKlxuICAgICAqIF8uZmlyc3QoWzEsIDIsIDNdLCAyKTtcbiAgICAgKiAvLyA9PiBbMSwgMl1cbiAgICAgKlxuICAgICAqIF8uZmlyc3QoWzEsIDIsIDNdLCBmdW5jdGlvbihudW0pIHtcbiAgICAgKiAgIHJldHVybiBudW0gPCAzO1xuICAgICAqIH0pO1xuICAgICAqIC8vID0+IFsxLCAyXVxuICAgICAqXG4gICAgICogdmFyIGZvb2QgPSBbXG4gICAgICogICB7ICduYW1lJzogJ2JhbmFuYScsICdvcmdhbmljJzogdHJ1ZSB9LFxuICAgICAqICAgeyAnbmFtZSc6ICdiZWV0JywgICAnb3JnYW5pYyc6IGZhbHNlIH0sXG4gICAgICogXTtcbiAgICAgKlxuICAgICAqIC8vIHVzaW5nIFwiXy5wbHVja1wiIGNhbGxiYWNrIHNob3J0aGFuZFxuICAgICAqIF8uZmlyc3QoZm9vZCwgJ29yZ2FuaWMnKTtcbiAgICAgKiAvLyA9PiBbeyAnbmFtZSc6ICdiYW5hbmEnLCAnb3JnYW5pYyc6IHRydWUgfV1cbiAgICAgKlxuICAgICAqIHZhciBmb29kID0gW1xuICAgICAqICAgeyAnbmFtZSc6ICdhcHBsZScsICAndHlwZSc6ICdmcnVpdCcgfSxcbiAgICAgKiAgIHsgJ25hbWUnOiAnYmFuYW5hJywgJ3R5cGUnOiAnZnJ1aXQnIH0sXG4gICAgICogICB7ICduYW1lJzogJ2JlZXQnLCAgICd0eXBlJzogJ3ZlZ2V0YWJsZScgfVxuICAgICAqIF07XG4gICAgICpcbiAgICAgKiAvLyB1c2luZyBcIl8ud2hlcmVcIiBjYWxsYmFjayBzaG9ydGhhbmRcbiAgICAgKiBfLmZpcnN0KGZvb2QsIHsgJ3R5cGUnOiAnZnJ1aXQnIH0pO1xuICAgICAqIC8vID0+IFt7ICduYW1lJzogJ2FwcGxlJywgJ3R5cGUnOiAnZnJ1aXQnIH0sIHsgJ25hbWUnOiAnYmFuYW5hJywgJ3R5cGUnOiAnZnJ1aXQnIH1dXG4gICAgICovXG4gICAgZnVuY3Rpb24gZmlyc3QoYXJyYXksIGNhbGxiYWNrLCB0aGlzQXJnKSB7XG4gICAgICBpZiAoYXJyYXkpIHtcbiAgICAgICAgdmFyIG4gPSAwLFxuICAgICAgICAgICAgbGVuZ3RoID0gYXJyYXkubGVuZ3RoO1xuXG4gICAgICAgIGlmICh0eXBlb2YgY2FsbGJhY2sgIT0gJ251bWJlcicgJiYgY2FsbGJhY2sgIT0gbnVsbCkge1xuICAgICAgICAgIHZhciBpbmRleCA9IC0xO1xuICAgICAgICAgIGNhbGxiYWNrID0gbG9kYXNoLmNyZWF0ZUNhbGxiYWNrKGNhbGxiYWNrLCB0aGlzQXJnKTtcbiAgICAgICAgICB3aGlsZSAoKytpbmRleCA8IGxlbmd0aCAmJiBjYWxsYmFjayhhcnJheVtpbmRleF0sIGluZGV4LCBhcnJheSkpIHtcbiAgICAgICAgICAgIG4rKztcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgbiA9IGNhbGxiYWNrO1xuICAgICAgICAgIGlmIChuID09IG51bGwgfHwgdGhpc0FyZykge1xuICAgICAgICAgICAgcmV0dXJuIGFycmF5WzBdO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gc2xpY2UoYXJyYXksIDAsIG5hdGl2ZU1pbihuYXRpdmVNYXgoMCwgbiksIGxlbmd0aCkpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEZsYXR0ZW5zIGEgbmVzdGVkIGFycmF5ICh0aGUgbmVzdGluZyBjYW4gYmUgdG8gYW55IGRlcHRoKS4gSWYgYGlzU2hhbGxvd2BcbiAgICAgKiBpcyB0cnV0aHksIGBhcnJheWAgd2lsbCBvbmx5IGJlIGZsYXR0ZW5lZCBhIHNpbmdsZSBsZXZlbC4gSWYgYGNhbGxiYWNrYFxuICAgICAqIGlzIHBhc3NlZCwgZWFjaCBlbGVtZW50IG9mIGBhcnJheWAgaXMgcGFzc2VkIHRocm91Z2ggYSBgY2FsbGJhY2tgIGJlZm9yZVxuICAgICAqIGZsYXR0ZW5pbmcuIFRoZSBgY2FsbGJhY2tgIGlzIGJvdW5kIHRvIGB0aGlzQXJnYCBhbmQgaW52b2tlZCB3aXRoIHRocmVlXG4gICAgICogYXJndW1lbnRzOyAodmFsdWUsIGluZGV4LCBhcnJheSkuXG4gICAgICpcbiAgICAgKiBJZiBhIHByb3BlcnR5IG5hbWUgaXMgcGFzc2VkIGZvciBgY2FsbGJhY2tgLCB0aGUgY3JlYXRlZCBcIl8ucGx1Y2tcIiBzdHlsZVxuICAgICAqIGNhbGxiYWNrIHdpbGwgcmV0dXJuIHRoZSBwcm9wZXJ0eSB2YWx1ZSBvZiB0aGUgZ2l2ZW4gZWxlbWVudC5cbiAgICAgKlxuICAgICAqIElmIGFuIG9iamVjdCBpcyBwYXNzZWQgZm9yIGBjYWxsYmFja2AsIHRoZSBjcmVhdGVkIFwiXy53aGVyZVwiIHN0eWxlIGNhbGxiYWNrXG4gICAgICogd2lsbCByZXR1cm4gYHRydWVgIGZvciBlbGVtZW50cyB0aGF0IGhhdmUgdGhlIHByb3BlcnRpZXMgb2YgdGhlIGdpdmVuIG9iamVjdCxcbiAgICAgKiBlbHNlIGBmYWxzZWAuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgQXJyYXlzXG4gICAgICogQHBhcmFtIHtBcnJheX0gYXJyYXkgVGhlIGFycmF5IHRvIGZsYXR0ZW4uXG4gICAgICogQHBhcmFtIHtCb29sZWFufSBbaXNTaGFsbG93PWZhbHNlXSBBIGZsYWcgdG8gaW5kaWNhdGUgb25seSBmbGF0dGVuaW5nIGEgc2luZ2xlIGxldmVsLlxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb258T2JqZWN0fFN0cmluZ30gW2NhbGxiYWNrPWlkZW50aXR5XSBUaGUgZnVuY3Rpb24gY2FsbGVkIHBlclxuICAgICAqICBpdGVyYXRpb24uIElmIGEgcHJvcGVydHkgbmFtZSBvciBvYmplY3QgaXMgcGFzc2VkLCBpdCB3aWxsIGJlIHVzZWQgdG8gY3JlYXRlXG4gICAgICogIGEgXCJfLnBsdWNrXCIgb3IgXCJfLndoZXJlXCIgc3R5bGUgY2FsbGJhY2ssIHJlc3BlY3RpdmVseS5cbiAgICAgKiBAcGFyYW0ge01peGVkfSBbdGhpc0FyZ10gVGhlIGB0aGlzYCBiaW5kaW5nIG9mIGBjYWxsYmFja2AuXG4gICAgICogQHJldHVybnMge0FycmF5fSBSZXR1cm5zIGEgbmV3IGZsYXR0ZW5lZCBhcnJheS5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5mbGF0dGVuKFsxLCBbMl0sIFszLCBbWzRdXV1dKTtcbiAgICAgKiAvLyA9PiBbMSwgMiwgMywgNF07XG4gICAgICpcbiAgICAgKiBfLmZsYXR0ZW4oWzEsIFsyXSwgWzMsIFtbNF1dXV0sIHRydWUpO1xuICAgICAqIC8vID0+IFsxLCAyLCAzLCBbWzRdXV07XG4gICAgICpcbiAgICAgKiB2YXIgc3Rvb2dlcyA9IFtcbiAgICAgKiAgIHsgJ25hbWUnOiAnY3VybHknLCAncXVvdGVzJzogWydPaCwgYSB3aXNlIGd1eSwgZWg/JywgJ1BvaWZlY3QhJ10gfSxcbiAgICAgKiAgIHsgJ25hbWUnOiAnbW9lJywgJ3F1b3Rlcyc6IFsnU3ByZWFkIG91dCEnLCAnWW91IGtudWNrbGVoZWFkISddIH1cbiAgICAgKiBdO1xuICAgICAqXG4gICAgICogLy8gdXNpbmcgXCJfLnBsdWNrXCIgY2FsbGJhY2sgc2hvcnRoYW5kXG4gICAgICogXy5mbGF0dGVuKHN0b29nZXMsICdxdW90ZXMnKTtcbiAgICAgKiAvLyA9PiBbJ09oLCBhIHdpc2UgZ3V5LCBlaD8nLCAnUG9pZmVjdCEnLCAnU3ByZWFkIG91dCEnLCAnWW91IGtudWNrbGVoZWFkISddXG4gICAgICovXG4gICAgdmFyIGZsYXR0ZW4gPSBvdmVybG9hZFdyYXBwZXIoZnVuY3Rpb24gZmxhdHRlbihhcnJheSwgaXNTaGFsbG93LCBjYWxsYmFjaykge1xuICAgICAgdmFyIGluZGV4ID0gLTEsXG4gICAgICAgICAgbGVuZ3RoID0gYXJyYXkgPyBhcnJheS5sZW5ndGggOiAwLFxuICAgICAgICAgIHJlc3VsdCA9IFtdO1xuXG4gICAgICB3aGlsZSAoKytpbmRleCA8IGxlbmd0aCkge1xuICAgICAgICB2YXIgdmFsdWUgPSBhcnJheVtpbmRleF07XG4gICAgICAgIGlmIChjYWxsYmFjaykge1xuICAgICAgICAgIHZhbHVlID0gY2FsbGJhY2sodmFsdWUsIGluZGV4LCBhcnJheSk7XG4gICAgICAgIH1cbiAgICAgICAgLy8gcmVjdXJzaXZlbHkgZmxhdHRlbiBhcnJheXMgKHN1c2NlcHRpYmxlIHRvIGNhbGwgc3RhY2sgbGltaXRzKVxuICAgICAgICBpZiAoaXNBcnJheSh2YWx1ZSkpIHtcbiAgICAgICAgICBwdXNoLmFwcGx5KHJlc3VsdCwgaXNTaGFsbG93ID8gdmFsdWUgOiBmbGF0dGVuKHZhbHVlKSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcmVzdWx0LnB1c2godmFsdWUpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH0pO1xuXG4gICAgLyoqXG4gICAgICogR2V0cyB0aGUgaW5kZXggYXQgd2hpY2ggdGhlIGZpcnN0IG9jY3VycmVuY2Ugb2YgYHZhbHVlYCBpcyBmb3VuZCB1c2luZ1xuICAgICAqIHN0cmljdCBlcXVhbGl0eSBmb3IgY29tcGFyaXNvbnMsIGkuZS4gYD09PWAuIElmIHRoZSBgYXJyYXlgIGlzIGFscmVhZHlcbiAgICAgKiBzb3J0ZWQsIHBhc3NpbmcgYHRydWVgIGZvciBgZnJvbUluZGV4YCB3aWxsIHJ1biBhIGZhc3RlciBiaW5hcnkgc2VhcmNoLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IEFycmF5c1xuICAgICAqIEBwYXJhbSB7QXJyYXl9IGFycmF5IFRoZSBhcnJheSB0byBzZWFyY2guXG4gICAgICogQHBhcmFtIHtNaXhlZH0gdmFsdWUgVGhlIHZhbHVlIHRvIHNlYXJjaCBmb3IuXG4gICAgICogQHBhcmFtIHtCb29sZWFufE51bWJlcn0gW2Zyb21JbmRleD0wXSBUaGUgaW5kZXggdG8gc2VhcmNoIGZyb20gb3IgYHRydWVgIHRvXG4gICAgICogIHBlcmZvcm0gYSBiaW5hcnkgc2VhcmNoIG9uIGEgc29ydGVkIGBhcnJheWAuXG4gICAgICogQHJldHVybnMge051bWJlcn0gUmV0dXJucyB0aGUgaW5kZXggb2YgdGhlIG1hdGNoZWQgdmFsdWUgb3IgYC0xYC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5pbmRleE9mKFsxLCAyLCAzLCAxLCAyLCAzXSwgMik7XG4gICAgICogLy8gPT4gMVxuICAgICAqXG4gICAgICogXy5pbmRleE9mKFsxLCAyLCAzLCAxLCAyLCAzXSwgMiwgMyk7XG4gICAgICogLy8gPT4gNFxuICAgICAqXG4gICAgICogXy5pbmRleE9mKFsxLCAxLCAyLCAyLCAzLCAzXSwgMiwgdHJ1ZSk7XG4gICAgICogLy8gPT4gMlxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGluZGV4T2YoYXJyYXksIHZhbHVlLCBmcm9tSW5kZXgpIHtcbiAgICAgIGlmICh0eXBlb2YgZnJvbUluZGV4ID09ICdudW1iZXInKSB7XG4gICAgICAgIHZhciBsZW5ndGggPSBhcnJheSA/IGFycmF5Lmxlbmd0aCA6IDA7XG4gICAgICAgIGZyb21JbmRleCA9IChmcm9tSW5kZXggPCAwID8gbmF0aXZlTWF4KDAsIGxlbmd0aCArIGZyb21JbmRleCkgOiBmcm9tSW5kZXggfHwgMCk7XG4gICAgICB9IGVsc2UgaWYgKGZyb21JbmRleCkge1xuICAgICAgICB2YXIgaW5kZXggPSBzb3J0ZWRJbmRleChhcnJheSwgdmFsdWUpO1xuICAgICAgICByZXR1cm4gYXJyYXlbaW5kZXhdID09PSB2YWx1ZSA/IGluZGV4IDogLTE7XG4gICAgICB9XG4gICAgICByZXR1cm4gYXJyYXkgPyBiYXNpY0luZGV4T2YoYXJyYXksIHZhbHVlLCBmcm9tSW5kZXgpIDogLTE7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0cyBhbGwgYnV0IHRoZSBsYXN0IGVsZW1lbnQgb2YgYGFycmF5YC4gSWYgYSBudW1iZXIgYG5gIGlzIHBhc3NlZCwgdGhlXG4gICAgICogbGFzdCBgbmAgZWxlbWVudHMgYXJlIGV4Y2x1ZGVkIGZyb20gdGhlIHJlc3VsdC4gSWYgYSBgY2FsbGJhY2tgIGZ1bmN0aW9uXG4gICAgICogaXMgcGFzc2VkLCBlbGVtZW50cyBhdCB0aGUgZW5kIG9mIHRoZSBhcnJheSBhcmUgZXhjbHVkZWQgZnJvbSB0aGUgcmVzdWx0XG4gICAgICogYXMgbG9uZyBhcyB0aGUgYGNhbGxiYWNrYCByZXR1cm5zIHRydXRoeS4gVGhlIGBjYWxsYmFja2AgaXMgYm91bmQgdG9cbiAgICAgKiBgdGhpc0FyZ2AgYW5kIGludm9rZWQgd2l0aCB0aHJlZSBhcmd1bWVudHM7ICh2YWx1ZSwgaW5kZXgsIGFycmF5KS5cbiAgICAgKlxuICAgICAqIElmIGEgcHJvcGVydHkgbmFtZSBpcyBwYXNzZWQgZm9yIGBjYWxsYmFja2AsIHRoZSBjcmVhdGVkIFwiXy5wbHVja1wiIHN0eWxlXG4gICAgICogY2FsbGJhY2sgd2lsbCByZXR1cm4gdGhlIHByb3BlcnR5IHZhbHVlIG9mIHRoZSBnaXZlbiBlbGVtZW50LlxuICAgICAqXG4gICAgICogSWYgYW4gb2JqZWN0IGlzIHBhc3NlZCBmb3IgYGNhbGxiYWNrYCwgdGhlIGNyZWF0ZWQgXCJfLndoZXJlXCIgc3R5bGUgY2FsbGJhY2tcbiAgICAgKiB3aWxsIHJldHVybiBgdHJ1ZWAgZm9yIGVsZW1lbnRzIHRoYXQgaGF2ZSB0aGUgcHJvcGVydGllcyBvZiB0aGUgZ2l2ZW4gb2JqZWN0LFxuICAgICAqIGVsc2UgYGZhbHNlYC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBBcnJheXNcbiAgICAgKiBAcGFyYW0ge0FycmF5fSBhcnJheSBUaGUgYXJyYXkgdG8gcXVlcnkuXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbnxPYmplY3R8TnVtYmVyfFN0cmluZ30gW2NhbGxiYWNrfG49MV0gVGhlIGZ1bmN0aW9uIGNhbGxlZFxuICAgICAqICBwZXIgZWxlbWVudCBvciB0aGUgbnVtYmVyIG9mIGVsZW1lbnRzIHRvIGV4Y2x1ZGUuIElmIGEgcHJvcGVydHkgbmFtZSBvclxuICAgICAqICBvYmplY3QgaXMgcGFzc2VkLCBpdCB3aWxsIGJlIHVzZWQgdG8gY3JlYXRlIGEgXCJfLnBsdWNrXCIgb3IgXCJfLndoZXJlXCJcbiAgICAgKiAgc3R5bGUgY2FsbGJhY2ssIHJlc3BlY3RpdmVseS5cbiAgICAgKiBAcGFyYW0ge01peGVkfSBbdGhpc0FyZ10gVGhlIGB0aGlzYCBiaW5kaW5nIG9mIGBjYWxsYmFja2AuXG4gICAgICogQHJldHVybnMge0FycmF5fSBSZXR1cm5zIGEgc2xpY2Ugb2YgYGFycmF5YC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5pbml0aWFsKFsxLCAyLCAzXSk7XG4gICAgICogLy8gPT4gWzEsIDJdXG4gICAgICpcbiAgICAgKiBfLmluaXRpYWwoWzEsIDIsIDNdLCAyKTtcbiAgICAgKiAvLyA9PiBbMV1cbiAgICAgKlxuICAgICAqIF8uaW5pdGlhbChbMSwgMiwgM10sIGZ1bmN0aW9uKG51bSkge1xuICAgICAqICAgcmV0dXJuIG51bSA+IDE7XG4gICAgICogfSk7XG4gICAgICogLy8gPT4gWzFdXG4gICAgICpcbiAgICAgKiB2YXIgZm9vZCA9IFtcbiAgICAgKiAgIHsgJ25hbWUnOiAnYmVldCcsICAgJ29yZ2FuaWMnOiBmYWxzZSB9LFxuICAgICAqICAgeyAnbmFtZSc6ICdjYXJyb3QnLCAnb3JnYW5pYyc6IHRydWUgfVxuICAgICAqIF07XG4gICAgICpcbiAgICAgKiAvLyB1c2luZyBcIl8ucGx1Y2tcIiBjYWxsYmFjayBzaG9ydGhhbmRcbiAgICAgKiBfLmluaXRpYWwoZm9vZCwgJ29yZ2FuaWMnKTtcbiAgICAgKiAvLyA9PiBbeyAnbmFtZSc6ICdiZWV0JywgICAnb3JnYW5pYyc6IGZhbHNlIH1dXG4gICAgICpcbiAgICAgKiB2YXIgZm9vZCA9IFtcbiAgICAgKiAgIHsgJ25hbWUnOiAnYmFuYW5hJywgJ3R5cGUnOiAnZnJ1aXQnIH0sXG4gICAgICogICB7ICduYW1lJzogJ2JlZXQnLCAgICd0eXBlJzogJ3ZlZ2V0YWJsZScgfSxcbiAgICAgKiAgIHsgJ25hbWUnOiAnY2Fycm90JywgJ3R5cGUnOiAndmVnZXRhYmxlJyB9XG4gICAgICogXTtcbiAgICAgKlxuICAgICAqIC8vIHVzaW5nIFwiXy53aGVyZVwiIGNhbGxiYWNrIHNob3J0aGFuZFxuICAgICAqIF8uaW5pdGlhbChmb29kLCB7ICd0eXBlJzogJ3ZlZ2V0YWJsZScgfSk7XG4gICAgICogLy8gPT4gW3sgJ25hbWUnOiAnYmFuYW5hJywgJ3R5cGUnOiAnZnJ1aXQnIH1dXG4gICAgICovXG4gICAgZnVuY3Rpb24gaW5pdGlhbChhcnJheSwgY2FsbGJhY2ssIHRoaXNBcmcpIHtcbiAgICAgIGlmICghYXJyYXkpIHtcbiAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgfVxuICAgICAgdmFyIG4gPSAwLFxuICAgICAgICAgIGxlbmd0aCA9IGFycmF5Lmxlbmd0aDtcblxuICAgICAgaWYgKHR5cGVvZiBjYWxsYmFjayAhPSAnbnVtYmVyJyAmJiBjYWxsYmFjayAhPSBudWxsKSB7XG4gICAgICAgIHZhciBpbmRleCA9IGxlbmd0aDtcbiAgICAgICAgY2FsbGJhY2sgPSBsb2Rhc2guY3JlYXRlQ2FsbGJhY2soY2FsbGJhY2ssIHRoaXNBcmcpO1xuICAgICAgICB3aGlsZSAoaW5kZXgtLSAmJiBjYWxsYmFjayhhcnJheVtpbmRleF0sIGluZGV4LCBhcnJheSkpIHtcbiAgICAgICAgICBuKys7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIG4gPSAoY2FsbGJhY2sgPT0gbnVsbCB8fCB0aGlzQXJnKSA/IDEgOiBjYWxsYmFjayB8fCBuO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHNsaWNlKGFycmF5LCAwLCBuYXRpdmVNaW4obmF0aXZlTWF4KDAsIGxlbmd0aCAtIG4pLCBsZW5ndGgpKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDb21wdXRlcyB0aGUgaW50ZXJzZWN0aW9uIG9mIGFsbCB0aGUgcGFzc2VkLWluIGFycmF5cyB1c2luZyBzdHJpY3QgZXF1YWxpdHlcbiAgICAgKiBmb3IgY29tcGFyaXNvbnMsIGkuZS4gYD09PWAuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgQXJyYXlzXG4gICAgICogQHBhcmFtIHtBcnJheX0gW2FycmF5MSwgYXJyYXkyLCAuLi5dIEFycmF5cyB0byBwcm9jZXNzLlxuICAgICAqIEByZXR1cm5zIHtBcnJheX0gUmV0dXJucyBhIG5ldyBhcnJheSBvZiB1bmlxdWUgZWxlbWVudHMgdGhhdCBhcmUgcHJlc2VudFxuICAgICAqICBpbiAqKmFsbCoqIG9mIHRoZSBhcnJheXMuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8uaW50ZXJzZWN0aW9uKFsxLCAyLCAzXSwgWzEwMSwgMiwgMSwgMTBdLCBbMiwgMV0pO1xuICAgICAqIC8vID0+IFsxLCAyXVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGludGVyc2VjdGlvbihhcnJheSkge1xuICAgICAgdmFyIGFyZ3MgPSBhcmd1bWVudHMsXG4gICAgICAgICAgYXJnc0xlbmd0aCA9IGFyZ3MubGVuZ3RoLFxuICAgICAgICAgIGFyZ3NJbmRleCA9IC0xLFxuICAgICAgICAgIGNhY2hlcyA9IGdldEFycmF5KCksXG4gICAgICAgICAgaW5kZXggPSAtMSxcbiAgICAgICAgICBpbmRleE9mID0gZ2V0SW5kZXhPZigpLFxuICAgICAgICAgIGxlbmd0aCA9IGFycmF5ID8gYXJyYXkubGVuZ3RoIDogMCxcbiAgICAgICAgICByZXN1bHQgPSBbXSxcbiAgICAgICAgICBzZWVuID0gZ2V0QXJyYXkoKTtcblxuICAgICAgd2hpbGUgKCsrYXJnc0luZGV4IDwgYXJnc0xlbmd0aCkge1xuICAgICAgICB2YXIgdmFsdWUgPSBhcmdzW2FyZ3NJbmRleF07XG4gICAgICAgIGNhY2hlc1thcmdzSW5kZXhdID0gaW5kZXhPZiA9PT0gYmFzaWNJbmRleE9mICYmXG4gICAgICAgICAgKHZhbHVlID8gdmFsdWUubGVuZ3RoIDogMCkgPj0gbGFyZ2VBcnJheVNpemUgJiZcbiAgICAgICAgICBjcmVhdGVDYWNoZShhcmdzSW5kZXggPyBhcmdzW2FyZ3NJbmRleF0gOiBzZWVuKTtcbiAgICAgIH1cbiAgICAgIG91dGVyOlxuICAgICAgd2hpbGUgKCsraW5kZXggPCBsZW5ndGgpIHtcbiAgICAgICAgdmFyIGNhY2hlID0gY2FjaGVzWzBdO1xuICAgICAgICB2YWx1ZSA9IGFycmF5W2luZGV4XTtcblxuICAgICAgICBpZiAoKGNhY2hlID8gY2FjaGVJbmRleE9mKGNhY2hlLCB2YWx1ZSkgOiBpbmRleE9mKHNlZW4sIHZhbHVlKSkgPCAwKSB7XG4gICAgICAgICAgYXJnc0luZGV4ID0gYXJnc0xlbmd0aDtcbiAgICAgICAgICAoY2FjaGUgfHwgc2VlbikucHVzaCh2YWx1ZSk7XG4gICAgICAgICAgd2hpbGUgKC0tYXJnc0luZGV4KSB7XG4gICAgICAgICAgICBjYWNoZSA9IGNhY2hlc1thcmdzSW5kZXhdO1xuICAgICAgICAgICAgaWYgKChjYWNoZSA/IGNhY2hlSW5kZXhPZihjYWNoZSwgdmFsdWUpIDogaW5kZXhPZihhcmdzW2FyZ3NJbmRleF0sIHZhbHVlKSkgPCAwKSB7XG4gICAgICAgICAgICAgIGNvbnRpbnVlIG91dGVyO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICByZXN1bHQucHVzaCh2YWx1ZSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHdoaWxlIChhcmdzTGVuZ3RoLS0pIHtcbiAgICAgICAgY2FjaGUgPSBjYWNoZXNbYXJnc0xlbmd0aF07XG4gICAgICAgIGlmIChjYWNoZSkge1xuICAgICAgICAgIHJlbGVhc2VPYmplY3QoY2FjaGUpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZWxlYXNlQXJyYXkoY2FjaGVzKTtcbiAgICAgIHJlbGVhc2VBcnJheShzZWVuKTtcbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0cyB0aGUgbGFzdCBlbGVtZW50IG9mIHRoZSBgYXJyYXlgLiBJZiBhIG51bWJlciBgbmAgaXMgcGFzc2VkLCB0aGVcbiAgICAgKiBsYXN0IGBuYCBlbGVtZW50cyBvZiB0aGUgYGFycmF5YCBhcmUgcmV0dXJuZWQuIElmIGEgYGNhbGxiYWNrYCBmdW5jdGlvblxuICAgICAqIGlzIHBhc3NlZCwgZWxlbWVudHMgYXQgdGhlIGVuZCBvZiB0aGUgYXJyYXkgYXJlIHJldHVybmVkIGFzIGxvbmcgYXMgdGhlXG4gICAgICogYGNhbGxiYWNrYCByZXR1cm5zIHRydXRoeS4gVGhlIGBjYWxsYmFja2AgaXMgYm91bmQgdG8gYHRoaXNBcmdgIGFuZFxuICAgICAqIGludm9rZWQgd2l0aCB0aHJlZSBhcmd1bWVudHM7KHZhbHVlLCBpbmRleCwgYXJyYXkpLlxuICAgICAqXG4gICAgICpcbiAgICAgKiBJZiBhIHByb3BlcnR5IG5hbWUgaXMgcGFzc2VkIGZvciBgY2FsbGJhY2tgLCB0aGUgY3JlYXRlZCBcIl8ucGx1Y2tcIiBzdHlsZVxuICAgICAqIGNhbGxiYWNrIHdpbGwgcmV0dXJuIHRoZSBwcm9wZXJ0eSB2YWx1ZSBvZiB0aGUgZ2l2ZW4gZWxlbWVudC5cbiAgICAgKlxuICAgICAqIElmIGFuIG9iamVjdCBpcyBwYXNzZWQgZm9yIGBjYWxsYmFja2AsIHRoZSBjcmVhdGVkIFwiXy53aGVyZVwiIHN0eWxlIGNhbGxiYWNrXG4gICAgICogd2lsbCByZXR1cm4gYHRydWVgIGZvciBlbGVtZW50cyB0aGF0IGhhdmUgdGhlIHByb3BlcnRpZXMgb2YgdGhlIGdpdmVuIG9iamVjdCxcbiAgICAgKiBlbHNlIGBmYWxzZWAuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgQXJyYXlzXG4gICAgICogQHBhcmFtIHtBcnJheX0gYXJyYXkgVGhlIGFycmF5IHRvIHF1ZXJ5LlxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb258T2JqZWN0fE51bWJlcnxTdHJpbmd9IFtjYWxsYmFja3xuXSBUaGUgZnVuY3Rpb24gY2FsbGVkXG4gICAgICogIHBlciBlbGVtZW50IG9yIHRoZSBudW1iZXIgb2YgZWxlbWVudHMgdG8gcmV0dXJuLiBJZiBhIHByb3BlcnR5IG5hbWUgb3JcbiAgICAgKiAgb2JqZWN0IGlzIHBhc3NlZCwgaXQgd2lsbCBiZSB1c2VkIHRvIGNyZWF0ZSBhIFwiXy5wbHVja1wiIG9yIFwiXy53aGVyZVwiXG4gICAgICogIHN0eWxlIGNhbGxiYWNrLCByZXNwZWN0aXZlbHkuXG4gICAgICogQHBhcmFtIHtNaXhlZH0gW3RoaXNBcmddIFRoZSBgdGhpc2AgYmluZGluZyBvZiBgY2FsbGJhY2tgLlxuICAgICAqIEByZXR1cm5zIHtNaXhlZH0gUmV0dXJucyB0aGUgbGFzdCBlbGVtZW50KHMpIG9mIGBhcnJheWAuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8ubGFzdChbMSwgMiwgM10pO1xuICAgICAqIC8vID0+IDNcbiAgICAgKlxuICAgICAqIF8ubGFzdChbMSwgMiwgM10sIDIpO1xuICAgICAqIC8vID0+IFsyLCAzXVxuICAgICAqXG4gICAgICogXy5sYXN0KFsxLCAyLCAzXSwgZnVuY3Rpb24obnVtKSB7XG4gICAgICogICByZXR1cm4gbnVtID4gMTtcbiAgICAgKiB9KTtcbiAgICAgKiAvLyA9PiBbMiwgM11cbiAgICAgKlxuICAgICAqIHZhciBmb29kID0gW1xuICAgICAqICAgeyAnbmFtZSc6ICdiZWV0JywgICAnb3JnYW5pYyc6IGZhbHNlIH0sXG4gICAgICogICB7ICduYW1lJzogJ2NhcnJvdCcsICdvcmdhbmljJzogdHJ1ZSB9XG4gICAgICogXTtcbiAgICAgKlxuICAgICAqIC8vIHVzaW5nIFwiXy5wbHVja1wiIGNhbGxiYWNrIHNob3J0aGFuZFxuICAgICAqIF8ubGFzdChmb29kLCAnb3JnYW5pYycpO1xuICAgICAqIC8vID0+IFt7ICduYW1lJzogJ2NhcnJvdCcsICdvcmdhbmljJzogdHJ1ZSB9XVxuICAgICAqXG4gICAgICogdmFyIGZvb2QgPSBbXG4gICAgICogICB7ICduYW1lJzogJ2JhbmFuYScsICd0eXBlJzogJ2ZydWl0JyB9LFxuICAgICAqICAgeyAnbmFtZSc6ICdiZWV0JywgICAndHlwZSc6ICd2ZWdldGFibGUnIH0sXG4gICAgICogICB7ICduYW1lJzogJ2NhcnJvdCcsICd0eXBlJzogJ3ZlZ2V0YWJsZScgfVxuICAgICAqIF07XG4gICAgICpcbiAgICAgKiAvLyB1c2luZyBcIl8ud2hlcmVcIiBjYWxsYmFjayBzaG9ydGhhbmRcbiAgICAgKiBfLmxhc3QoZm9vZCwgeyAndHlwZSc6ICd2ZWdldGFibGUnIH0pO1xuICAgICAqIC8vID0+IFt7ICduYW1lJzogJ2JlZXQnLCAndHlwZSc6ICd2ZWdldGFibGUnIH0sIHsgJ25hbWUnOiAnY2Fycm90JywgJ3R5cGUnOiAndmVnZXRhYmxlJyB9XVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGxhc3QoYXJyYXksIGNhbGxiYWNrLCB0aGlzQXJnKSB7XG4gICAgICBpZiAoYXJyYXkpIHtcbiAgICAgICAgdmFyIG4gPSAwLFxuICAgICAgICAgICAgbGVuZ3RoID0gYXJyYXkubGVuZ3RoO1xuXG4gICAgICAgIGlmICh0eXBlb2YgY2FsbGJhY2sgIT0gJ251bWJlcicgJiYgY2FsbGJhY2sgIT0gbnVsbCkge1xuICAgICAgICAgIHZhciBpbmRleCA9IGxlbmd0aDtcbiAgICAgICAgICBjYWxsYmFjayA9IGxvZGFzaC5jcmVhdGVDYWxsYmFjayhjYWxsYmFjaywgdGhpc0FyZyk7XG4gICAgICAgICAgd2hpbGUgKGluZGV4LS0gJiYgY2FsbGJhY2soYXJyYXlbaW5kZXhdLCBpbmRleCwgYXJyYXkpKSB7XG4gICAgICAgICAgICBuKys7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIG4gPSBjYWxsYmFjaztcbiAgICAgICAgICBpZiAobiA9PSBudWxsIHx8IHRoaXNBcmcpIHtcbiAgICAgICAgICAgIHJldHVybiBhcnJheVtsZW5ndGggLSAxXTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHNsaWNlKGFycmF5LCBuYXRpdmVNYXgoMCwgbGVuZ3RoIC0gbikpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldHMgdGhlIGluZGV4IGF0IHdoaWNoIHRoZSBsYXN0IG9jY3VycmVuY2Ugb2YgYHZhbHVlYCBpcyBmb3VuZCB1c2luZyBzdHJpY3RcbiAgICAgKiBlcXVhbGl0eSBmb3IgY29tcGFyaXNvbnMsIGkuZS4gYD09PWAuIElmIGBmcm9tSW5kZXhgIGlzIG5lZ2F0aXZlLCBpdCBpcyB1c2VkXG4gICAgICogYXMgdGhlIG9mZnNldCBmcm9tIHRoZSBlbmQgb2YgdGhlIGNvbGxlY3Rpb24uXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgQXJyYXlzXG4gICAgICogQHBhcmFtIHtBcnJheX0gYXJyYXkgVGhlIGFycmF5IHRvIHNlYXJjaC5cbiAgICAgKiBAcGFyYW0ge01peGVkfSB2YWx1ZSBUaGUgdmFsdWUgdG8gc2VhcmNoIGZvci5cbiAgICAgKiBAcGFyYW0ge051bWJlcn0gW2Zyb21JbmRleD1hcnJheS5sZW5ndGgtMV0gVGhlIGluZGV4IHRvIHNlYXJjaCBmcm9tLlxuICAgICAqIEByZXR1cm5zIHtOdW1iZXJ9IFJldHVybnMgdGhlIGluZGV4IG9mIHRoZSBtYXRjaGVkIHZhbHVlIG9yIGAtMWAuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8ubGFzdEluZGV4T2YoWzEsIDIsIDMsIDEsIDIsIDNdLCAyKTtcbiAgICAgKiAvLyA9PiA0XG4gICAgICpcbiAgICAgKiBfLmxhc3RJbmRleE9mKFsxLCAyLCAzLCAxLCAyLCAzXSwgMiwgMyk7XG4gICAgICogLy8gPT4gMVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGxhc3RJbmRleE9mKGFycmF5LCB2YWx1ZSwgZnJvbUluZGV4KSB7XG4gICAgICB2YXIgaW5kZXggPSBhcnJheSA/IGFycmF5Lmxlbmd0aCA6IDA7XG4gICAgICBpZiAodHlwZW9mIGZyb21JbmRleCA9PSAnbnVtYmVyJykge1xuICAgICAgICBpbmRleCA9IChmcm9tSW5kZXggPCAwID8gbmF0aXZlTWF4KDAsIGluZGV4ICsgZnJvbUluZGV4KSA6IG5hdGl2ZU1pbihmcm9tSW5kZXgsIGluZGV4IC0gMSkpICsgMTtcbiAgICAgIH1cbiAgICAgIHdoaWxlIChpbmRleC0tKSB7XG4gICAgICAgIGlmIChhcnJheVtpbmRleF0gPT09IHZhbHVlKSB7XG4gICAgICAgICAgcmV0dXJuIGluZGV4O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gLTE7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhbiBhcnJheSBvZiBudW1iZXJzIChwb3NpdGl2ZSBhbmQvb3IgbmVnYXRpdmUpIHByb2dyZXNzaW5nIGZyb21cbiAgICAgKiBgc3RhcnRgIHVwIHRvIGJ1dCBub3QgaW5jbHVkaW5nIGBlbmRgLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IEFycmF5c1xuICAgICAqIEBwYXJhbSB7TnVtYmVyfSBbc3RhcnQ9MF0gVGhlIHN0YXJ0IG9mIHRoZSByYW5nZS5cbiAgICAgKiBAcGFyYW0ge051bWJlcn0gZW5kIFRoZSBlbmQgb2YgdGhlIHJhbmdlLlxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSBbc3RlcD0xXSBUaGUgdmFsdWUgdG8gaW5jcmVtZW50IG9yIGRlY3JlbWVudCBieS5cbiAgICAgKiBAcmV0dXJucyB7QXJyYXl9IFJldHVybnMgYSBuZXcgcmFuZ2UgYXJyYXkuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8ucmFuZ2UoMTApO1xuICAgICAqIC8vID0+IFswLCAxLCAyLCAzLCA0LCA1LCA2LCA3LCA4LCA5XVxuICAgICAqXG4gICAgICogXy5yYW5nZSgxLCAxMSk7XG4gICAgICogLy8gPT4gWzEsIDIsIDMsIDQsIDUsIDYsIDcsIDgsIDksIDEwXVxuICAgICAqXG4gICAgICogXy5yYW5nZSgwLCAzMCwgNSk7XG4gICAgICogLy8gPT4gWzAsIDUsIDEwLCAxNSwgMjAsIDI1XVxuICAgICAqXG4gICAgICogXy5yYW5nZSgwLCAtMTAsIC0xKTtcbiAgICAgKiAvLyA9PiBbMCwgLTEsIC0yLCAtMywgLTQsIC01LCAtNiwgLTcsIC04LCAtOV1cbiAgICAgKlxuICAgICAqIF8ucmFuZ2UoMCk7XG4gICAgICogLy8gPT4gW11cbiAgICAgKi9cbiAgICBmdW5jdGlvbiByYW5nZShzdGFydCwgZW5kLCBzdGVwKSB7XG4gICAgICBzdGFydCA9ICtzdGFydCB8fCAwO1xuICAgICAgc3RlcCA9ICtzdGVwIHx8IDE7XG5cbiAgICAgIGlmIChlbmQgPT0gbnVsbCkge1xuICAgICAgICBlbmQgPSBzdGFydDtcbiAgICAgICAgc3RhcnQgPSAwO1xuICAgICAgfVxuICAgICAgLy8gdXNlIGBBcnJheShsZW5ndGgpYCBzbyBWOCB3aWxsIGF2b2lkIHRoZSBzbG93ZXIgXCJkaWN0aW9uYXJ5XCIgbW9kZVxuICAgICAgLy8gaHR0cDovL3lvdXR1LmJlL1hBcUlwR1U4WlprI3Q9MTdtMjVzXG4gICAgICB2YXIgaW5kZXggPSAtMSxcbiAgICAgICAgICBsZW5ndGggPSBuYXRpdmVNYXgoMCwgY2VpbCgoZW5kIC0gc3RhcnQpIC8gc3RlcCkpLFxuICAgICAgICAgIHJlc3VsdCA9IEFycmF5KGxlbmd0aCk7XG5cbiAgICAgIHdoaWxlICgrK2luZGV4IDwgbGVuZ3RoKSB7XG4gICAgICAgIHJlc3VsdFtpbmRleF0gPSBzdGFydDtcbiAgICAgICAgc3RhcnQgKz0gc3RlcDtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVGhlIG9wcG9zaXRlIG9mIGBfLmluaXRpYWxgLCB0aGlzIG1ldGhvZCBnZXRzIGFsbCBidXQgdGhlIGZpcnN0IHZhbHVlIG9mXG4gICAgICogYGFycmF5YC4gSWYgYSBudW1iZXIgYG5gIGlzIHBhc3NlZCwgdGhlIGZpcnN0IGBuYCB2YWx1ZXMgYXJlIGV4Y2x1ZGVkIGZyb21cbiAgICAgKiB0aGUgcmVzdWx0LiBJZiBhIGBjYWxsYmFja2AgZnVuY3Rpb24gaXMgcGFzc2VkLCBlbGVtZW50cyBhdCB0aGUgYmVnaW5uaW5nXG4gICAgICogb2YgdGhlIGFycmF5IGFyZSBleGNsdWRlZCBmcm9tIHRoZSByZXN1bHQgYXMgbG9uZyBhcyB0aGUgYGNhbGxiYWNrYCByZXR1cm5zXG4gICAgICogdHJ1dGh5LiBUaGUgYGNhbGxiYWNrYCBpcyBib3VuZCB0byBgdGhpc0FyZ2AgYW5kIGludm9rZWQgd2l0aCB0aHJlZVxuICAgICAqIGFyZ3VtZW50czsgKHZhbHVlLCBpbmRleCwgYXJyYXkpLlxuICAgICAqXG4gICAgICogSWYgYSBwcm9wZXJ0eSBuYW1lIGlzIHBhc3NlZCBmb3IgYGNhbGxiYWNrYCwgdGhlIGNyZWF0ZWQgXCJfLnBsdWNrXCIgc3R5bGVcbiAgICAgKiBjYWxsYmFjayB3aWxsIHJldHVybiB0aGUgcHJvcGVydHkgdmFsdWUgb2YgdGhlIGdpdmVuIGVsZW1lbnQuXG4gICAgICpcbiAgICAgKiBJZiBhbiBvYmplY3QgaXMgcGFzc2VkIGZvciBgY2FsbGJhY2tgLCB0aGUgY3JlYXRlZCBcIl8ud2hlcmVcIiBzdHlsZSBjYWxsYmFja1xuICAgICAqIHdpbGwgcmV0dXJuIGB0cnVlYCBmb3IgZWxlbWVudHMgdGhhdCBoYXZlIHRoZSBwcm9wZXJ0aWVzIG9mIHRoZSBnaXZlbiBvYmplY3QsXG4gICAgICogZWxzZSBgZmFsc2VgLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGFsaWFzIGRyb3AsIHRhaWxcbiAgICAgKiBAY2F0ZWdvcnkgQXJyYXlzXG4gICAgICogQHBhcmFtIHtBcnJheX0gYXJyYXkgVGhlIGFycmF5IHRvIHF1ZXJ5LlxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb258T2JqZWN0fE51bWJlcnxTdHJpbmd9IFtjYWxsYmFja3xuPTFdIFRoZSBmdW5jdGlvbiBjYWxsZWRcbiAgICAgKiAgcGVyIGVsZW1lbnQgb3IgdGhlIG51bWJlciBvZiBlbGVtZW50cyB0byBleGNsdWRlLiBJZiBhIHByb3BlcnR5IG5hbWUgb3JcbiAgICAgKiAgb2JqZWN0IGlzIHBhc3NlZCwgaXQgd2lsbCBiZSB1c2VkIHRvIGNyZWF0ZSBhIFwiXy5wbHVja1wiIG9yIFwiXy53aGVyZVwiXG4gICAgICogIHN0eWxlIGNhbGxiYWNrLCByZXNwZWN0aXZlbHkuXG4gICAgICogQHBhcmFtIHtNaXhlZH0gW3RoaXNBcmddIFRoZSBgdGhpc2AgYmluZGluZyBvZiBgY2FsbGJhY2tgLlxuICAgICAqIEByZXR1cm5zIHtBcnJheX0gUmV0dXJucyBhIHNsaWNlIG9mIGBhcnJheWAuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8ucmVzdChbMSwgMiwgM10pO1xuICAgICAqIC8vID0+IFsyLCAzXVxuICAgICAqXG4gICAgICogXy5yZXN0KFsxLCAyLCAzXSwgMik7XG4gICAgICogLy8gPT4gWzNdXG4gICAgICpcbiAgICAgKiBfLnJlc3QoWzEsIDIsIDNdLCBmdW5jdGlvbihudW0pIHtcbiAgICAgKiAgIHJldHVybiBudW0gPCAzO1xuICAgICAqIH0pO1xuICAgICAqIC8vID0+IFszXVxuICAgICAqXG4gICAgICogdmFyIGZvb2QgPSBbXG4gICAgICogICB7ICduYW1lJzogJ2JhbmFuYScsICdvcmdhbmljJzogdHJ1ZSB9LFxuICAgICAqICAgeyAnbmFtZSc6ICdiZWV0JywgICAnb3JnYW5pYyc6IGZhbHNlIH0sXG4gICAgICogXTtcbiAgICAgKlxuICAgICAqIC8vIHVzaW5nIFwiXy5wbHVja1wiIGNhbGxiYWNrIHNob3J0aGFuZFxuICAgICAqIF8ucmVzdChmb29kLCAnb3JnYW5pYycpO1xuICAgICAqIC8vID0+IFt7ICduYW1lJzogJ2JlZXQnLCAnb3JnYW5pYyc6IGZhbHNlIH1dXG4gICAgICpcbiAgICAgKiB2YXIgZm9vZCA9IFtcbiAgICAgKiAgIHsgJ25hbWUnOiAnYXBwbGUnLCAgJ3R5cGUnOiAnZnJ1aXQnIH0sXG4gICAgICogICB7ICduYW1lJzogJ2JhbmFuYScsICd0eXBlJzogJ2ZydWl0JyB9LFxuICAgICAqICAgeyAnbmFtZSc6ICdiZWV0JywgICAndHlwZSc6ICd2ZWdldGFibGUnIH1cbiAgICAgKiBdO1xuICAgICAqXG4gICAgICogLy8gdXNpbmcgXCJfLndoZXJlXCIgY2FsbGJhY2sgc2hvcnRoYW5kXG4gICAgICogXy5yZXN0KGZvb2QsIHsgJ3R5cGUnOiAnZnJ1aXQnIH0pO1xuICAgICAqIC8vID0+IFt7ICduYW1lJzogJ2JlZXQnLCAndHlwZSc6ICd2ZWdldGFibGUnIH1dXG4gICAgICovXG4gICAgZnVuY3Rpb24gcmVzdChhcnJheSwgY2FsbGJhY2ssIHRoaXNBcmcpIHtcbiAgICAgIGlmICh0eXBlb2YgY2FsbGJhY2sgIT0gJ251bWJlcicgJiYgY2FsbGJhY2sgIT0gbnVsbCkge1xuICAgICAgICB2YXIgbiA9IDAsXG4gICAgICAgICAgICBpbmRleCA9IC0xLFxuICAgICAgICAgICAgbGVuZ3RoID0gYXJyYXkgPyBhcnJheS5sZW5ndGggOiAwO1xuXG4gICAgICAgIGNhbGxiYWNrID0gbG9kYXNoLmNyZWF0ZUNhbGxiYWNrKGNhbGxiYWNrLCB0aGlzQXJnKTtcbiAgICAgICAgd2hpbGUgKCsraW5kZXggPCBsZW5ndGggJiYgY2FsbGJhY2soYXJyYXlbaW5kZXhdLCBpbmRleCwgYXJyYXkpKSB7XG4gICAgICAgICAgbisrO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBuID0gKGNhbGxiYWNrID09IG51bGwgfHwgdGhpc0FyZykgPyAxIDogbmF0aXZlTWF4KDAsIGNhbGxiYWNrKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBzbGljZShhcnJheSwgbik7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVXNlcyBhIGJpbmFyeSBzZWFyY2ggdG8gZGV0ZXJtaW5lIHRoZSBzbWFsbGVzdCBpbmRleCBhdCB3aGljaCB0aGUgYHZhbHVlYFxuICAgICAqIHNob3VsZCBiZSBpbnNlcnRlZCBpbnRvIGBhcnJheWAgaW4gb3JkZXIgdG8gbWFpbnRhaW4gdGhlIHNvcnQgb3JkZXIgb2YgdGhlXG4gICAgICogc29ydGVkIGBhcnJheWAuIElmIGBjYWxsYmFja2AgaXMgcGFzc2VkLCBpdCB3aWxsIGJlIGV4ZWN1dGVkIGZvciBgdmFsdWVgIGFuZFxuICAgICAqIGVhY2ggZWxlbWVudCBpbiBgYXJyYXlgIHRvIGNvbXB1dGUgdGhlaXIgc29ydCByYW5raW5nLiBUaGUgYGNhbGxiYWNrYCBpc1xuICAgICAqIGJvdW5kIHRvIGB0aGlzQXJnYCBhbmQgaW52b2tlZCB3aXRoIG9uZSBhcmd1bWVudDsgKHZhbHVlKS5cbiAgICAgKlxuICAgICAqIElmIGEgcHJvcGVydHkgbmFtZSBpcyBwYXNzZWQgZm9yIGBjYWxsYmFja2AsIHRoZSBjcmVhdGVkIFwiXy5wbHVja1wiIHN0eWxlXG4gICAgICogY2FsbGJhY2sgd2lsbCByZXR1cm4gdGhlIHByb3BlcnR5IHZhbHVlIG9mIHRoZSBnaXZlbiBlbGVtZW50LlxuICAgICAqXG4gICAgICogSWYgYW4gb2JqZWN0IGlzIHBhc3NlZCBmb3IgYGNhbGxiYWNrYCwgdGhlIGNyZWF0ZWQgXCJfLndoZXJlXCIgc3R5bGUgY2FsbGJhY2tcbiAgICAgKiB3aWxsIHJldHVybiBgdHJ1ZWAgZm9yIGVsZW1lbnRzIHRoYXQgaGF2ZSB0aGUgcHJvcGVydGllcyBvZiB0aGUgZ2l2ZW4gb2JqZWN0LFxuICAgICAqIGVsc2UgYGZhbHNlYC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBBcnJheXNcbiAgICAgKiBAcGFyYW0ge0FycmF5fSBhcnJheSBUaGUgYXJyYXkgdG8gaW5zcGVjdC5cbiAgICAgKiBAcGFyYW0ge01peGVkfSB2YWx1ZSBUaGUgdmFsdWUgdG8gZXZhbHVhdGUuXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbnxPYmplY3R8U3RyaW5nfSBbY2FsbGJhY2s9aWRlbnRpdHldIFRoZSBmdW5jdGlvbiBjYWxsZWQgcGVyXG4gICAgICogIGl0ZXJhdGlvbi4gSWYgYSBwcm9wZXJ0eSBuYW1lIG9yIG9iamVjdCBpcyBwYXNzZWQsIGl0IHdpbGwgYmUgdXNlZCB0byBjcmVhdGVcbiAgICAgKiAgYSBcIl8ucGx1Y2tcIiBvciBcIl8ud2hlcmVcIiBzdHlsZSBjYWxsYmFjaywgcmVzcGVjdGl2ZWx5LlxuICAgICAqIEBwYXJhbSB7TWl4ZWR9IFt0aGlzQXJnXSBUaGUgYHRoaXNgIGJpbmRpbmcgb2YgYGNhbGxiYWNrYC5cbiAgICAgKiBAcmV0dXJucyB7TnVtYmVyfSBSZXR1cm5zIHRoZSBpbmRleCBhdCB3aGljaCB0aGUgdmFsdWUgc2hvdWxkIGJlIGluc2VydGVkXG4gICAgICogIGludG8gYGFycmF5YC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5zb3J0ZWRJbmRleChbMjAsIDMwLCA1MF0sIDQwKTtcbiAgICAgKiAvLyA9PiAyXG4gICAgICpcbiAgICAgKiAvLyB1c2luZyBcIl8ucGx1Y2tcIiBjYWxsYmFjayBzaG9ydGhhbmRcbiAgICAgKiBfLnNvcnRlZEluZGV4KFt7ICd4JzogMjAgfSwgeyAneCc6IDMwIH0sIHsgJ3gnOiA1MCB9XSwgeyAneCc6IDQwIH0sICd4Jyk7XG4gICAgICogLy8gPT4gMlxuICAgICAqXG4gICAgICogdmFyIGRpY3QgPSB7XG4gICAgICogICAnd29yZFRvTnVtYmVyJzogeyAndHdlbnR5JzogMjAsICd0aGlydHknOiAzMCwgJ2ZvdXJ0eSc6IDQwLCAnZmlmdHknOiA1MCB9XG4gICAgICogfTtcbiAgICAgKlxuICAgICAqIF8uc29ydGVkSW5kZXgoWyd0d2VudHknLCAndGhpcnR5JywgJ2ZpZnR5J10sICdmb3VydHknLCBmdW5jdGlvbih3b3JkKSB7XG4gICAgICogICByZXR1cm4gZGljdC53b3JkVG9OdW1iZXJbd29yZF07XG4gICAgICogfSk7XG4gICAgICogLy8gPT4gMlxuICAgICAqXG4gICAgICogXy5zb3J0ZWRJbmRleChbJ3R3ZW50eScsICd0aGlydHknLCAnZmlmdHknXSwgJ2ZvdXJ0eScsIGZ1bmN0aW9uKHdvcmQpIHtcbiAgICAgKiAgIHJldHVybiB0aGlzLndvcmRUb051bWJlclt3b3JkXTtcbiAgICAgKiB9LCBkaWN0KTtcbiAgICAgKiAvLyA9PiAyXG4gICAgICovXG4gICAgZnVuY3Rpb24gc29ydGVkSW5kZXgoYXJyYXksIHZhbHVlLCBjYWxsYmFjaywgdGhpc0FyZykge1xuICAgICAgdmFyIGxvdyA9IDAsXG4gICAgICAgICAgaGlnaCA9IGFycmF5ID8gYXJyYXkubGVuZ3RoIDogbG93O1xuXG4gICAgICAvLyBleHBsaWNpdGx5IHJlZmVyZW5jZSBgaWRlbnRpdHlgIGZvciBiZXR0ZXIgaW5saW5pbmcgaW4gRmlyZWZveFxuICAgICAgY2FsbGJhY2sgPSBjYWxsYmFjayA/IGxvZGFzaC5jcmVhdGVDYWxsYmFjayhjYWxsYmFjaywgdGhpc0FyZywgMSkgOiBpZGVudGl0eTtcbiAgICAgIHZhbHVlID0gY2FsbGJhY2sodmFsdWUpO1xuXG4gICAgICB3aGlsZSAobG93IDwgaGlnaCkge1xuICAgICAgICB2YXIgbWlkID0gKGxvdyArIGhpZ2gpID4+PiAxO1xuICAgICAgICAoY2FsbGJhY2soYXJyYXlbbWlkXSkgPCB2YWx1ZSlcbiAgICAgICAgICA/IGxvdyA9IG1pZCArIDFcbiAgICAgICAgICA6IGhpZ2ggPSBtaWQ7XG4gICAgICB9XG4gICAgICByZXR1cm4gbG93O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENvbXB1dGVzIHRoZSB1bmlvbiBvZiB0aGUgcGFzc2VkLWluIGFycmF5cyB1c2luZyBzdHJpY3QgZXF1YWxpdHkgZm9yXG4gICAgICogY29tcGFyaXNvbnMsIGkuZS4gYD09PWAuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgQXJyYXlzXG4gICAgICogQHBhcmFtIHtBcnJheX0gW2FycmF5MSwgYXJyYXkyLCAuLi5dIEFycmF5cyB0byBwcm9jZXNzLlxuICAgICAqIEByZXR1cm5zIHtBcnJheX0gUmV0dXJucyBhIG5ldyBhcnJheSBvZiB1bmlxdWUgdmFsdWVzLCBpbiBvcmRlciwgdGhhdCBhcmVcbiAgICAgKiAgcHJlc2VudCBpbiBvbmUgb3IgbW9yZSBvZiB0aGUgYXJyYXlzLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLnVuaW9uKFsxLCAyLCAzXSwgWzEwMSwgMiwgMSwgMTBdLCBbMiwgMV0pO1xuICAgICAqIC8vID0+IFsxLCAyLCAzLCAxMDEsIDEwXVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIHVuaW9uKGFycmF5KSB7XG4gICAgICBpZiAoIWlzQXJyYXkoYXJyYXkpKSB7XG4gICAgICAgIGFyZ3VtZW50c1swXSA9IGFycmF5ID8gbmF0aXZlU2xpY2UuY2FsbChhcnJheSkgOiBhcnJheVJlZjtcbiAgICAgIH1cbiAgICAgIHJldHVybiB1bmlxKGNvbmNhdC5hcHBseShhcnJheVJlZiwgYXJndW1lbnRzKSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhIGR1cGxpY2F0ZS12YWx1ZS1mcmVlIHZlcnNpb24gb2YgdGhlIGBhcnJheWAgdXNpbmcgc3RyaWN0IGVxdWFsaXR5XG4gICAgICogZm9yIGNvbXBhcmlzb25zLCBpLmUuIGA9PT1gLiBJZiB0aGUgYGFycmF5YCBpcyBhbHJlYWR5IHNvcnRlZCwgcGFzc2luZyBgdHJ1ZWBcbiAgICAgKiBmb3IgYGlzU29ydGVkYCB3aWxsIHJ1biBhIGZhc3RlciBhbGdvcml0aG0uIElmIGBjYWxsYmFja2AgaXMgcGFzc2VkLCBlYWNoXG4gICAgICogZWxlbWVudCBvZiBgYXJyYXlgIGlzIHBhc3NlZCB0aHJvdWdoIHRoZSBgY2FsbGJhY2tgIGJlZm9yZSB1bmlxdWVuZXNzIGlzIGNvbXB1dGVkLlxuICAgICAqIFRoZSBgY2FsbGJhY2tgIGlzIGJvdW5kIHRvIGB0aGlzQXJnYCBhbmQgaW52b2tlZCB3aXRoIHRocmVlIGFyZ3VtZW50czsgKHZhbHVlLCBpbmRleCwgYXJyYXkpLlxuICAgICAqXG4gICAgICogSWYgYSBwcm9wZXJ0eSBuYW1lIGlzIHBhc3NlZCBmb3IgYGNhbGxiYWNrYCwgdGhlIGNyZWF0ZWQgXCJfLnBsdWNrXCIgc3R5bGVcbiAgICAgKiBjYWxsYmFjayB3aWxsIHJldHVybiB0aGUgcHJvcGVydHkgdmFsdWUgb2YgdGhlIGdpdmVuIGVsZW1lbnQuXG4gICAgICpcbiAgICAgKiBJZiBhbiBvYmplY3QgaXMgcGFzc2VkIGZvciBgY2FsbGJhY2tgLCB0aGUgY3JlYXRlZCBcIl8ud2hlcmVcIiBzdHlsZSBjYWxsYmFja1xuICAgICAqIHdpbGwgcmV0dXJuIGB0cnVlYCBmb3IgZWxlbWVudHMgdGhhdCBoYXZlIHRoZSBwcm9wZXJ0aWVzIG9mIHRoZSBnaXZlbiBvYmplY3QsXG4gICAgICogZWxzZSBgZmFsc2VgLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGFsaWFzIHVuaXF1ZVxuICAgICAqIEBjYXRlZ29yeSBBcnJheXNcbiAgICAgKiBAcGFyYW0ge0FycmF5fSBhcnJheSBUaGUgYXJyYXkgdG8gcHJvY2Vzcy5cbiAgICAgKiBAcGFyYW0ge0Jvb2xlYW59IFtpc1NvcnRlZD1mYWxzZV0gQSBmbGFnIHRvIGluZGljYXRlIHRoYXQgdGhlIGBhcnJheWAgaXMgYWxyZWFkeSBzb3J0ZWQuXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbnxPYmplY3R8U3RyaW5nfSBbY2FsbGJhY2s9aWRlbnRpdHldIFRoZSBmdW5jdGlvbiBjYWxsZWQgcGVyXG4gICAgICogIGl0ZXJhdGlvbi4gSWYgYSBwcm9wZXJ0eSBuYW1lIG9yIG9iamVjdCBpcyBwYXNzZWQsIGl0IHdpbGwgYmUgdXNlZCB0byBjcmVhdGVcbiAgICAgKiAgYSBcIl8ucGx1Y2tcIiBvciBcIl8ud2hlcmVcIiBzdHlsZSBjYWxsYmFjaywgcmVzcGVjdGl2ZWx5LlxuICAgICAqIEBwYXJhbSB7TWl4ZWR9IFt0aGlzQXJnXSBUaGUgYHRoaXNgIGJpbmRpbmcgb2YgYGNhbGxiYWNrYC5cbiAgICAgKiBAcmV0dXJucyB7QXJyYXl9IFJldHVybnMgYSBkdXBsaWNhdGUtdmFsdWUtZnJlZSBhcnJheS5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy51bmlxKFsxLCAyLCAxLCAzLCAxXSk7XG4gICAgICogLy8gPT4gWzEsIDIsIDNdXG4gICAgICpcbiAgICAgKiBfLnVuaXEoWzEsIDEsIDIsIDIsIDNdLCB0cnVlKTtcbiAgICAgKiAvLyA9PiBbMSwgMiwgM11cbiAgICAgKlxuICAgICAqIF8udW5pcShbJ0EnLCAnYicsICdDJywgJ2EnLCAnQicsICdjJ10sIGZ1bmN0aW9uKGxldHRlcikgeyByZXR1cm4gbGV0dGVyLnRvTG93ZXJDYXNlKCk7IH0pO1xuICAgICAqIC8vID0+IFsnQScsICdiJywgJ0MnXVxuICAgICAqXG4gICAgICogXy51bmlxKFsxLCAyLjUsIDMsIDEuNSwgMiwgMy41XSwgZnVuY3Rpb24obnVtKSB7IHJldHVybiB0aGlzLmZsb29yKG51bSk7IH0sIE1hdGgpO1xuICAgICAqIC8vID0+IFsxLCAyLjUsIDNdXG4gICAgICpcbiAgICAgKiAvLyB1c2luZyBcIl8ucGx1Y2tcIiBjYWxsYmFjayBzaG9ydGhhbmRcbiAgICAgKiBfLnVuaXEoW3sgJ3gnOiAxIH0sIHsgJ3gnOiAyIH0sIHsgJ3gnOiAxIH1dLCAneCcpO1xuICAgICAqIC8vID0+IFt7ICd4JzogMSB9LCB7ICd4JzogMiB9XVxuICAgICAqL1xuICAgIHZhciB1bmlxID0gb3ZlcmxvYWRXcmFwcGVyKGZ1bmN0aW9uKGFycmF5LCBpc1NvcnRlZCwgY2FsbGJhY2spIHtcbiAgICAgIHZhciBpbmRleCA9IC0xLFxuICAgICAgICAgIGluZGV4T2YgPSBnZXRJbmRleE9mKCksXG4gICAgICAgICAgbGVuZ3RoID0gYXJyYXkgPyBhcnJheS5sZW5ndGggOiAwLFxuICAgICAgICAgIHJlc3VsdCA9IFtdO1xuXG4gICAgICB2YXIgaXNMYXJnZSA9ICFpc1NvcnRlZCAmJiBsZW5ndGggPj0gbGFyZ2VBcnJheVNpemUgJiYgaW5kZXhPZiA9PT0gYmFzaWNJbmRleE9mLFxuICAgICAgICAgIHNlZW4gPSAoY2FsbGJhY2sgfHwgaXNMYXJnZSkgPyBnZXRBcnJheSgpIDogcmVzdWx0O1xuXG4gICAgICBpZiAoaXNMYXJnZSkge1xuICAgICAgICB2YXIgY2FjaGUgPSBjcmVhdGVDYWNoZShzZWVuKTtcbiAgICAgICAgaWYgKGNhY2hlKSB7XG4gICAgICAgICAgaW5kZXhPZiA9IGNhY2hlSW5kZXhPZjtcbiAgICAgICAgICBzZWVuID0gY2FjaGU7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgaXNMYXJnZSA9IGZhbHNlO1xuICAgICAgICAgIHNlZW4gPSBjYWxsYmFjayA/IHNlZW4gOiAocmVsZWFzZUFycmF5KHNlZW4pLCByZXN1bHQpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICB3aGlsZSAoKytpbmRleCA8IGxlbmd0aCkge1xuICAgICAgICB2YXIgdmFsdWUgPSBhcnJheVtpbmRleF0sXG4gICAgICAgICAgICBjb21wdXRlZCA9IGNhbGxiYWNrID8gY2FsbGJhY2sodmFsdWUsIGluZGV4LCBhcnJheSkgOiB2YWx1ZTtcblxuICAgICAgICBpZiAoaXNTb3J0ZWRcbiAgICAgICAgICAgICAgPyAhaW5kZXggfHwgc2VlbltzZWVuLmxlbmd0aCAtIDFdICE9PSBjb21wdXRlZFxuICAgICAgICAgICAgICA6IGluZGV4T2Yoc2VlbiwgY29tcHV0ZWQpIDwgMFxuICAgICAgICAgICAgKSB7XG4gICAgICAgICAgaWYgKGNhbGxiYWNrIHx8IGlzTGFyZ2UpIHtcbiAgICAgICAgICAgIHNlZW4ucHVzaChjb21wdXRlZCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJlc3VsdC5wdXNoKHZhbHVlKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaWYgKGlzTGFyZ2UpIHtcbiAgICAgICAgcmVsZWFzZUFycmF5KHNlZW4uYXJyYXkpO1xuICAgICAgICByZWxlYXNlT2JqZWN0KHNlZW4pO1xuICAgICAgfSBlbHNlIGlmIChjYWxsYmFjaykge1xuICAgICAgICByZWxlYXNlQXJyYXkoc2Vlbik7XG4gICAgICB9XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH0pO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGludmVyc2Ugb2YgYF8uemlwYCwgdGhpcyBtZXRob2Qgc3BsaXRzIGdyb3VwcyBvZiBlbGVtZW50cyBpbnRvIGFycmF5c1xuICAgICAqIGNvbXBvc2VkIG9mIGVsZW1lbnRzIGZyb20gZWFjaCBncm91cCBhdCB0aGVpciBjb3JyZXNwb25kaW5nIGluZGV4ZXMuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgQXJyYXlzXG4gICAgICogQHBhcmFtIHtBcnJheX0gYXJyYXkgVGhlIGFycmF5IHRvIHByb2Nlc3MuXG4gICAgICogQHJldHVybnMge0FycmF5fSBSZXR1cm5zIGEgbmV3IGFycmF5IG9mIHRoZSBjb21wb3NlZCBhcnJheXMuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8udW56aXAoW1snbW9lJywgMzAsIHRydWVdLCBbJ2xhcnJ5JywgNDAsIGZhbHNlXV0pO1xuICAgICAqIC8vID0+IFtbJ21vZScsICdsYXJyeSddLCBbMzAsIDQwXSwgW3RydWUsIGZhbHNlXV07XG4gICAgICovXG4gICAgZnVuY3Rpb24gdW56aXAoYXJyYXkpIHtcbiAgICAgIHZhciBpbmRleCA9IC0xLFxuICAgICAgICAgIGxlbmd0aCA9IGFycmF5ID8gbWF4KHBsdWNrKGFycmF5LCAnbGVuZ3RoJykpIDogMCxcbiAgICAgICAgICByZXN1bHQgPSBBcnJheShsZW5ndGggPCAwID8gMCA6IGxlbmd0aCk7XG5cbiAgICAgIHdoaWxlICgrK2luZGV4IDwgbGVuZ3RoKSB7XG4gICAgICAgIHJlc3VsdFtpbmRleF0gPSBwbHVjayhhcnJheSwgaW5kZXgpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuIGFycmF5IHdpdGggYWxsIG9jY3VycmVuY2VzIG9mIHRoZSBwYXNzZWQgdmFsdWVzIHJlbW92ZWQgdXNpbmdcbiAgICAgKiBzdHJpY3QgZXF1YWxpdHkgZm9yIGNvbXBhcmlzb25zLCBpLmUuIGA9PT1gLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IEFycmF5c1xuICAgICAqIEBwYXJhbSB7QXJyYXl9IGFycmF5IFRoZSBhcnJheSB0byBmaWx0ZXIuXG4gICAgICogQHBhcmFtIHtNaXhlZH0gW3ZhbHVlMSwgdmFsdWUyLCAuLi5dIFZhbHVlcyB0byByZW1vdmUuXG4gICAgICogQHJldHVybnMge0FycmF5fSBSZXR1cm5zIGEgbmV3IGZpbHRlcmVkIGFycmF5LlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLndpdGhvdXQoWzEsIDIsIDEsIDAsIDMsIDEsIDRdLCAwLCAxKTtcbiAgICAgKiAvLyA9PiBbMiwgMywgNF1cbiAgICAgKi9cbiAgICBmdW5jdGlvbiB3aXRob3V0KGFycmF5KSB7XG4gICAgICByZXR1cm4gZGlmZmVyZW5jZShhcnJheSwgbmF0aXZlU2xpY2UuY2FsbChhcmd1bWVudHMsIDEpKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHcm91cHMgdGhlIGVsZW1lbnRzIG9mIGVhY2ggYXJyYXkgYXQgdGhlaXIgY29ycmVzcG9uZGluZyBpbmRleGVzLiBVc2VmdWwgZm9yXG4gICAgICogc2VwYXJhdGUgZGF0YSBzb3VyY2VzIHRoYXQgYXJlIGNvb3JkaW5hdGVkIHRocm91Z2ggbWF0Y2hpbmcgYXJyYXkgaW5kZXhlcy5cbiAgICAgKiBGb3IgYSBtYXRyaXggb2YgbmVzdGVkIGFycmF5cywgYF8uemlwLmFwcGx5KC4uLilgIGNhbiB0cmFuc3Bvc2UgdGhlIG1hdHJpeFxuICAgICAqIGluIGEgc2ltaWxhciBmYXNoaW9uLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IEFycmF5c1xuICAgICAqIEBwYXJhbSB7QXJyYXl9IFthcnJheTEsIGFycmF5MiwgLi4uXSBBcnJheXMgdG8gcHJvY2Vzcy5cbiAgICAgKiBAcmV0dXJucyB7QXJyYXl9IFJldHVybnMgYSBuZXcgYXJyYXkgb2YgZ3JvdXBlZCBlbGVtZW50cy5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy56aXAoWydtb2UnLCAnbGFycnknXSwgWzMwLCA0MF0sIFt0cnVlLCBmYWxzZV0pO1xuICAgICAqIC8vID0+IFtbJ21vZScsIDMwLCB0cnVlXSwgWydsYXJyeScsIDQwLCBmYWxzZV1dXG4gICAgICovXG4gICAgZnVuY3Rpb24gemlwKGFycmF5KSB7XG4gICAgICByZXR1cm4gYXJyYXkgPyB1bnppcChhcmd1bWVudHMpIDogW107XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhbiBvYmplY3QgY29tcG9zZWQgZnJvbSBhcnJheXMgb2YgYGtleXNgIGFuZCBgdmFsdWVzYC4gUGFzcyBlaXRoZXJcbiAgICAgKiBhIHNpbmdsZSB0d28gZGltZW5zaW9uYWwgYXJyYXksIGkuZS4gYFtba2V5MSwgdmFsdWUxXSwgW2tleTIsIHZhbHVlMl1dYCwgb3JcbiAgICAgKiB0d28gYXJyYXlzLCBvbmUgb2YgYGtleXNgIGFuZCBvbmUgb2YgY29ycmVzcG9uZGluZyBgdmFsdWVzYC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBhbGlhcyBvYmplY3RcbiAgICAgKiBAY2F0ZWdvcnkgQXJyYXlzXG4gICAgICogQHBhcmFtIHtBcnJheX0ga2V5cyBUaGUgYXJyYXkgb2Yga2V5cy5cbiAgICAgKiBAcGFyYW0ge0FycmF5fSBbdmFsdWVzPVtdXSBUaGUgYXJyYXkgb2YgdmFsdWVzLlxuICAgICAqIEByZXR1cm5zIHtPYmplY3R9IFJldHVybnMgYW4gb2JqZWN0IGNvbXBvc2VkIG9mIHRoZSBnaXZlbiBrZXlzIGFuZFxuICAgICAqICBjb3JyZXNwb25kaW5nIHZhbHVlcy5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy56aXBPYmplY3QoWydtb2UnLCAnbGFycnknXSwgWzMwLCA0MF0pO1xuICAgICAqIC8vID0+IHsgJ21vZSc6IDMwLCAnbGFycnknOiA0MCB9XG4gICAgICovXG4gICAgZnVuY3Rpb24gemlwT2JqZWN0KGtleXMsIHZhbHVlcykge1xuICAgICAgdmFyIGluZGV4ID0gLTEsXG4gICAgICAgICAgbGVuZ3RoID0ga2V5cyA/IGtleXMubGVuZ3RoIDogMCxcbiAgICAgICAgICByZXN1bHQgPSB7fTtcblxuICAgICAgd2hpbGUgKCsraW5kZXggPCBsZW5ndGgpIHtcbiAgICAgICAgdmFyIGtleSA9IGtleXNbaW5kZXhdO1xuICAgICAgICBpZiAodmFsdWVzKSB7XG4gICAgICAgICAgcmVzdWx0W2tleV0gPSB2YWx1ZXNbaW5kZXhdO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJlc3VsdFtrZXlbMF1dID0ga2V5WzFdO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIC8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuXG4gICAgLyoqXG4gICAgICogSWYgYG5gIGlzIGdyZWF0ZXIgdGhhbiBgMGAsIGEgZnVuY3Rpb24gaXMgY3JlYXRlZCB0aGF0IGlzIHJlc3RyaWN0ZWQgdG9cbiAgICAgKiBleGVjdXRpbmcgYGZ1bmNgLCB3aXRoIHRoZSBgdGhpc2AgYmluZGluZyBhbmQgYXJndW1lbnRzIG9mIHRoZSBjcmVhdGVkXG4gICAgICogZnVuY3Rpb24sIG9ubHkgYWZ0ZXIgaXQgaXMgY2FsbGVkIGBuYCB0aW1lcy4gSWYgYG5gIGlzIGxlc3MgdGhhbiBgMWAsXG4gICAgICogYGZ1bmNgIGlzIGV4ZWN1dGVkIGltbWVkaWF0ZWx5LCB3aXRob3V0IGEgYHRoaXNgIGJpbmRpbmcgb3IgYWRkaXRpb25hbFxuICAgICAqIGFyZ3VtZW50cywgYW5kIGl0cyByZXN1bHQgaXMgcmV0dXJuZWQuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgRnVuY3Rpb25zXG4gICAgICogQHBhcmFtIHtOdW1iZXJ9IG4gVGhlIG51bWJlciBvZiB0aW1lcyB0aGUgZnVuY3Rpb24gbXVzdCBiZSBjYWxsZWQgYmVmb3JlXG4gICAgICogaXQgaXMgZXhlY3V0ZWQuXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbn0gZnVuYyBUaGUgZnVuY3Rpb24gdG8gcmVzdHJpY3QuXG4gICAgICogQHJldHVybnMge0Z1bmN0aW9ufSBSZXR1cm5zIHRoZSBuZXcgcmVzdHJpY3RlZCBmdW5jdGlvbi5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogdmFyIHJlbmRlck5vdGVzID0gXy5hZnRlcihub3Rlcy5sZW5ndGgsIHJlbmRlcik7XG4gICAgICogXy5mb3JFYWNoKG5vdGVzLCBmdW5jdGlvbihub3RlKSB7XG4gICAgICogICBub3RlLmFzeW5jU2F2ZSh7ICdzdWNjZXNzJzogcmVuZGVyTm90ZXMgfSk7XG4gICAgICogfSk7XG4gICAgICogLy8gYHJlbmRlck5vdGVzYCBpcyBydW4gb25jZSwgYWZ0ZXIgYWxsIG5vdGVzIGhhdmUgc2F2ZWRcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBhZnRlcihuLCBmdW5jKSB7XG4gICAgICBpZiAobiA8IDEpIHtcbiAgICAgICAgcmV0dXJuIGZ1bmMoKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICAgICAgaWYgKC0tbiA8IDEpIHtcbiAgICAgICAgICByZXR1cm4gZnVuYy5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICB9XG4gICAgICB9O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYSBmdW5jdGlvbiB0aGF0LCB3aGVuIGNhbGxlZCwgaW52b2tlcyBgZnVuY2Agd2l0aCB0aGUgYHRoaXNgXG4gICAgICogYmluZGluZyBvZiBgdGhpc0FyZ2AgYW5kIHByZXBlbmRzIGFueSBhZGRpdGlvbmFsIGBiaW5kYCBhcmd1bWVudHMgdG8gdGhvc2VcbiAgICAgKiBwYXNzZWQgdG8gdGhlIGJvdW5kIGZ1bmN0aW9uLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IEZ1bmN0aW9uc1xuICAgICAqIEBwYXJhbSB7RnVuY3Rpb259IGZ1bmMgVGhlIGZ1bmN0aW9uIHRvIGJpbmQuXG4gICAgICogQHBhcmFtIHtNaXhlZH0gW3RoaXNBcmddIFRoZSBgdGhpc2AgYmluZGluZyBvZiBgZnVuY2AuXG4gICAgICogQHBhcmFtIHtNaXhlZH0gW2FyZzEsIGFyZzIsIC4uLl0gQXJndW1lbnRzIHRvIGJlIHBhcnRpYWxseSBhcHBsaWVkLlxuICAgICAqIEByZXR1cm5zIHtGdW5jdGlvbn0gUmV0dXJucyB0aGUgbmV3IGJvdW5kIGZ1bmN0aW9uLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiB2YXIgZnVuYyA9IGZ1bmN0aW9uKGdyZWV0aW5nKSB7XG4gICAgICogICByZXR1cm4gZ3JlZXRpbmcgKyAnICcgKyB0aGlzLm5hbWU7XG4gICAgICogfTtcbiAgICAgKlxuICAgICAqIGZ1bmMgPSBfLmJpbmQoZnVuYywgeyAnbmFtZSc6ICdtb2UnIH0sICdoaScpO1xuICAgICAqIGZ1bmMoKTtcbiAgICAgKiAvLyA9PiAnaGkgbW9lJ1xuICAgICAqL1xuICAgIGZ1bmN0aW9uIGJpbmQoZnVuYywgdGhpc0FyZykge1xuICAgICAgLy8gdXNlIGBGdW5jdGlvbiNiaW5kYCBpZiBpdCBleGlzdHMgYW5kIGlzIGZhc3RcbiAgICAgIC8vIChpbiBWOCBgRnVuY3Rpb24jYmluZGAgaXMgc2xvd2VyIGV4Y2VwdCB3aGVuIHBhcnRpYWxseSBhcHBsaWVkKVxuICAgICAgcmV0dXJuIHN1cHBvcnQuZmFzdEJpbmQgfHwgKG5hdGl2ZUJpbmQgJiYgYXJndW1lbnRzLmxlbmd0aCA+IDIpXG4gICAgICAgID8gbmF0aXZlQmluZC5jYWxsLmFwcGx5KG5hdGl2ZUJpbmQsIGFyZ3VtZW50cylcbiAgICAgICAgOiBjcmVhdGVCb3VuZChmdW5jLCB0aGlzQXJnLCBuYXRpdmVTbGljZS5jYWxsKGFyZ3VtZW50cywgMikpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEJpbmRzIG1ldGhvZHMgb24gYG9iamVjdGAgdG8gYG9iamVjdGAsIG92ZXJ3cml0aW5nIHRoZSBleGlzdGluZyBtZXRob2QuXG4gICAgICogTWV0aG9kIG5hbWVzIG1heSBiZSBzcGVjaWZpZWQgYXMgaW5kaXZpZHVhbCBhcmd1bWVudHMgb3IgYXMgYXJyYXlzIG9mIG1ldGhvZFxuICAgICAqIG5hbWVzLiBJZiBubyBtZXRob2QgbmFtZXMgYXJlIHByb3ZpZGVkLCBhbGwgdGhlIGZ1bmN0aW9uIHByb3BlcnRpZXMgb2YgYG9iamVjdGBcbiAgICAgKiB3aWxsIGJlIGJvdW5kLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IEZ1bmN0aW9uc1xuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3QgVGhlIG9iamVjdCB0byBiaW5kIGFuZCBhc3NpZ24gdGhlIGJvdW5kIG1ldGhvZHMgdG8uXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IFttZXRob2ROYW1lMSwgbWV0aG9kTmFtZTIsIC4uLl0gTWV0aG9kIG5hbWVzIG9uIHRoZSBvYmplY3QgdG8gYmluZC5cbiAgICAgKiBAcmV0dXJucyB7T2JqZWN0fSBSZXR1cm5zIGBvYmplY3RgLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiB2YXIgdmlldyA9IHtcbiAgICAgKiAgJ2xhYmVsJzogJ2RvY3MnLFxuICAgICAqICAnb25DbGljayc6IGZ1bmN0aW9uKCkgeyBhbGVydCgnY2xpY2tlZCAnICsgdGhpcy5sYWJlbCk7IH1cbiAgICAgKiB9O1xuICAgICAqXG4gICAgICogXy5iaW5kQWxsKHZpZXcpO1xuICAgICAqIGpRdWVyeSgnI2RvY3MnKS5vbignY2xpY2snLCB2aWV3Lm9uQ2xpY2spO1xuICAgICAqIC8vID0+IGFsZXJ0cyAnY2xpY2tlZCBkb2NzJywgd2hlbiB0aGUgYnV0dG9uIGlzIGNsaWNrZWRcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBiaW5kQWxsKG9iamVjdCkge1xuICAgICAgdmFyIGZ1bmNzID0gYXJndW1lbnRzLmxlbmd0aCA+IDEgPyBjb25jYXQuYXBwbHkoYXJyYXlSZWYsIG5hdGl2ZVNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKSkgOiBmdW5jdGlvbnMob2JqZWN0KSxcbiAgICAgICAgICBpbmRleCA9IC0xLFxuICAgICAgICAgIGxlbmd0aCA9IGZ1bmNzLmxlbmd0aDtcblxuICAgICAgd2hpbGUgKCsraW5kZXggPCBsZW5ndGgpIHtcbiAgICAgICAgdmFyIGtleSA9IGZ1bmNzW2luZGV4XTtcbiAgICAgICAgb2JqZWN0W2tleV0gPSBiaW5kKG9iamVjdFtrZXldLCBvYmplY3QpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIG9iamVjdDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGEgZnVuY3Rpb24gdGhhdCwgd2hlbiBjYWxsZWQsIGludm9rZXMgdGhlIG1ldGhvZCBhdCBgb2JqZWN0W2tleV1gXG4gICAgICogYW5kIHByZXBlbmRzIGFueSBhZGRpdGlvbmFsIGBiaW5kS2V5YCBhcmd1bWVudHMgdG8gdGhvc2UgcGFzc2VkIHRvIHRoZSBib3VuZFxuICAgICAqIGZ1bmN0aW9uLiBUaGlzIG1ldGhvZCBkaWZmZXJzIGZyb20gYF8uYmluZGAgYnkgYWxsb3dpbmcgYm91bmQgZnVuY3Rpb25zIHRvXG4gICAgICogcmVmZXJlbmNlIG1ldGhvZHMgdGhhdCB3aWxsIGJlIHJlZGVmaW5lZCBvciBkb24ndCB5ZXQgZXhpc3QuXG4gICAgICogU2VlIGh0dHA6Ly9taWNoYXV4LmNhL2FydGljbGVzL2xhenktZnVuY3Rpb24tZGVmaW5pdGlvbi1wYXR0ZXJuLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IEZ1bmN0aW9uc1xuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3QgVGhlIG9iamVjdCB0aGUgbWV0aG9kIGJlbG9uZ3MgdG8uXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IGtleSBUaGUga2V5IG9mIHRoZSBtZXRob2QuXG4gICAgICogQHBhcmFtIHtNaXhlZH0gW2FyZzEsIGFyZzIsIC4uLl0gQXJndW1lbnRzIHRvIGJlIHBhcnRpYWxseSBhcHBsaWVkLlxuICAgICAqIEByZXR1cm5zIHtGdW5jdGlvbn0gUmV0dXJucyB0aGUgbmV3IGJvdW5kIGZ1bmN0aW9uLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiB2YXIgb2JqZWN0ID0ge1xuICAgICAqICAgJ25hbWUnOiAnbW9lJyxcbiAgICAgKiAgICdncmVldCc6IGZ1bmN0aW9uKGdyZWV0aW5nKSB7XG4gICAgICogICAgIHJldHVybiBncmVldGluZyArICcgJyArIHRoaXMubmFtZTtcbiAgICAgKiAgIH1cbiAgICAgKiB9O1xuICAgICAqXG4gICAgICogdmFyIGZ1bmMgPSBfLmJpbmRLZXkob2JqZWN0LCAnZ3JlZXQnLCAnaGknKTtcbiAgICAgKiBmdW5jKCk7XG4gICAgICogLy8gPT4gJ2hpIG1vZSdcbiAgICAgKlxuICAgICAqIG9iamVjdC5ncmVldCA9IGZ1bmN0aW9uKGdyZWV0aW5nKSB7XG4gICAgICogICByZXR1cm4gZ3JlZXRpbmcgKyAnLCAnICsgdGhpcy5uYW1lICsgJyEnO1xuICAgICAqIH07XG4gICAgICpcbiAgICAgKiBmdW5jKCk7XG4gICAgICogLy8gPT4gJ2hpLCBtb2UhJ1xuICAgICAqL1xuICAgIGZ1bmN0aW9uIGJpbmRLZXkob2JqZWN0LCBrZXkpIHtcbiAgICAgIHJldHVybiBjcmVhdGVCb3VuZChvYmplY3QsIGtleSwgbmF0aXZlU2xpY2UuY2FsbChhcmd1bWVudHMsIDIpLCBpbmRpY2F0b3JPYmplY3QpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYSBmdW5jdGlvbiB0aGF0IGlzIHRoZSBjb21wb3NpdGlvbiBvZiB0aGUgcGFzc2VkIGZ1bmN0aW9ucyxcbiAgICAgKiB3aGVyZSBlYWNoIGZ1bmN0aW9uIGNvbnN1bWVzIHRoZSByZXR1cm4gdmFsdWUgb2YgdGhlIGZ1bmN0aW9uIHRoYXQgZm9sbG93cy5cbiAgICAgKiBGb3IgZXhhbXBsZSwgY29tcG9zaW5nIHRoZSBmdW5jdGlvbnMgYGYoKWAsIGBnKClgLCBhbmQgYGgoKWAgcHJvZHVjZXMgYGYoZyhoKCkpKWAuXG4gICAgICogRWFjaCBmdW5jdGlvbiBpcyBleGVjdXRlZCB3aXRoIHRoZSBgdGhpc2AgYmluZGluZyBvZiB0aGUgY29tcG9zZWQgZnVuY3Rpb24uXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgRnVuY3Rpb25zXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbn0gW2Z1bmMxLCBmdW5jMiwgLi4uXSBGdW5jdGlvbnMgdG8gY29tcG9zZS5cbiAgICAgKiBAcmV0dXJucyB7RnVuY3Rpb259IFJldHVybnMgdGhlIG5ldyBjb21wb3NlZCBmdW5jdGlvbi5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogdmFyIGdyZWV0ID0gZnVuY3Rpb24obmFtZSkgeyByZXR1cm4gJ2hpICcgKyBuYW1lOyB9O1xuICAgICAqIHZhciBleGNsYWltID0gZnVuY3Rpb24oc3RhdGVtZW50KSB7IHJldHVybiBzdGF0ZW1lbnQgKyAnISc7IH07XG4gICAgICogdmFyIHdlbGNvbWUgPSBfLmNvbXBvc2UoZXhjbGFpbSwgZ3JlZXQpO1xuICAgICAqIHdlbGNvbWUoJ21vZScpO1xuICAgICAqIC8vID0+ICdoaSBtb2UhJ1xuICAgICAqL1xuICAgIGZ1bmN0aW9uIGNvbXBvc2UoKSB7XG4gICAgICB2YXIgZnVuY3MgPSBhcmd1bWVudHM7XG4gICAgICByZXR1cm4gZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBhcmdzID0gYXJndW1lbnRzLFxuICAgICAgICAgICAgbGVuZ3RoID0gZnVuY3MubGVuZ3RoO1xuXG4gICAgICAgIHdoaWxlIChsZW5ndGgtLSkge1xuICAgICAgICAgIGFyZ3MgPSBbZnVuY3NbbGVuZ3RoXS5hcHBseSh0aGlzLCBhcmdzKV07XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGFyZ3NbMF07XG4gICAgICB9O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFByb2R1Y2VzIGEgY2FsbGJhY2sgYm91bmQgdG8gYW4gb3B0aW9uYWwgYHRoaXNBcmdgLiBJZiBgZnVuY2AgaXMgYSBwcm9wZXJ0eVxuICAgICAqIG5hbWUsIHRoZSBjcmVhdGVkIGNhbGxiYWNrIHdpbGwgcmV0dXJuIHRoZSBwcm9wZXJ0eSB2YWx1ZSBmb3IgYSBnaXZlbiBlbGVtZW50LlxuICAgICAqIElmIGBmdW5jYCBpcyBhbiBvYmplY3QsIHRoZSBjcmVhdGVkIGNhbGxiYWNrIHdpbGwgcmV0dXJuIGB0cnVlYCBmb3IgZWxlbWVudHNcbiAgICAgKiB0aGF0IGNvbnRhaW4gdGhlIGVxdWl2YWxlbnQgb2JqZWN0IHByb3BlcnRpZXMsIG90aGVyd2lzZSBpdCB3aWxsIHJldHVybiBgZmFsc2VgLlxuICAgICAqXG4gICAgICogTm90ZTogQWxsIExvLURhc2ggbWV0aG9kcywgdGhhdCBhY2NlcHQgYSBgY2FsbGJhY2tgIGFyZ3VtZW50LCB1c2UgYF8uY3JlYXRlQ2FsbGJhY2tgLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IEZ1bmN0aW9uc1xuICAgICAqIEBwYXJhbSB7TWl4ZWR9IFtmdW5jPWlkZW50aXR5XSBUaGUgdmFsdWUgdG8gY29udmVydCB0byBhIGNhbGxiYWNrLlxuICAgICAqIEBwYXJhbSB7TWl4ZWR9IFt0aGlzQXJnXSBUaGUgYHRoaXNgIGJpbmRpbmcgb2YgdGhlIGNyZWF0ZWQgY2FsbGJhY2suXG4gICAgICogQHBhcmFtIHtOdW1iZXJ9IFthcmdDb3VudD0zXSBUaGUgbnVtYmVyIG9mIGFyZ3VtZW50cyB0aGUgY2FsbGJhY2sgYWNjZXB0cy5cbiAgICAgKiBAcmV0dXJucyB7RnVuY3Rpb259IFJldHVybnMgYSBjYWxsYmFjayBmdW5jdGlvbi5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogdmFyIHN0b29nZXMgPSBbXG4gICAgICogICB7ICduYW1lJzogJ21vZScsICdhZ2UnOiA0MCB9LFxuICAgICAqICAgeyAnbmFtZSc6ICdsYXJyeScsICdhZ2UnOiA1MCB9XG4gICAgICogXTtcbiAgICAgKlxuICAgICAqIC8vIHdyYXAgdG8gY3JlYXRlIGN1c3RvbSBjYWxsYmFjayBzaG9ydGhhbmRzXG4gICAgICogXy5jcmVhdGVDYWxsYmFjayA9IF8ud3JhcChfLmNyZWF0ZUNhbGxiYWNrLCBmdW5jdGlvbihmdW5jLCBjYWxsYmFjaywgdGhpc0FyZykge1xuICAgICAqICAgdmFyIG1hdGNoID0gL14oLis/KV9fKFtnbF10KSguKykkLy5leGVjKGNhbGxiYWNrKTtcbiAgICAgKiAgIHJldHVybiAhbWF0Y2ggPyBmdW5jKGNhbGxiYWNrLCB0aGlzQXJnKSA6IGZ1bmN0aW9uKG9iamVjdCkge1xuICAgICAqICAgICByZXR1cm4gbWF0Y2hbMl0gPT0gJ2d0JyA/IG9iamVjdFttYXRjaFsxXV0gPiBtYXRjaFszXSA6IG9iamVjdFttYXRjaFsxXV0gPCBtYXRjaFszXTtcbiAgICAgKiAgIH07XG4gICAgICogfSk7XG4gICAgICpcbiAgICAgKiBfLmZpbHRlcihzdG9vZ2VzLCAnYWdlX19ndDQ1Jyk7XG4gICAgICogLy8gPT4gW3sgJ25hbWUnOiAnbGFycnknLCAnYWdlJzogNTAgfV1cbiAgICAgKlxuICAgICAqIC8vIGNyZWF0ZSBtaXhpbnMgd2l0aCBzdXBwb3J0IGZvciBcIl8ucGx1Y2tcIiBhbmQgXCJfLndoZXJlXCIgY2FsbGJhY2sgc2hvcnRoYW5kc1xuICAgICAqIF8ubWl4aW4oe1xuICAgICAqICAgJ3RvTG9va3VwJzogZnVuY3Rpb24oY29sbGVjdGlvbiwgY2FsbGJhY2ssIHRoaXNBcmcpIHtcbiAgICAgKiAgICAgY2FsbGJhY2sgPSBfLmNyZWF0ZUNhbGxiYWNrKGNhbGxiYWNrLCB0aGlzQXJnKTtcbiAgICAgKiAgICAgcmV0dXJuIF8ucmVkdWNlKGNvbGxlY3Rpb24sIGZ1bmN0aW9uKHJlc3VsdCwgdmFsdWUsIGluZGV4LCBjb2xsZWN0aW9uKSB7XG4gICAgICogICAgICAgcmV0dXJuIChyZXN1bHRbY2FsbGJhY2sodmFsdWUsIGluZGV4LCBjb2xsZWN0aW9uKV0gPSB2YWx1ZSwgcmVzdWx0KTtcbiAgICAgKiAgICAgfSwge30pO1xuICAgICAqICAgfVxuICAgICAqIH0pO1xuICAgICAqXG4gICAgICogXy50b0xvb2t1cChzdG9vZ2VzLCAnbmFtZScpO1xuICAgICAqIC8vID0+IHsgJ21vZSc6IHsgJ25hbWUnOiAnbW9lJywgJ2FnZSc6IDQwIH0sICdsYXJyeSc6IHsgJ25hbWUnOiAnbGFycnknLCAnYWdlJzogNTAgfSB9XG4gICAgICovXG4gICAgZnVuY3Rpb24gY3JlYXRlQ2FsbGJhY2soZnVuYywgdGhpc0FyZywgYXJnQ291bnQpIHtcbiAgICAgIGlmIChmdW5jID09IG51bGwpIHtcbiAgICAgICAgcmV0dXJuIGlkZW50aXR5O1xuICAgICAgfVxuICAgICAgdmFyIHR5cGUgPSB0eXBlb2YgZnVuYztcbiAgICAgIGlmICh0eXBlICE9ICdmdW5jdGlvbicpIHtcbiAgICAgICAgaWYgKHR5cGUgIT0gJ29iamVjdCcpIHtcbiAgICAgICAgICByZXR1cm4gZnVuY3Rpb24ob2JqZWN0KSB7XG4gICAgICAgICAgICByZXR1cm4gb2JqZWN0W2Z1bmNdO1xuICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHByb3BzID0ga2V5cyhmdW5jKTtcbiAgICAgICAgcmV0dXJuIGZ1bmN0aW9uKG9iamVjdCkge1xuICAgICAgICAgIHZhciBsZW5ndGggPSBwcm9wcy5sZW5ndGgsXG4gICAgICAgICAgICAgIHJlc3VsdCA9IGZhbHNlO1xuICAgICAgICAgIHdoaWxlIChsZW5ndGgtLSkge1xuICAgICAgICAgICAgaWYgKCEocmVzdWx0ID0gaXNFcXVhbChvYmplY3RbcHJvcHNbbGVuZ3RoXV0sIGZ1bmNbcHJvcHNbbGVuZ3RoXV0sIGluZGljYXRvck9iamVjdCkpKSB7XG4gICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICB9O1xuICAgICAgfVxuICAgICAgaWYgKHR5cGVvZiB0aGlzQXJnID09ICd1bmRlZmluZWQnIHx8IChyZVRoaXMgJiYgIXJlVGhpcy50ZXN0KGZuVG9TdHJpbmcuY2FsbChmdW5jKSkpKSB7XG4gICAgICAgIHJldHVybiBmdW5jO1xuICAgICAgfVxuICAgICAgaWYgKGFyZ0NvdW50ID09PSAxKSB7XG4gICAgICAgIHJldHVybiBmdW5jdGlvbih2YWx1ZSkge1xuICAgICAgICAgIHJldHVybiBmdW5jLmNhbGwodGhpc0FyZywgdmFsdWUpO1xuICAgICAgICB9O1xuICAgICAgfVxuICAgICAgaWYgKGFyZ0NvdW50ID09PSAyKSB7XG4gICAgICAgIHJldHVybiBmdW5jdGlvbihhLCBiKSB7XG4gICAgICAgICAgcmV0dXJuIGZ1bmMuY2FsbCh0aGlzQXJnLCBhLCBiKTtcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICAgIGlmIChhcmdDb3VudCA9PT0gNCkge1xuICAgICAgICByZXR1cm4gZnVuY3Rpb24oYWNjdW11bGF0b3IsIHZhbHVlLCBpbmRleCwgY29sbGVjdGlvbikge1xuICAgICAgICAgIHJldHVybiBmdW5jLmNhbGwodGhpc0FyZywgYWNjdW11bGF0b3IsIHZhbHVlLCBpbmRleCwgY29sbGVjdGlvbik7XG4gICAgICAgIH07XG4gICAgICB9XG4gICAgICByZXR1cm4gZnVuY3Rpb24odmFsdWUsIGluZGV4LCBjb2xsZWN0aW9uKSB7XG4gICAgICAgIHJldHVybiBmdW5jLmNhbGwodGhpc0FyZywgdmFsdWUsIGluZGV4LCBjb2xsZWN0aW9uKTtcbiAgICAgIH07XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhIGZ1bmN0aW9uIHRoYXQgd2lsbCBkZWxheSB0aGUgZXhlY3V0aW9uIG9mIGBmdW5jYCB1bnRpbCBhZnRlclxuICAgICAqIGB3YWl0YCBtaWxsaXNlY29uZHMgaGF2ZSBlbGFwc2VkIHNpbmNlIHRoZSBsYXN0IHRpbWUgaXQgd2FzIGludm9rZWQuIFBhc3NcbiAgICAgKiBhbiBgb3B0aW9uc2Agb2JqZWN0IHRvIGluZGljYXRlIHRoYXQgYGZ1bmNgIHNob3VsZCBiZSBpbnZva2VkIG9uIHRoZSBsZWFkaW5nXG4gICAgICogYW5kL29yIHRyYWlsaW5nIGVkZ2Ugb2YgdGhlIGB3YWl0YCB0aW1lb3V0LiBTdWJzZXF1ZW50IGNhbGxzIHRvIHRoZSBkZWJvdW5jZWRcbiAgICAgKiBmdW5jdGlvbiB3aWxsIHJldHVybiB0aGUgcmVzdWx0IG9mIHRoZSBsYXN0IGBmdW5jYCBjYWxsLlxuICAgICAqXG4gICAgICogTm90ZTogSWYgYGxlYWRpbmdgIGFuZCBgdHJhaWxpbmdgIG9wdGlvbnMgYXJlIGB0cnVlYCwgYGZ1bmNgIHdpbGwgYmUgY2FsbGVkXG4gICAgICogb24gdGhlIHRyYWlsaW5nIGVkZ2Ugb2YgdGhlIHRpbWVvdXQgb25seSBpZiB0aGUgdGhlIGRlYm91bmNlZCBmdW5jdGlvbiBpc1xuICAgICAqIGludm9rZWQgbW9yZSB0aGFuIG9uY2UgZHVyaW5nIHRoZSBgd2FpdGAgdGltZW91dC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBGdW5jdGlvbnNcbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBmdW5jIFRoZSBmdW5jdGlvbiB0byBkZWJvdW5jZS5cbiAgICAgKiBAcGFyYW0ge051bWJlcn0gd2FpdCBUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyB0byBkZWxheS5cbiAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBUaGUgb3B0aW9ucyBvYmplY3QuXG4gICAgICogIFtsZWFkaW5nPWZhbHNlXSBBIGJvb2xlYW4gdG8gc3BlY2lmeSBleGVjdXRpb24gb24gdGhlIGxlYWRpbmcgZWRnZSBvZiB0aGUgdGltZW91dC5cbiAgICAgKiAgW21heFdhaXRdIFRoZSBtYXhpbXVtIHRpbWUgYGZ1bmNgIGlzIGFsbG93ZWQgdG8gYmUgZGVsYXllZCBiZWZvcmUgaXQncyBjYWxsZWQuXG4gICAgICogIFt0cmFpbGluZz10cnVlXSBBIGJvb2xlYW4gdG8gc3BlY2lmeSBleGVjdXRpb24gb24gdGhlIHRyYWlsaW5nIGVkZ2Ugb2YgdGhlIHRpbWVvdXQuXG4gICAgICogQHJldHVybnMge0Z1bmN0aW9ufSBSZXR1cm5zIHRoZSBuZXcgZGVib3VuY2VkIGZ1bmN0aW9uLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiB2YXIgbGF6eUxheW91dCA9IF8uZGVib3VuY2UoY2FsY3VsYXRlTGF5b3V0LCAzMDApO1xuICAgICAqIGpRdWVyeSh3aW5kb3cpLm9uKCdyZXNpemUnLCBsYXp5TGF5b3V0KTtcbiAgICAgKlxuICAgICAqIGpRdWVyeSgnI3Bvc3Rib3gnKS5vbignY2xpY2snLCBfLmRlYm91bmNlKHNlbmRNYWlsLCAyMDAsIHtcbiAgICAgKiAgICdsZWFkaW5nJzogdHJ1ZSxcbiAgICAgKiAgICd0cmFpbGluZyc6IGZhbHNlXG4gICAgICogfSk7XG4gICAgICovXG4gICAgZnVuY3Rpb24gZGVib3VuY2UoZnVuYywgd2FpdCwgb3B0aW9ucykge1xuICAgICAgdmFyIGFyZ3MsXG4gICAgICAgICAgcmVzdWx0LFxuICAgICAgICAgIHRoaXNBcmcsXG4gICAgICAgICAgY2FsbENvdW50ID0gMCxcbiAgICAgICAgICBsYXN0Q2FsbGVkID0gMCxcbiAgICAgICAgICBtYXhXYWl0ID0gZmFsc2UsXG4gICAgICAgICAgbWF4VGltZW91dElkID0gbnVsbCxcbiAgICAgICAgICB0aW1lb3V0SWQgPSBudWxsLFxuICAgICAgICAgIHRyYWlsaW5nID0gdHJ1ZTtcblxuICAgICAgZnVuY3Rpb24gY2xlYXIoKSB7XG4gICAgICAgIGNsZWFyVGltZW91dChtYXhUaW1lb3V0SWQpO1xuICAgICAgICBjbGVhclRpbWVvdXQodGltZW91dElkKTtcbiAgICAgICAgY2FsbENvdW50ID0gMDtcbiAgICAgICAgbWF4VGltZW91dElkID0gdGltZW91dElkID0gbnVsbDtcbiAgICAgIH1cblxuICAgICAgZnVuY3Rpb24gZGVsYXllZCgpIHtcbiAgICAgICAgdmFyIGlzQ2FsbGVkID0gdHJhaWxpbmcgJiYgKCFsZWFkaW5nIHx8IGNhbGxDb3VudCA+IDEpO1xuICAgICAgICBjbGVhcigpO1xuICAgICAgICBpZiAoaXNDYWxsZWQpIHtcbiAgICAgICAgICBpZiAobWF4V2FpdCAhPT0gZmFsc2UpIHtcbiAgICAgICAgICAgIGxhc3RDYWxsZWQgPSBuZXcgRGF0ZTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmVzdWx0ID0gZnVuYy5hcHBseSh0aGlzQXJnLCBhcmdzKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBmdW5jdGlvbiBtYXhEZWxheWVkKCkge1xuICAgICAgICBjbGVhcigpO1xuICAgICAgICBpZiAodHJhaWxpbmcgfHwgKG1heFdhaXQgIT09IHdhaXQpKSB7XG4gICAgICAgICAgbGFzdENhbGxlZCA9IG5ldyBEYXRlO1xuICAgICAgICAgIHJlc3VsdCA9IGZ1bmMuYXBwbHkodGhpc0FyZywgYXJncyk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgd2FpdCA9IG5hdGl2ZU1heCgwLCB3YWl0IHx8IDApO1xuICAgICAgaWYgKG9wdGlvbnMgPT09IHRydWUpIHtcbiAgICAgICAgdmFyIGxlYWRpbmcgPSB0cnVlO1xuICAgICAgICB0cmFpbGluZyA9IGZhbHNlO1xuICAgICAgfSBlbHNlIGlmIChpc09iamVjdChvcHRpb25zKSkge1xuICAgICAgICBsZWFkaW5nID0gb3B0aW9ucy5sZWFkaW5nO1xuICAgICAgICBtYXhXYWl0ID0gJ21heFdhaXQnIGluIG9wdGlvbnMgJiYgbmF0aXZlTWF4KHdhaXQsIG9wdGlvbnMubWF4V2FpdCB8fCAwKTtcbiAgICAgICAgdHJhaWxpbmcgPSAndHJhaWxpbmcnIGluIG9wdGlvbnMgPyBvcHRpb25zLnRyYWlsaW5nIDogdHJhaWxpbmc7XG4gICAgICB9XG4gICAgICByZXR1cm4gZnVuY3Rpb24oKSB7XG4gICAgICAgIGFyZ3MgPSBhcmd1bWVudHM7XG4gICAgICAgIHRoaXNBcmcgPSB0aGlzO1xuICAgICAgICBjYWxsQ291bnQrKztcblxuICAgICAgICAvLyBhdm9pZCBpc3N1ZXMgd2l0aCBUaXRhbml1bSBhbmQgYHVuZGVmaW5lZGAgdGltZW91dCBpZHNcbiAgICAgICAgLy8gaHR0cHM6Ly9naXRodWIuY29tL2FwcGNlbGVyYXRvci90aXRhbml1bV9tb2JpbGUvYmxvYi8zXzFfMF9HQS9hbmRyb2lkL3RpdGFuaXVtL3NyYy9qYXZhL3RpL21vZHVsZXMvdGl0YW5pdW0vVGl0YW5pdW1Nb2R1bGUuamF2YSNMMTg1LUwxOTJcbiAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVvdXRJZCk7XG5cbiAgICAgICAgaWYgKG1heFdhaXQgPT09IGZhbHNlKSB7XG4gICAgICAgICAgaWYgKGxlYWRpbmcgJiYgY2FsbENvdW50IDwgMikge1xuICAgICAgICAgICAgcmVzdWx0ID0gZnVuYy5hcHBseSh0aGlzQXJnLCBhcmdzKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdmFyIG5vdyA9IG5ldyBEYXRlO1xuICAgICAgICAgIGlmICghbWF4VGltZW91dElkICYmICFsZWFkaW5nKSB7XG4gICAgICAgICAgICBsYXN0Q2FsbGVkID0gbm93O1xuICAgICAgICAgIH1cbiAgICAgICAgICB2YXIgcmVtYWluaW5nID0gbWF4V2FpdCAtIChub3cgLSBsYXN0Q2FsbGVkKTtcbiAgICAgICAgICBpZiAocmVtYWluaW5nIDw9IDApIHtcbiAgICAgICAgICAgIGNsZWFyVGltZW91dChtYXhUaW1lb3V0SWQpO1xuICAgICAgICAgICAgbWF4VGltZW91dElkID0gbnVsbDtcbiAgICAgICAgICAgIGxhc3RDYWxsZWQgPSBub3c7XG4gICAgICAgICAgICByZXN1bHQgPSBmdW5jLmFwcGx5KHRoaXNBcmcsIGFyZ3MpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBlbHNlIGlmICghbWF4VGltZW91dElkKSB7XG4gICAgICAgICAgICBtYXhUaW1lb3V0SWQgPSBzZXRUaW1lb3V0KG1heERlbGF5ZWQsIHJlbWFpbmluZyk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmICh3YWl0ICE9PSBtYXhXYWl0KSB7XG4gICAgICAgICAgdGltZW91dElkID0gc2V0VGltZW91dChkZWxheWVkLCB3YWl0KTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgfTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBEZWZlcnMgZXhlY3V0aW5nIHRoZSBgZnVuY2AgZnVuY3Rpb24gdW50aWwgdGhlIGN1cnJlbnQgY2FsbCBzdGFjayBoYXMgY2xlYXJlZC5cbiAgICAgKiBBZGRpdGlvbmFsIGFyZ3VtZW50cyB3aWxsIGJlIHBhc3NlZCB0byBgZnVuY2Agd2hlbiBpdCBpcyBpbnZva2VkLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IEZ1bmN0aW9uc1xuICAgICAqIEBwYXJhbSB7RnVuY3Rpb259IGZ1bmMgVGhlIGZ1bmN0aW9uIHRvIGRlZmVyLlxuICAgICAqIEBwYXJhbSB7TWl4ZWR9IFthcmcxLCBhcmcyLCAuLi5dIEFyZ3VtZW50cyB0byBpbnZva2UgdGhlIGZ1bmN0aW9uIHdpdGguXG4gICAgICogQHJldHVybnMge051bWJlcn0gUmV0dXJucyB0aGUgdGltZXIgaWQuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8uZGVmZXIoZnVuY3Rpb24oKSB7IGFsZXJ0KCdkZWZlcnJlZCcpOyB9KTtcbiAgICAgKiAvLyByZXR1cm5zIGZyb20gdGhlIGZ1bmN0aW9uIGJlZm9yZSBgYWxlcnRgIGlzIGNhbGxlZFxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGRlZmVyKGZ1bmMpIHtcbiAgICAgIHZhciBhcmdzID0gbmF0aXZlU2xpY2UuY2FsbChhcmd1bWVudHMsIDEpO1xuICAgICAgcmV0dXJuIHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7IGZ1bmMuYXBwbHkodW5kZWZpbmVkLCBhcmdzKTsgfSwgMSk7XG4gICAgfVxuICAgIC8vIHVzZSBgc2V0SW1tZWRpYXRlYCBpZiBpdCdzIGF2YWlsYWJsZSBpbiBOb2RlLmpzXG4gICAgaWYgKGlzVjggJiYgZnJlZU1vZHVsZSAmJiB0eXBlb2Ygc2V0SW1tZWRpYXRlID09ICdmdW5jdGlvbicpIHtcbiAgICAgIGRlZmVyID0gYmluZChzZXRJbW1lZGlhdGUsIGNvbnRleHQpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEV4ZWN1dGVzIHRoZSBgZnVuY2AgZnVuY3Rpb24gYWZ0ZXIgYHdhaXRgIG1pbGxpc2Vjb25kcy4gQWRkaXRpb25hbCBhcmd1bWVudHNcbiAgICAgKiB3aWxsIGJlIHBhc3NlZCB0byBgZnVuY2Agd2hlbiBpdCBpcyBpbnZva2VkLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IEZ1bmN0aW9uc1xuICAgICAqIEBwYXJhbSB7RnVuY3Rpb259IGZ1bmMgVGhlIGZ1bmN0aW9uIHRvIGRlbGF5LlxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSB3YWl0IFRoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIGRlbGF5IGV4ZWN1dGlvbi5cbiAgICAgKiBAcGFyYW0ge01peGVkfSBbYXJnMSwgYXJnMiwgLi4uXSBBcmd1bWVudHMgdG8gaW52b2tlIHRoZSBmdW5jdGlvbiB3aXRoLlxuICAgICAqIEByZXR1cm5zIHtOdW1iZXJ9IFJldHVybnMgdGhlIHRpbWVyIGlkLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiB2YXIgbG9nID0gXy5iaW5kKGNvbnNvbGUubG9nLCBjb25zb2xlKTtcbiAgICAgKiBfLmRlbGF5KGxvZywgMTAwMCwgJ2xvZ2dlZCBsYXRlcicpO1xuICAgICAqIC8vID0+ICdsb2dnZWQgbGF0ZXInIChBcHBlYXJzIGFmdGVyIG9uZSBzZWNvbmQuKVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGRlbGF5KGZ1bmMsIHdhaXQpIHtcbiAgICAgIHZhciBhcmdzID0gbmF0aXZlU2xpY2UuY2FsbChhcmd1bWVudHMsIDIpO1xuICAgICAgcmV0dXJuIHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7IGZ1bmMuYXBwbHkodW5kZWZpbmVkLCBhcmdzKTsgfSwgd2FpdCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhIGZ1bmN0aW9uIHRoYXQgbWVtb2l6ZXMgdGhlIHJlc3VsdCBvZiBgZnVuY2AuIElmIGByZXNvbHZlcmAgaXNcbiAgICAgKiBwYXNzZWQsIGl0IHdpbGwgYmUgdXNlZCB0byBkZXRlcm1pbmUgdGhlIGNhY2hlIGtleSBmb3Igc3RvcmluZyB0aGUgcmVzdWx0XG4gICAgICogYmFzZWQgb24gdGhlIGFyZ3VtZW50cyBwYXNzZWQgdG8gdGhlIG1lbW9pemVkIGZ1bmN0aW9uLiBCeSBkZWZhdWx0LCB0aGUgZmlyc3RcbiAgICAgKiBhcmd1bWVudCBwYXNzZWQgdG8gdGhlIG1lbW9pemVkIGZ1bmN0aW9uIGlzIHVzZWQgYXMgdGhlIGNhY2hlIGtleS4gVGhlIGBmdW5jYFxuICAgICAqIGlzIGV4ZWN1dGVkIHdpdGggdGhlIGB0aGlzYCBiaW5kaW5nIG9mIHRoZSBtZW1vaXplZCBmdW5jdGlvbi4gVGhlIHJlc3VsdFxuICAgICAqIGNhY2hlIGlzIGV4cG9zZWQgYXMgdGhlIGBjYWNoZWAgcHJvcGVydHkgb24gdGhlIG1lbW9pemVkIGZ1bmN0aW9uLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IEZ1bmN0aW9uc1xuICAgICAqIEBwYXJhbSB7RnVuY3Rpb259IGZ1bmMgVGhlIGZ1bmN0aW9uIHRvIGhhdmUgaXRzIG91dHB1dCBtZW1vaXplZC5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBbcmVzb2x2ZXJdIEEgZnVuY3Rpb24gdXNlZCB0byByZXNvbHZlIHRoZSBjYWNoZSBrZXkuXG4gICAgICogQHJldHVybnMge0Z1bmN0aW9ufSBSZXR1cm5zIHRoZSBuZXcgbWVtb2l6aW5nIGZ1bmN0aW9uLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiB2YXIgZmlib25hY2NpID0gXy5tZW1vaXplKGZ1bmN0aW9uKG4pIHtcbiAgICAgKiAgIHJldHVybiBuIDwgMiA/IG4gOiBmaWJvbmFjY2kobiAtIDEpICsgZmlib25hY2NpKG4gLSAyKTtcbiAgICAgKiB9KTtcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBtZW1vaXplKGZ1bmMsIHJlc29sdmVyKSB7XG4gICAgICBmdW5jdGlvbiBtZW1vaXplZCgpIHtcbiAgICAgICAgdmFyIGNhY2hlID0gbWVtb2l6ZWQuY2FjaGUsXG4gICAgICAgICAgICBrZXkgPSBrZXlQcmVmaXggKyAocmVzb2x2ZXIgPyByZXNvbHZlci5hcHBseSh0aGlzLCBhcmd1bWVudHMpIDogYXJndW1lbnRzWzBdKTtcblxuICAgICAgICByZXR1cm4gaGFzT3duUHJvcGVydHkuY2FsbChjYWNoZSwga2V5KVxuICAgICAgICAgID8gY2FjaGVba2V5XVxuICAgICAgICAgIDogKGNhY2hlW2tleV0gPSBmdW5jLmFwcGx5KHRoaXMsIGFyZ3VtZW50cykpO1xuICAgICAgfVxuICAgICAgbWVtb2l6ZWQuY2FjaGUgPSB7fTtcbiAgICAgIHJldHVybiBtZW1vaXplZDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGEgZnVuY3Rpb24gdGhhdCBpcyByZXN0cmljdGVkIHRvIGV4ZWN1dGUgYGZ1bmNgIG9uY2UuIFJlcGVhdCBjYWxscyB0b1xuICAgICAqIHRoZSBmdW5jdGlvbiB3aWxsIHJldHVybiB0aGUgdmFsdWUgb2YgdGhlIGZpcnN0IGNhbGwuIFRoZSBgZnVuY2AgaXMgZXhlY3V0ZWRcbiAgICAgKiB3aXRoIHRoZSBgdGhpc2AgYmluZGluZyBvZiB0aGUgY3JlYXRlZCBmdW5jdGlvbi5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBGdW5jdGlvbnNcbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBmdW5jIFRoZSBmdW5jdGlvbiB0byByZXN0cmljdC5cbiAgICAgKiBAcmV0dXJucyB7RnVuY3Rpb259IFJldHVybnMgdGhlIG5ldyByZXN0cmljdGVkIGZ1bmN0aW9uLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiB2YXIgaW5pdGlhbGl6ZSA9IF8ub25jZShjcmVhdGVBcHBsaWNhdGlvbik7XG4gICAgICogaW5pdGlhbGl6ZSgpO1xuICAgICAqIGluaXRpYWxpemUoKTtcbiAgICAgKiAvLyBgaW5pdGlhbGl6ZWAgZXhlY3V0ZXMgYGNyZWF0ZUFwcGxpY2F0aW9uYCBvbmNlXG4gICAgICovXG4gICAgZnVuY3Rpb24gb25jZShmdW5jKSB7XG4gICAgICB2YXIgcmFuLFxuICAgICAgICAgIHJlc3VsdDtcblxuICAgICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgICAgICBpZiAocmFuKSB7XG4gICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfVxuICAgICAgICByYW4gPSB0cnVlO1xuICAgICAgICByZXN1bHQgPSBmdW5jLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG5cbiAgICAgICAgLy8gY2xlYXIgdGhlIGBmdW5jYCB2YXJpYWJsZSBzbyB0aGUgZnVuY3Rpb24gbWF5IGJlIGdhcmJhZ2UgY29sbGVjdGVkXG4gICAgICAgIGZ1bmMgPSBudWxsO1xuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgfTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGEgZnVuY3Rpb24gdGhhdCwgd2hlbiBjYWxsZWQsIGludm9rZXMgYGZ1bmNgIHdpdGggYW55IGFkZGl0aW9uYWxcbiAgICAgKiBgcGFydGlhbGAgYXJndW1lbnRzIHByZXBlbmRlZCB0byB0aG9zZSBwYXNzZWQgdG8gdGhlIG5ldyBmdW5jdGlvbi4gVGhpc1xuICAgICAqIG1ldGhvZCBpcyBzaW1pbGFyIHRvIGBfLmJpbmRgLCBleGNlcHQgaXQgZG9lcyAqKm5vdCoqIGFsdGVyIHRoZSBgdGhpc2AgYmluZGluZy5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBGdW5jdGlvbnNcbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBmdW5jIFRoZSBmdW5jdGlvbiB0byBwYXJ0aWFsbHkgYXBwbHkgYXJndW1lbnRzIHRvLlxuICAgICAqIEBwYXJhbSB7TWl4ZWR9IFthcmcxLCBhcmcyLCAuLi5dIEFyZ3VtZW50cyB0byBiZSBwYXJ0aWFsbHkgYXBwbGllZC5cbiAgICAgKiBAcmV0dXJucyB7RnVuY3Rpb259IFJldHVybnMgdGhlIG5ldyBwYXJ0aWFsbHkgYXBwbGllZCBmdW5jdGlvbi5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogdmFyIGdyZWV0ID0gZnVuY3Rpb24oZ3JlZXRpbmcsIG5hbWUpIHsgcmV0dXJuIGdyZWV0aW5nICsgJyAnICsgbmFtZTsgfTtcbiAgICAgKiB2YXIgaGkgPSBfLnBhcnRpYWwoZ3JlZXQsICdoaScpO1xuICAgICAqIGhpKCdtb2UnKTtcbiAgICAgKiAvLyA9PiAnaGkgbW9lJ1xuICAgICAqL1xuICAgIGZ1bmN0aW9uIHBhcnRpYWwoZnVuYykge1xuICAgICAgcmV0dXJuIGNyZWF0ZUJvdW5kKGZ1bmMsIG5hdGl2ZVNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVGhpcyBtZXRob2QgaXMgc2ltaWxhciB0byBgXy5wYXJ0aWFsYCwgZXhjZXB0IHRoYXQgYHBhcnRpYWxgIGFyZ3VtZW50cyBhcmVcbiAgICAgKiBhcHBlbmRlZCB0byB0aG9zZSBwYXNzZWQgdG8gdGhlIG5ldyBmdW5jdGlvbi5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBGdW5jdGlvbnNcbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBmdW5jIFRoZSBmdW5jdGlvbiB0byBwYXJ0aWFsbHkgYXBwbHkgYXJndW1lbnRzIHRvLlxuICAgICAqIEBwYXJhbSB7TWl4ZWR9IFthcmcxLCBhcmcyLCAuLi5dIEFyZ3VtZW50cyB0byBiZSBwYXJ0aWFsbHkgYXBwbGllZC5cbiAgICAgKiBAcmV0dXJucyB7RnVuY3Rpb259IFJldHVybnMgdGhlIG5ldyBwYXJ0aWFsbHkgYXBwbGllZCBmdW5jdGlvbi5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogdmFyIGRlZmF1bHRzRGVlcCA9IF8ucGFydGlhbFJpZ2h0KF8ubWVyZ2UsIF8uZGVmYXVsdHMpO1xuICAgICAqXG4gICAgICogdmFyIG9wdGlvbnMgPSB7XG4gICAgICogICAndmFyaWFibGUnOiAnZGF0YScsXG4gICAgICogICAnaW1wb3J0cyc6IHsgJ2pxJzogJCB9XG4gICAgICogfTtcbiAgICAgKlxuICAgICAqIGRlZmF1bHRzRGVlcChvcHRpb25zLCBfLnRlbXBsYXRlU2V0dGluZ3MpO1xuICAgICAqXG4gICAgICogb3B0aW9ucy52YXJpYWJsZVxuICAgICAqIC8vID0+ICdkYXRhJ1xuICAgICAqXG4gICAgICogb3B0aW9ucy5pbXBvcnRzXG4gICAgICogLy8gPT4geyAnXyc6IF8sICdqcSc6ICQgfVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIHBhcnRpYWxSaWdodChmdW5jKSB7XG4gICAgICByZXR1cm4gY3JlYXRlQm91bmQoZnVuYywgbmF0aXZlU2xpY2UuY2FsbChhcmd1bWVudHMsIDEpLCBudWxsLCBpbmRpY2F0b3JPYmplY3QpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYSBmdW5jdGlvbiB0aGF0LCB3aGVuIGV4ZWN1dGVkLCB3aWxsIG9ubHkgY2FsbCB0aGUgYGZ1bmNgIGZ1bmN0aW9uXG4gICAgICogYXQgbW9zdCBvbmNlIHBlciBldmVyeSBgd2FpdGAgbWlsbGlzZWNvbmRzLiBQYXNzIGFuIGBvcHRpb25zYCBvYmplY3QgdG9cbiAgICAgKiBpbmRpY2F0ZSB0aGF0IGBmdW5jYCBzaG91bGQgYmUgaW52b2tlZCBvbiB0aGUgbGVhZGluZyBhbmQvb3IgdHJhaWxpbmcgZWRnZVxuICAgICAqIG9mIHRoZSBgd2FpdGAgdGltZW91dC4gU3Vic2VxdWVudCBjYWxscyB0byB0aGUgdGhyb3R0bGVkIGZ1bmN0aW9uIHdpbGxcbiAgICAgKiByZXR1cm4gdGhlIHJlc3VsdCBvZiB0aGUgbGFzdCBgZnVuY2AgY2FsbC5cbiAgICAgKlxuICAgICAqIE5vdGU6IElmIGBsZWFkaW5nYCBhbmQgYHRyYWlsaW5nYCBvcHRpb25zIGFyZSBgdHJ1ZWAsIGBmdW5jYCB3aWxsIGJlIGNhbGxlZFxuICAgICAqIG9uIHRoZSB0cmFpbGluZyBlZGdlIG9mIHRoZSB0aW1lb3V0IG9ubHkgaWYgdGhlIHRoZSB0aHJvdHRsZWQgZnVuY3Rpb24gaXNcbiAgICAgKiBpbnZva2VkIG1vcmUgdGhhbiBvbmNlIGR1cmluZyB0aGUgYHdhaXRgIHRpbWVvdXQuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgRnVuY3Rpb25zXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbn0gZnVuYyBUaGUgZnVuY3Rpb24gdG8gdGhyb3R0bGUuXG4gICAgICogQHBhcmFtIHtOdW1iZXJ9IHdhaXQgVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gdGhyb3R0bGUgZXhlY3V0aW9ucyB0by5cbiAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBUaGUgb3B0aW9ucyBvYmplY3QuXG4gICAgICogIFtsZWFkaW5nPXRydWVdIEEgYm9vbGVhbiB0byBzcGVjaWZ5IGV4ZWN1dGlvbiBvbiB0aGUgbGVhZGluZyBlZGdlIG9mIHRoZSB0aW1lb3V0LlxuICAgICAqICBbdHJhaWxpbmc9dHJ1ZV0gQSBib29sZWFuIHRvIHNwZWNpZnkgZXhlY3V0aW9uIG9uIHRoZSB0cmFpbGluZyBlZGdlIG9mIHRoZSB0aW1lb3V0LlxuICAgICAqIEByZXR1cm5zIHtGdW5jdGlvbn0gUmV0dXJucyB0aGUgbmV3IHRocm90dGxlZCBmdW5jdGlvbi5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogdmFyIHRocm90dGxlZCA9IF8udGhyb3R0bGUodXBkYXRlUG9zaXRpb24sIDEwMCk7XG4gICAgICogalF1ZXJ5KHdpbmRvdykub24oJ3Njcm9sbCcsIHRocm90dGxlZCk7XG4gICAgICpcbiAgICAgKiBqUXVlcnkoJy5pbnRlcmFjdGl2ZScpLm9uKCdjbGljaycsIF8udGhyb3R0bGUocmVuZXdUb2tlbiwgMzAwMDAwLCB7XG4gICAgICogICAndHJhaWxpbmcnOiBmYWxzZVxuICAgICAqIH0pKTtcbiAgICAgKi9cbiAgICBmdW5jdGlvbiB0aHJvdHRsZShmdW5jLCB3YWl0LCBvcHRpb25zKSB7XG4gICAgICB2YXIgbGVhZGluZyA9IHRydWUsXG4gICAgICAgICAgdHJhaWxpbmcgPSB0cnVlO1xuXG4gICAgICBpZiAob3B0aW9ucyA9PT0gZmFsc2UpIHtcbiAgICAgICAgbGVhZGluZyA9IGZhbHNlO1xuICAgICAgfSBlbHNlIGlmIChpc09iamVjdChvcHRpb25zKSkge1xuICAgICAgICBsZWFkaW5nID0gJ2xlYWRpbmcnIGluIG9wdGlvbnMgPyBvcHRpb25zLmxlYWRpbmcgOiBsZWFkaW5nO1xuICAgICAgICB0cmFpbGluZyA9ICd0cmFpbGluZycgaW4gb3B0aW9ucyA/IG9wdGlvbnMudHJhaWxpbmcgOiB0cmFpbGluZztcbiAgICAgIH1cbiAgICAgIG9wdGlvbnMgPSBnZXRPYmplY3QoKTtcbiAgICAgIG9wdGlvbnMubGVhZGluZyA9IGxlYWRpbmc7XG4gICAgICBvcHRpb25zLm1heFdhaXQgPSB3YWl0O1xuICAgICAgb3B0aW9ucy50cmFpbGluZyA9IHRyYWlsaW5nO1xuXG4gICAgICB2YXIgcmVzdWx0ID0gZGVib3VuY2UoZnVuYywgd2FpdCwgb3B0aW9ucyk7XG4gICAgICByZWxlYXNlT2JqZWN0KG9wdGlvbnMpO1xuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGEgZnVuY3Rpb24gdGhhdCBwYXNzZXMgYHZhbHVlYCB0byB0aGUgYHdyYXBwZXJgIGZ1bmN0aW9uIGFzIGl0c1xuICAgICAqIGZpcnN0IGFyZ3VtZW50LiBBZGRpdGlvbmFsIGFyZ3VtZW50cyBwYXNzZWQgdG8gdGhlIGZ1bmN0aW9uIGFyZSBhcHBlbmRlZFxuICAgICAqIHRvIHRob3NlIHBhc3NlZCB0byB0aGUgYHdyYXBwZXJgIGZ1bmN0aW9uLiBUaGUgYHdyYXBwZXJgIGlzIGV4ZWN1dGVkIHdpdGhcbiAgICAgKiB0aGUgYHRoaXNgIGJpbmRpbmcgb2YgdGhlIGNyZWF0ZWQgZnVuY3Rpb24uXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgRnVuY3Rpb25zXG4gICAgICogQHBhcmFtIHtNaXhlZH0gdmFsdWUgVGhlIHZhbHVlIHRvIHdyYXAuXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbn0gd3JhcHBlciBUaGUgd3JhcHBlciBmdW5jdGlvbi5cbiAgICAgKiBAcmV0dXJucyB7RnVuY3Rpb259IFJldHVybnMgdGhlIG5ldyBmdW5jdGlvbi5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogdmFyIGhlbGxvID0gZnVuY3Rpb24obmFtZSkgeyByZXR1cm4gJ2hlbGxvICcgKyBuYW1lOyB9O1xuICAgICAqIGhlbGxvID0gXy53cmFwKGhlbGxvLCBmdW5jdGlvbihmdW5jKSB7XG4gICAgICogICByZXR1cm4gJ2JlZm9yZSwgJyArIGZ1bmMoJ21vZScpICsgJywgYWZ0ZXInO1xuICAgICAqIH0pO1xuICAgICAqIGhlbGxvKCk7XG4gICAgICogLy8gPT4gJ2JlZm9yZSwgaGVsbG8gbW9lLCBhZnRlcidcbiAgICAgKi9cbiAgICBmdW5jdGlvbiB3cmFwKHZhbHVlLCB3cmFwcGVyKSB7XG4gICAgICByZXR1cm4gZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBhcmdzID0gW3ZhbHVlXTtcbiAgICAgICAgcHVzaC5hcHBseShhcmdzLCBhcmd1bWVudHMpO1xuICAgICAgICByZXR1cm4gd3JhcHBlci5hcHBseSh0aGlzLCBhcmdzKTtcbiAgICAgIH07XG4gICAgfVxuXG4gICAgLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5cbiAgICAvKipcbiAgICAgKiBDb252ZXJ0cyB0aGUgY2hhcmFjdGVycyBgJmAsIGA8YCwgYD5gLCBgXCJgLCBhbmQgYCdgIGluIGBzdHJpbmdgIHRvIHRoZWlyXG4gICAgICogY29ycmVzcG9uZGluZyBIVE1MIGVudGl0aWVzLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IFV0aWxpdGllc1xuICAgICAqIEBwYXJhbSB7U3RyaW5nfSBzdHJpbmcgVGhlIHN0cmluZyB0byBlc2NhcGUuXG4gICAgICogQHJldHVybnMge1N0cmluZ30gUmV0dXJucyB0aGUgZXNjYXBlZCBzdHJpbmcuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8uZXNjYXBlKCdNb2UsIExhcnJ5ICYgQ3VybHknKTtcbiAgICAgKiAvLyA9PiAnTW9lLCBMYXJyeSAmYW1wOyBDdXJseSdcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBlc2NhcGUoc3RyaW5nKSB7XG4gICAgICByZXR1cm4gc3RyaW5nID09IG51bGwgPyAnJyA6IFN0cmluZyhzdHJpbmcpLnJlcGxhY2UocmVVbmVzY2FwZWRIdG1sLCBlc2NhcGVIdG1sQ2hhcik7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVGhpcyBtZXRob2QgcmV0dXJucyB0aGUgZmlyc3QgYXJndW1lbnQgcGFzc2VkIHRvIGl0LlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IFV0aWxpdGllc1xuICAgICAqIEBwYXJhbSB7TWl4ZWR9IHZhbHVlIEFueSB2YWx1ZS5cbiAgICAgKiBAcmV0dXJucyB7TWl4ZWR9IFJldHVybnMgYHZhbHVlYC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogdmFyIG1vZSA9IHsgJ25hbWUnOiAnbW9lJyB9O1xuICAgICAqIG1vZSA9PT0gXy5pZGVudGl0eShtb2UpO1xuICAgICAqIC8vID0+IHRydWVcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBpZGVudGl0eSh2YWx1ZSkge1xuICAgICAgcmV0dXJuIHZhbHVlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEFkZHMgZnVuY3Rpb25zIHByb3BlcnRpZXMgb2YgYG9iamVjdGAgdG8gdGhlIGBsb2Rhc2hgIGZ1bmN0aW9uIGFuZCBjaGFpbmFibGVcbiAgICAgKiB3cmFwcGVyLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IFV0aWxpdGllc1xuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3QgVGhlIG9iamVjdCBvZiBmdW5jdGlvbiBwcm9wZXJ0aWVzIHRvIGFkZCB0byBgbG9kYXNoYC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy5taXhpbih7XG4gICAgICogICAnY2FwaXRhbGl6ZSc6IGZ1bmN0aW9uKHN0cmluZykge1xuICAgICAqICAgICByZXR1cm4gc3RyaW5nLmNoYXJBdCgwKS50b1VwcGVyQ2FzZSgpICsgc3RyaW5nLnNsaWNlKDEpLnRvTG93ZXJDYXNlKCk7XG4gICAgICogICB9XG4gICAgICogfSk7XG4gICAgICpcbiAgICAgKiBfLmNhcGl0YWxpemUoJ21vZScpO1xuICAgICAqIC8vID0+ICdNb2UnXG4gICAgICpcbiAgICAgKiBfKCdtb2UnKS5jYXBpdGFsaXplKCk7XG4gICAgICogLy8gPT4gJ01vZSdcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBtaXhpbihvYmplY3QpIHtcbiAgICAgIGZvckVhY2goZnVuY3Rpb25zKG9iamVjdCksIGZ1bmN0aW9uKG1ldGhvZE5hbWUpIHtcbiAgICAgICAgdmFyIGZ1bmMgPSBsb2Rhc2hbbWV0aG9kTmFtZV0gPSBvYmplY3RbbWV0aG9kTmFtZV07XG5cbiAgICAgICAgbG9kYXNoLnByb3RvdHlwZVttZXRob2ROYW1lXSA9IGZ1bmN0aW9uKCkge1xuICAgICAgICAgIHZhciB2YWx1ZSA9IHRoaXMuX193cmFwcGVkX18sXG4gICAgICAgICAgICAgIGFyZ3MgPSBbdmFsdWVdO1xuXG4gICAgICAgICAgcHVzaC5hcHBseShhcmdzLCBhcmd1bWVudHMpO1xuICAgICAgICAgIHZhciByZXN1bHQgPSBmdW5jLmFwcGx5KGxvZGFzaCwgYXJncyk7XG4gICAgICAgICAgcmV0dXJuICh2YWx1ZSAmJiB0eXBlb2YgdmFsdWUgPT0gJ29iamVjdCcgJiYgdmFsdWUgPT09IHJlc3VsdClcbiAgICAgICAgICAgID8gdGhpc1xuICAgICAgICAgICAgOiBuZXcgbG9kYXNoV3JhcHBlcihyZXN1bHQpO1xuICAgICAgICB9O1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV2ZXJ0cyB0aGUgJ18nIHZhcmlhYmxlIHRvIGl0cyBwcmV2aW91cyB2YWx1ZSBhbmQgcmV0dXJucyBhIHJlZmVyZW5jZSB0b1xuICAgICAqIHRoZSBgbG9kYXNoYCBmdW5jdGlvbi5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBVdGlsaXRpZXNcbiAgICAgKiBAcmV0dXJucyB7RnVuY3Rpb259IFJldHVybnMgdGhlIGBsb2Rhc2hgIGZ1bmN0aW9uLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiB2YXIgbG9kYXNoID0gXy5ub0NvbmZsaWN0KCk7XG4gICAgICovXG4gICAgZnVuY3Rpb24gbm9Db25mbGljdCgpIHtcbiAgICAgIGNvbnRleHQuXyA9IG9sZERhc2g7XG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDb252ZXJ0cyB0aGUgZ2l2ZW4gYHZhbHVlYCBpbnRvIGFuIGludGVnZXIgb2YgdGhlIHNwZWNpZmllZCBgcmFkaXhgLlxuICAgICAqIElmIGByYWRpeGAgaXMgYHVuZGVmaW5lZGAgb3IgYDBgLCBhIGByYWRpeGAgb2YgYDEwYCBpcyB1c2VkIHVubGVzcyB0aGVcbiAgICAgKiBgdmFsdWVgIGlzIGEgaGV4YWRlY2ltYWwsIGluIHdoaWNoIGNhc2UgYSBgcmFkaXhgIG9mIGAxNmAgaXMgdXNlZC5cbiAgICAgKlxuICAgICAqIE5vdGU6IFRoaXMgbWV0aG9kIGF2b2lkcyBkaWZmZXJlbmNlcyBpbiBuYXRpdmUgRVMzIGFuZCBFUzUgYHBhcnNlSW50YFxuICAgICAqIGltcGxlbWVudGF0aW9ucy4gU2VlIGh0dHA6Ly9lczUuZ2l0aHViLmNvbS8jRS5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBVdGlsaXRpZXNcbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gdmFsdWUgVGhlIHZhbHVlIHRvIHBhcnNlLlxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSBbcmFkaXhdIFRoZSByYWRpeCB1c2VkIHRvIGludGVycHJldCB0aGUgdmFsdWUgdG8gcGFyc2UuXG4gICAgICogQHJldHVybnMge051bWJlcn0gUmV0dXJucyB0aGUgbmV3IGludGVnZXIgdmFsdWUuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8ucGFyc2VJbnQoJzA4Jyk7XG4gICAgICogLy8gPT4gOFxuICAgICAqL1xuICAgIHZhciBwYXJzZUludCA9IG5hdGl2ZVBhcnNlSW50KHdoaXRlc3BhY2UgKyAnMDgnKSA9PSA4ID8gbmF0aXZlUGFyc2VJbnQgOiBmdW5jdGlvbih2YWx1ZSwgcmFkaXgpIHtcbiAgICAgIC8vIEZpcmVmb3ggYW5kIE9wZXJhIHN0aWxsIGZvbGxvdyB0aGUgRVMzIHNwZWNpZmllZCBpbXBsZW1lbnRhdGlvbiBvZiBgcGFyc2VJbnRgXG4gICAgICByZXR1cm4gbmF0aXZlUGFyc2VJbnQoaXNTdHJpbmcodmFsdWUpID8gdmFsdWUucmVwbGFjZShyZUxlYWRpbmdTcGFjZXNBbmRaZXJvcywgJycpIDogdmFsdWUsIHJhZGl4IHx8IDApO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBQcm9kdWNlcyBhIHJhbmRvbSBudW1iZXIgYmV0d2VlbiBgbWluYCBhbmQgYG1heGAgKGluY2x1c2l2ZSkuIElmIG9ubHkgb25lXG4gICAgICogYXJndW1lbnQgaXMgcGFzc2VkLCBhIG51bWJlciBiZXR3ZWVuIGAwYCBhbmQgdGhlIGdpdmVuIG51bWJlciB3aWxsIGJlIHJldHVybmVkLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IFV0aWxpdGllc1xuICAgICAqIEBwYXJhbSB7TnVtYmVyfSBbbWluPTBdIFRoZSBtaW5pbXVtIHBvc3NpYmxlIHZhbHVlLlxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSBbbWF4PTFdIFRoZSBtYXhpbXVtIHBvc3NpYmxlIHZhbHVlLlxuICAgICAqIEByZXR1cm5zIHtOdW1iZXJ9IFJldHVybnMgYSByYW5kb20gbnVtYmVyLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfLnJhbmRvbSgwLCA1KTtcbiAgICAgKiAvLyA9PiBhIG51bWJlciBiZXR3ZWVuIDAgYW5kIDVcbiAgICAgKlxuICAgICAqIF8ucmFuZG9tKDUpO1xuICAgICAqIC8vID0+IGFsc28gYSBudW1iZXIgYmV0d2VlbiAwIGFuZCA1XG4gICAgICovXG4gICAgZnVuY3Rpb24gcmFuZG9tKG1pbiwgbWF4KSB7XG4gICAgICBpZiAobWluID09IG51bGwgJiYgbWF4ID09IG51bGwpIHtcbiAgICAgICAgbWF4ID0gMTtcbiAgICAgIH1cbiAgICAgIG1pbiA9ICttaW4gfHwgMDtcbiAgICAgIGlmIChtYXggPT0gbnVsbCkge1xuICAgICAgICBtYXggPSBtaW47XG4gICAgICAgIG1pbiA9IDA7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBtYXggPSArbWF4IHx8IDA7XG4gICAgICB9XG4gICAgICB2YXIgcmFuZCA9IG5hdGl2ZVJhbmRvbSgpO1xuICAgICAgcmV0dXJuIChtaW4gJSAxIHx8IG1heCAlIDEpXG4gICAgICAgID8gbWluICsgbmF0aXZlTWluKHJhbmQgKiAobWF4IC0gbWluICsgcGFyc2VGbG9hdCgnMWUtJyArICgocmFuZCArJycpLmxlbmd0aCAtIDEpKSksIG1heClcbiAgICAgICAgOiBtaW4gKyBmbG9vcihyYW5kICogKG1heCAtIG1pbiArIDEpKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXNvbHZlcyB0aGUgdmFsdWUgb2YgYHByb3BlcnR5YCBvbiBgb2JqZWN0YC4gSWYgYHByb3BlcnR5YCBpcyBhIGZ1bmN0aW9uLFxuICAgICAqIGl0IHdpbGwgYmUgaW52b2tlZCB3aXRoIHRoZSBgdGhpc2AgYmluZGluZyBvZiBgb2JqZWN0YCBhbmQgaXRzIHJlc3VsdCByZXR1cm5lZCxcbiAgICAgKiBlbHNlIHRoZSBwcm9wZXJ0eSB2YWx1ZSBpcyByZXR1cm5lZC4gSWYgYG9iamVjdGAgaXMgZmFsc2V5LCB0aGVuIGB1bmRlZmluZWRgXG4gICAgICogaXMgcmV0dXJuZWQuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgVXRpbGl0aWVzXG4gICAgICogQHBhcmFtIHtPYmplY3R9IG9iamVjdCBUaGUgb2JqZWN0IHRvIGluc3BlY3QuXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IHByb3BlcnR5IFRoZSBwcm9wZXJ0eSB0byBnZXQgdGhlIHZhbHVlIG9mLlxuICAgICAqIEByZXR1cm5zIHtNaXhlZH0gUmV0dXJucyB0aGUgcmVzb2x2ZWQgdmFsdWUuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIHZhciBvYmplY3QgPSB7XG4gICAgICogICAnY2hlZXNlJzogJ2NydW1wZXRzJyxcbiAgICAgKiAgICdzdHVmZic6IGZ1bmN0aW9uKCkge1xuICAgICAqICAgICByZXR1cm4gJ25vbnNlbnNlJztcbiAgICAgKiAgIH1cbiAgICAgKiB9O1xuICAgICAqXG4gICAgICogXy5yZXN1bHQob2JqZWN0LCAnY2hlZXNlJyk7XG4gICAgICogLy8gPT4gJ2NydW1wZXRzJ1xuICAgICAqXG4gICAgICogXy5yZXN1bHQob2JqZWN0LCAnc3R1ZmYnKTtcbiAgICAgKiAvLyA9PiAnbm9uc2Vuc2UnXG4gICAgICovXG4gICAgZnVuY3Rpb24gcmVzdWx0KG9iamVjdCwgcHJvcGVydHkpIHtcbiAgICAgIHZhciB2YWx1ZSA9IG9iamVjdCA/IG9iamVjdFtwcm9wZXJ0eV0gOiB1bmRlZmluZWQ7XG4gICAgICByZXR1cm4gaXNGdW5jdGlvbih2YWx1ZSkgPyBvYmplY3RbcHJvcGVydHldKCkgOiB2YWx1ZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBBIG1pY3JvLXRlbXBsYXRpbmcgbWV0aG9kIHRoYXQgaGFuZGxlcyBhcmJpdHJhcnkgZGVsaW1pdGVycywgcHJlc2VydmVzXG4gICAgICogd2hpdGVzcGFjZSwgYW5kIGNvcnJlY3RseSBlc2NhcGVzIHF1b3RlcyB3aXRoaW4gaW50ZXJwb2xhdGVkIGNvZGUuXG4gICAgICpcbiAgICAgKiBOb3RlOiBJbiB0aGUgZGV2ZWxvcG1lbnQgYnVpbGQsIGBfLnRlbXBsYXRlYCB1dGlsaXplcyBzb3VyY2VVUkxzIGZvciBlYXNpZXJcbiAgICAgKiBkZWJ1Z2dpbmcuIFNlZSBodHRwOi8vd3d3Lmh0bWw1cm9ja3MuY29tL2VuL3R1dG9yaWFscy9kZXZlbG9wZXJ0b29scy9zb3VyY2VtYXBzLyN0b2Mtc291cmNldXJsXG4gICAgICpcbiAgICAgKiBGb3IgbW9yZSBpbmZvcm1hdGlvbiBvbiBwcmVjb21waWxpbmcgdGVtcGxhdGVzIHNlZTpcbiAgICAgKiBodHRwOi8vbG9kYXNoLmNvbS8jY3VzdG9tLWJ1aWxkc1xuICAgICAqXG4gICAgICogRm9yIG1vcmUgaW5mb3JtYXRpb24gb24gQ2hyb21lIGV4dGVuc2lvbiBzYW5kYm94ZXMgc2VlOlxuICAgICAqIGh0dHA6Ly9kZXZlbG9wZXIuY2hyb21lLmNvbS9zdGFibGUvZXh0ZW5zaW9ucy9zYW5kYm94aW5nRXZhbC5odG1sXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQG1lbWJlck9mIF9cbiAgICAgKiBAY2F0ZWdvcnkgVXRpbGl0aWVzXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IHRleHQgVGhlIHRlbXBsYXRlIHRleHQuXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGRhdGEgVGhlIGRhdGEgb2JqZWN0IHVzZWQgdG8gcG9wdWxhdGUgdGhlIHRleHQuXG4gICAgICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgVGhlIG9wdGlvbnMgb2JqZWN0LlxuICAgICAqICBlc2NhcGUgLSBUaGUgXCJlc2NhcGVcIiBkZWxpbWl0ZXIgcmVnZXhwLlxuICAgICAqICBldmFsdWF0ZSAtIFRoZSBcImV2YWx1YXRlXCIgZGVsaW1pdGVyIHJlZ2V4cC5cbiAgICAgKiAgaW50ZXJwb2xhdGUgLSBUaGUgXCJpbnRlcnBvbGF0ZVwiIGRlbGltaXRlciByZWdleHAuXG4gICAgICogIHNvdXJjZVVSTCAtIFRoZSBzb3VyY2VVUkwgb2YgdGhlIHRlbXBsYXRlJ3MgY29tcGlsZWQgc291cmNlLlxuICAgICAqICB2YXJpYWJsZSAtIFRoZSBkYXRhIG9iamVjdCB2YXJpYWJsZSBuYW1lLlxuICAgICAqIEByZXR1cm5zIHtGdW5jdGlvbnxTdHJpbmd9IFJldHVybnMgYSBjb21waWxlZCBmdW5jdGlvbiB3aGVuIG5vIGBkYXRhYCBvYmplY3RcbiAgICAgKiAgaXMgZ2l2ZW4sIGVsc2UgaXQgcmV0dXJucyB0aGUgaW50ZXJwb2xhdGVkIHRleHQuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIC8vIHVzaW5nIGEgY29tcGlsZWQgdGVtcGxhdGVcbiAgICAgKiB2YXIgY29tcGlsZWQgPSBfLnRlbXBsYXRlKCdoZWxsbyA8JT0gbmFtZSAlPicpO1xuICAgICAqIGNvbXBpbGVkKHsgJ25hbWUnOiAnbW9lJyB9KTtcbiAgICAgKiAvLyA9PiAnaGVsbG8gbW9lJ1xuICAgICAqXG4gICAgICogdmFyIGxpc3QgPSAnPCUgXy5mb3JFYWNoKHBlb3BsZSwgZnVuY3Rpb24obmFtZSkgeyAlPjxsaT48JT0gbmFtZSAlPjwvbGk+PCUgfSk7ICU+JztcbiAgICAgKiBfLnRlbXBsYXRlKGxpc3QsIHsgJ3Blb3BsZSc6IFsnbW9lJywgJ2xhcnJ5J10gfSk7XG4gICAgICogLy8gPT4gJzxsaT5tb2U8L2xpPjxsaT5sYXJyeTwvbGk+J1xuICAgICAqXG4gICAgICogLy8gdXNpbmcgdGhlIFwiZXNjYXBlXCIgZGVsaW1pdGVyIHRvIGVzY2FwZSBIVE1MIGluIGRhdGEgcHJvcGVydHkgdmFsdWVzXG4gICAgICogXy50ZW1wbGF0ZSgnPGI+PCUtIHZhbHVlICU+PC9iPicsIHsgJ3ZhbHVlJzogJzxzY3JpcHQ+JyB9KTtcbiAgICAgKiAvLyA9PiAnPGI+Jmx0O3NjcmlwdCZndDs8L2I+J1xuICAgICAqXG4gICAgICogLy8gdXNpbmcgdGhlIEVTNiBkZWxpbWl0ZXIgYXMgYW4gYWx0ZXJuYXRpdmUgdG8gdGhlIGRlZmF1bHQgXCJpbnRlcnBvbGF0ZVwiIGRlbGltaXRlclxuICAgICAqIF8udGVtcGxhdGUoJ2hlbGxvICR7IG5hbWUgfScsIHsgJ25hbWUnOiAnY3VybHknIH0pO1xuICAgICAqIC8vID0+ICdoZWxsbyBjdXJseSdcbiAgICAgKlxuICAgICAqIC8vIHVzaW5nIHRoZSBpbnRlcm5hbCBgcHJpbnRgIGZ1bmN0aW9uIGluIFwiZXZhbHVhdGVcIiBkZWxpbWl0ZXJzXG4gICAgICogXy50ZW1wbGF0ZSgnPCUgcHJpbnQoXCJoZWxsbyBcIiArIGVwaXRoZXQpOyAlPiEnLCB7ICdlcGl0aGV0JzogJ3N0b29nZScgfSk7XG4gICAgICogLy8gPT4gJ2hlbGxvIHN0b29nZSEnXG4gICAgICpcbiAgICAgKiAvLyB1c2luZyBjdXN0b20gdGVtcGxhdGUgZGVsaW1pdGVyc1xuICAgICAqIF8udGVtcGxhdGVTZXR0aW5ncyA9IHtcbiAgICAgKiAgICdpbnRlcnBvbGF0ZSc6IC97eyhbXFxzXFxTXSs/KX19L2dcbiAgICAgKiB9O1xuICAgICAqXG4gICAgICogXy50ZW1wbGF0ZSgnaGVsbG8ge3sgbmFtZSB9fSEnLCB7ICduYW1lJzogJ211c3RhY2hlJyB9KTtcbiAgICAgKiAvLyA9PiAnaGVsbG8gbXVzdGFjaGUhJ1xuICAgICAqXG4gICAgICogLy8gdXNpbmcgdGhlIGBzb3VyY2VVUkxgIG9wdGlvbiB0byBzcGVjaWZ5IGEgY3VzdG9tIHNvdXJjZVVSTCBmb3IgdGhlIHRlbXBsYXRlXG4gICAgICogdmFyIGNvbXBpbGVkID0gXy50ZW1wbGF0ZSgnaGVsbG8gPCU9IG5hbWUgJT4nLCBudWxsLCB7ICdzb3VyY2VVUkwnOiAnL2Jhc2ljL2dyZWV0aW5nLmpzdCcgfSk7XG4gICAgICogY29tcGlsZWQoZGF0YSk7XG4gICAgICogLy8gPT4gZmluZCB0aGUgc291cmNlIG9mIFwiZ3JlZXRpbmcuanN0XCIgdW5kZXIgdGhlIFNvdXJjZXMgdGFiIG9yIFJlc291cmNlcyBwYW5lbCBvZiB0aGUgd2ViIGluc3BlY3RvclxuICAgICAqXG4gICAgICogLy8gdXNpbmcgdGhlIGB2YXJpYWJsZWAgb3B0aW9uIHRvIGVuc3VyZSBhIHdpdGgtc3RhdGVtZW50IGlzbid0IHVzZWQgaW4gdGhlIGNvbXBpbGVkIHRlbXBsYXRlXG4gICAgICogdmFyIGNvbXBpbGVkID0gXy50ZW1wbGF0ZSgnaGkgPCU9IGRhdGEubmFtZSAlPiEnLCBudWxsLCB7ICd2YXJpYWJsZSc6ICdkYXRhJyB9KTtcbiAgICAgKiBjb21waWxlZC5zb3VyY2U7XG4gICAgICogLy8gPT4gZnVuY3Rpb24oZGF0YSkge1xuICAgICAqICAgdmFyIF9fdCwgX19wID0gJycsIF9fZSA9IF8uZXNjYXBlO1xuICAgICAqICAgX19wICs9ICdoaSAnICsgKChfX3QgPSAoIGRhdGEubmFtZSApKSA9PSBudWxsID8gJycgOiBfX3QpICsgJyEnO1xuICAgICAqICAgcmV0dXJuIF9fcDtcbiAgICAgKiB9XG4gICAgICpcbiAgICAgKiAvLyB1c2luZyB0aGUgYHNvdXJjZWAgcHJvcGVydHkgdG8gaW5saW5lIGNvbXBpbGVkIHRlbXBsYXRlcyBmb3IgbWVhbmluZ2Z1bFxuICAgICAqIC8vIGxpbmUgbnVtYmVycyBpbiBlcnJvciBtZXNzYWdlcyBhbmQgYSBzdGFjayB0cmFjZVxuICAgICAqIGZzLndyaXRlRmlsZVN5bmMocGF0aC5qb2luKGN3ZCwgJ2pzdC5qcycpLCAnXFxcbiAgICAgKiAgIHZhciBKU1QgPSB7XFxcbiAgICAgKiAgICAgXCJtYWluXCI6ICcgKyBfLnRlbXBsYXRlKG1haW5UZXh0KS5zb3VyY2UgKyAnXFxcbiAgICAgKiAgIH07XFxcbiAgICAgKiAnKTtcbiAgICAgKi9cbiAgICBmdW5jdGlvbiB0ZW1wbGF0ZSh0ZXh0LCBkYXRhLCBvcHRpb25zKSB7XG4gICAgICAvLyBiYXNlZCBvbiBKb2huIFJlc2lnJ3MgYHRtcGxgIGltcGxlbWVudGF0aW9uXG4gICAgICAvLyBodHRwOi8vZWpvaG4ub3JnL2Jsb2cvamF2YXNjcmlwdC1taWNyby10ZW1wbGF0aW5nL1xuICAgICAgLy8gYW5kIExhdXJhIERva3Rvcm92YSdzIGRvVC5qc1xuICAgICAgLy8gaHR0cHM6Ly9naXRodWIuY29tL29sYWRvL2RvVFxuICAgICAgdmFyIHNldHRpbmdzID0gbG9kYXNoLnRlbXBsYXRlU2V0dGluZ3M7XG4gICAgICB0ZXh0IHx8ICh0ZXh0ID0gJycpO1xuXG4gICAgICAvLyBhdm9pZCBtaXNzaW5nIGRlcGVuZGVuY2llcyB3aGVuIGBpdGVyYXRvclRlbXBsYXRlYCBpcyBub3QgZGVmaW5lZFxuICAgICAgb3B0aW9ucyA9IGRlZmF1bHRzKHt9LCBvcHRpb25zLCBzZXR0aW5ncyk7XG5cbiAgICAgIHZhciBpbXBvcnRzID0gZGVmYXVsdHMoe30sIG9wdGlvbnMuaW1wb3J0cywgc2V0dGluZ3MuaW1wb3J0cyksXG4gICAgICAgICAgaW1wb3J0c0tleXMgPSBrZXlzKGltcG9ydHMpLFxuICAgICAgICAgIGltcG9ydHNWYWx1ZXMgPSB2YWx1ZXMoaW1wb3J0cyk7XG5cbiAgICAgIHZhciBpc0V2YWx1YXRpbmcsXG4gICAgICAgICAgaW5kZXggPSAwLFxuICAgICAgICAgIGludGVycG9sYXRlID0gb3B0aW9ucy5pbnRlcnBvbGF0ZSB8fCByZU5vTWF0Y2gsXG4gICAgICAgICAgc291cmNlID0gXCJfX3AgKz0gJ1wiO1xuXG4gICAgICAvLyBjb21waWxlIHRoZSByZWdleHAgdG8gbWF0Y2ggZWFjaCBkZWxpbWl0ZXJcbiAgICAgIHZhciByZURlbGltaXRlcnMgPSBSZWdFeHAoXG4gICAgICAgIChvcHRpb25zLmVzY2FwZSB8fCByZU5vTWF0Y2gpLnNvdXJjZSArICd8JyArXG4gICAgICAgIGludGVycG9sYXRlLnNvdXJjZSArICd8JyArXG4gICAgICAgIChpbnRlcnBvbGF0ZSA9PT0gcmVJbnRlcnBvbGF0ZSA/IHJlRXNUZW1wbGF0ZSA6IHJlTm9NYXRjaCkuc291cmNlICsgJ3wnICtcbiAgICAgICAgKG9wdGlvbnMuZXZhbHVhdGUgfHwgcmVOb01hdGNoKS5zb3VyY2UgKyAnfCQnXG4gICAgICAsICdnJyk7XG5cbiAgICAgIHRleHQucmVwbGFjZShyZURlbGltaXRlcnMsIGZ1bmN0aW9uKG1hdGNoLCBlc2NhcGVWYWx1ZSwgaW50ZXJwb2xhdGVWYWx1ZSwgZXNUZW1wbGF0ZVZhbHVlLCBldmFsdWF0ZVZhbHVlLCBvZmZzZXQpIHtcbiAgICAgICAgaW50ZXJwb2xhdGVWYWx1ZSB8fCAoaW50ZXJwb2xhdGVWYWx1ZSA9IGVzVGVtcGxhdGVWYWx1ZSk7XG5cbiAgICAgICAgLy8gZXNjYXBlIGNoYXJhY3RlcnMgdGhhdCBjYW5ub3QgYmUgaW5jbHVkZWQgaW4gc3RyaW5nIGxpdGVyYWxzXG4gICAgICAgIHNvdXJjZSArPSB0ZXh0LnNsaWNlKGluZGV4LCBvZmZzZXQpLnJlcGxhY2UocmVVbmVzY2FwZWRTdHJpbmcsIGVzY2FwZVN0cmluZ0NoYXIpO1xuXG4gICAgICAgIC8vIHJlcGxhY2UgZGVsaW1pdGVycyB3aXRoIHNuaXBwZXRzXG4gICAgICAgIGlmIChlc2NhcGVWYWx1ZSkge1xuICAgICAgICAgIHNvdXJjZSArPSBcIicgK1xcbl9fZShcIiArIGVzY2FwZVZhbHVlICsgXCIpICtcXG4nXCI7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGV2YWx1YXRlVmFsdWUpIHtcbiAgICAgICAgICBpc0V2YWx1YXRpbmcgPSB0cnVlO1xuICAgICAgICAgIHNvdXJjZSArPSBcIic7XFxuXCIgKyBldmFsdWF0ZVZhbHVlICsgXCI7XFxuX19wICs9ICdcIjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoaW50ZXJwb2xhdGVWYWx1ZSkge1xuICAgICAgICAgIHNvdXJjZSArPSBcIicgK1xcbigoX190ID0gKFwiICsgaW50ZXJwb2xhdGVWYWx1ZSArIFwiKSkgPT0gbnVsbCA/ICcnIDogX190KSArXFxuJ1wiO1xuICAgICAgICB9XG4gICAgICAgIGluZGV4ID0gb2Zmc2V0ICsgbWF0Y2gubGVuZ3RoO1xuXG4gICAgICAgIC8vIHRoZSBKUyBlbmdpbmUgZW1iZWRkZWQgaW4gQWRvYmUgcHJvZHVjdHMgcmVxdWlyZXMgcmV0dXJuaW5nIHRoZSBgbWF0Y2hgXG4gICAgICAgIC8vIHN0cmluZyBpbiBvcmRlciB0byBwcm9kdWNlIHRoZSBjb3JyZWN0IGBvZmZzZXRgIHZhbHVlXG4gICAgICAgIHJldHVybiBtYXRjaDtcbiAgICAgIH0pO1xuXG4gICAgICBzb3VyY2UgKz0gXCInO1xcblwiO1xuXG4gICAgICAvLyBpZiBgdmFyaWFibGVgIGlzIG5vdCBzcGVjaWZpZWQsIHdyYXAgYSB3aXRoLXN0YXRlbWVudCBhcm91bmQgdGhlIGdlbmVyYXRlZFxuICAgICAgLy8gY29kZSB0byBhZGQgdGhlIGRhdGEgb2JqZWN0IHRvIHRoZSB0b3Agb2YgdGhlIHNjb3BlIGNoYWluXG4gICAgICB2YXIgdmFyaWFibGUgPSBvcHRpb25zLnZhcmlhYmxlLFxuICAgICAgICAgIGhhc1ZhcmlhYmxlID0gdmFyaWFibGU7XG5cbiAgICAgIGlmICghaGFzVmFyaWFibGUpIHtcbiAgICAgICAgdmFyaWFibGUgPSAnb2JqJztcbiAgICAgICAgc291cmNlID0gJ3dpdGggKCcgKyB2YXJpYWJsZSArICcpIHtcXG4nICsgc291cmNlICsgJ1xcbn1cXG4nO1xuICAgICAgfVxuICAgICAgLy8gY2xlYW51cCBjb2RlIGJ5IHN0cmlwcGluZyBlbXB0eSBzdHJpbmdzXG4gICAgICBzb3VyY2UgPSAoaXNFdmFsdWF0aW5nID8gc291cmNlLnJlcGxhY2UocmVFbXB0eVN0cmluZ0xlYWRpbmcsICcnKSA6IHNvdXJjZSlcbiAgICAgICAgLnJlcGxhY2UocmVFbXB0eVN0cmluZ01pZGRsZSwgJyQxJylcbiAgICAgICAgLnJlcGxhY2UocmVFbXB0eVN0cmluZ1RyYWlsaW5nLCAnJDE7Jyk7XG5cbiAgICAgIC8vIGZyYW1lIGNvZGUgYXMgdGhlIGZ1bmN0aW9uIGJvZHlcbiAgICAgIHNvdXJjZSA9ICdmdW5jdGlvbignICsgdmFyaWFibGUgKyAnKSB7XFxuJyArXG4gICAgICAgIChoYXNWYXJpYWJsZSA/ICcnIDogdmFyaWFibGUgKyAnIHx8ICgnICsgdmFyaWFibGUgKyAnID0ge30pO1xcbicpICtcbiAgICAgICAgXCJ2YXIgX190LCBfX3AgPSAnJywgX19lID0gXy5lc2NhcGVcIiArXG4gICAgICAgIChpc0V2YWx1YXRpbmdcbiAgICAgICAgICA/ICcsIF9faiA9IEFycmF5LnByb3RvdHlwZS5qb2luO1xcbicgK1xuICAgICAgICAgICAgXCJmdW5jdGlvbiBwcmludCgpIHsgX19wICs9IF9fai5jYWxsKGFyZ3VtZW50cywgJycpIH1cXG5cIlxuICAgICAgICAgIDogJztcXG4nXG4gICAgICAgICkgK1xuICAgICAgICBzb3VyY2UgK1xuICAgICAgICAncmV0dXJuIF9fcFxcbn0nO1xuXG4gICAgICAvLyBVc2UgYSBzb3VyY2VVUkwgZm9yIGVhc2llciBkZWJ1Z2dpbmcgYW5kIHdyYXAgaW4gYSBtdWx0aS1saW5lIGNvbW1lbnQgdG9cbiAgICAgIC8vIGF2b2lkIGlzc3VlcyB3aXRoIE5hcndoYWwsIElFIGNvbmRpdGlvbmFsIGNvbXBpbGF0aW9uLCBhbmQgdGhlIEpTIGVuZ2luZVxuICAgICAgLy8gZW1iZWRkZWQgaW4gQWRvYmUgcHJvZHVjdHMuXG4gICAgICAvLyBodHRwOi8vd3d3Lmh0bWw1cm9ja3MuY29tL2VuL3R1dG9yaWFscy9kZXZlbG9wZXJ0b29scy9zb3VyY2VtYXBzLyN0b2Mtc291cmNldXJsXG4gICAgICB2YXIgc291cmNlVVJMID0gJ1xcbi8qXFxuLy9AIHNvdXJjZVVSTD0nICsgKG9wdGlvbnMuc291cmNlVVJMIHx8ICcvbG9kYXNoL3RlbXBsYXRlL3NvdXJjZVsnICsgKHRlbXBsYXRlQ291bnRlcisrKSArICddJykgKyAnXFxuKi8nO1xuXG4gICAgICB0cnkge1xuICAgICAgICB2YXIgcmVzdWx0ID0gRnVuY3Rpb24oaW1wb3J0c0tleXMsICdyZXR1cm4gJyArIHNvdXJjZSArIHNvdXJjZVVSTCkuYXBwbHkodW5kZWZpbmVkLCBpbXBvcnRzVmFsdWVzKTtcbiAgICAgIH0gY2F0Y2goZSkge1xuICAgICAgICBlLnNvdXJjZSA9IHNvdXJjZTtcbiAgICAgICAgdGhyb3cgZTtcbiAgICAgIH1cbiAgICAgIGlmIChkYXRhKSB7XG4gICAgICAgIHJldHVybiByZXN1bHQoZGF0YSk7XG4gICAgICB9XG4gICAgICAvLyBwcm92aWRlIHRoZSBjb21waWxlZCBmdW5jdGlvbidzIHNvdXJjZSB2aWEgaXRzIGB0b1N0cmluZ2AgbWV0aG9kLCBpblxuICAgICAgLy8gc3VwcG9ydGVkIGVudmlyb25tZW50cywgb3IgdGhlIGBzb3VyY2VgIHByb3BlcnR5IGFzIGEgY29udmVuaWVuY2UgZm9yXG4gICAgICAvLyBpbmxpbmluZyBjb21waWxlZCB0ZW1wbGF0ZXMgZHVyaW5nIHRoZSBidWlsZCBwcm9jZXNzXG4gICAgICByZXN1bHQuc291cmNlID0gc291cmNlO1xuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBFeGVjdXRlcyB0aGUgYGNhbGxiYWNrYCBmdW5jdGlvbiBgbmAgdGltZXMsIHJldHVybmluZyBhbiBhcnJheSBvZiB0aGUgcmVzdWx0c1xuICAgICAqIG9mIGVhY2ggYGNhbGxiYWNrYCBleGVjdXRpb24uIFRoZSBgY2FsbGJhY2tgIGlzIGJvdW5kIHRvIGB0aGlzQXJnYCBhbmQgaW52b2tlZFxuICAgICAqIHdpdGggb25lIGFyZ3VtZW50OyAoaW5kZXgpLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IFV0aWxpdGllc1xuICAgICAqIEBwYXJhbSB7TnVtYmVyfSBuIFRoZSBudW1iZXIgb2YgdGltZXMgdG8gZXhlY3V0ZSB0aGUgY2FsbGJhY2suXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2sgVGhlIGZ1bmN0aW9uIGNhbGxlZCBwZXIgaXRlcmF0aW9uLlxuICAgICAqIEBwYXJhbSB7TWl4ZWR9IFt0aGlzQXJnXSBUaGUgYHRoaXNgIGJpbmRpbmcgb2YgYGNhbGxiYWNrYC5cbiAgICAgKiBAcmV0dXJucyB7QXJyYXl9IFJldHVybnMgYSBuZXcgYXJyYXkgb2YgdGhlIHJlc3VsdHMgb2YgZWFjaCBgY2FsbGJhY2tgIGV4ZWN1dGlvbi5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogdmFyIGRpY2VSb2xscyA9IF8udGltZXMoMywgXy5wYXJ0aWFsKF8ucmFuZG9tLCAxLCA2KSk7XG4gICAgICogLy8gPT4gWzMsIDYsIDRdXG4gICAgICpcbiAgICAgKiBfLnRpbWVzKDMsIGZ1bmN0aW9uKG4pIHsgbWFnZS5jYXN0U3BlbGwobik7IH0pO1xuICAgICAqIC8vID0+IGNhbGxzIGBtYWdlLmNhc3RTcGVsbChuKWAgdGhyZWUgdGltZXMsIHBhc3NpbmcgYG5gIG9mIGAwYCwgYDFgLCBhbmQgYDJgIHJlc3BlY3RpdmVseVxuICAgICAqXG4gICAgICogXy50aW1lcygzLCBmdW5jdGlvbihuKSB7IHRoaXMuY2FzdChuKTsgfSwgbWFnZSk7XG4gICAgICogLy8gPT4gYWxzbyBjYWxscyBgbWFnZS5jYXN0U3BlbGwobilgIHRocmVlIHRpbWVzXG4gICAgICovXG4gICAgZnVuY3Rpb24gdGltZXMobiwgY2FsbGJhY2ssIHRoaXNBcmcpIHtcbiAgICAgIG4gPSAobiA9ICtuKSA+IC0xID8gbiA6IDA7XG4gICAgICB2YXIgaW5kZXggPSAtMSxcbiAgICAgICAgICByZXN1bHQgPSBBcnJheShuKTtcblxuICAgICAgY2FsbGJhY2sgPSBsb2Rhc2guY3JlYXRlQ2FsbGJhY2soY2FsbGJhY2ssIHRoaXNBcmcsIDEpO1xuICAgICAgd2hpbGUgKCsraW5kZXggPCBuKSB7XG4gICAgICAgIHJlc3VsdFtpbmRleF0gPSBjYWxsYmFjayhpbmRleCk7XG4gICAgICB9XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRoZSBpbnZlcnNlIG9mIGBfLmVzY2FwZWAsIHRoaXMgbWV0aG9kIGNvbnZlcnRzIHRoZSBIVE1MIGVudGl0aWVzXG4gICAgICogYCZhbXA7YCwgYCZsdDtgLCBgJmd0O2AsIGAmcXVvdDtgLCBhbmQgYCYjMzk7YCBpbiBgc3RyaW5nYCB0byB0aGVpclxuICAgICAqIGNvcnJlc3BvbmRpbmcgY2hhcmFjdGVycy5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBVdGlsaXRpZXNcbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gc3RyaW5nIFRoZSBzdHJpbmcgdG8gdW5lc2NhcGUuXG4gICAgICogQHJldHVybnMge1N0cmluZ30gUmV0dXJucyB0aGUgdW5lc2NhcGVkIHN0cmluZy5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy51bmVzY2FwZSgnTW9lLCBMYXJyeSAmYW1wOyBDdXJseScpO1xuICAgICAqIC8vID0+ICdNb2UsIExhcnJ5ICYgQ3VybHknXG4gICAgICovXG4gICAgZnVuY3Rpb24gdW5lc2NhcGUoc3RyaW5nKSB7XG4gICAgICByZXR1cm4gc3RyaW5nID09IG51bGwgPyAnJyA6IFN0cmluZyhzdHJpbmcpLnJlcGxhY2UocmVFc2NhcGVkSHRtbCwgdW5lc2NhcGVIdG1sQ2hhcik7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2VuZXJhdGVzIGEgdW5pcXVlIElELiBJZiBgcHJlZml4YCBpcyBwYXNzZWQsIHRoZSBJRCB3aWxsIGJlIGFwcGVuZGVkIHRvIGl0LlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IFV0aWxpdGllc1xuICAgICAqIEBwYXJhbSB7U3RyaW5nfSBbcHJlZml4XSBUaGUgdmFsdWUgdG8gcHJlZml4IHRoZSBJRCB3aXRoLlxuICAgICAqIEByZXR1cm5zIHtTdHJpbmd9IFJldHVybnMgdGhlIHVuaXF1ZSBJRC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqXG4gICAgICogXy51bmlxdWVJZCgnY29udGFjdF8nKTtcbiAgICAgKiAvLyA9PiAnY29udGFjdF8xMDQnXG4gICAgICpcbiAgICAgKiBfLnVuaXF1ZUlkKCk7XG4gICAgICogLy8gPT4gJzEwNSdcbiAgICAgKi9cbiAgICBmdW5jdGlvbiB1bmlxdWVJZChwcmVmaXgpIHtcbiAgICAgIHZhciBpZCA9ICsraWRDb3VudGVyO1xuICAgICAgcmV0dXJuIFN0cmluZyhwcmVmaXggPT0gbnVsbCA/ICcnIDogcHJlZml4KSArIGlkO1xuICAgIH1cblxuICAgIC8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuXG4gICAgLyoqXG4gICAgICogSW52b2tlcyBgaW50ZXJjZXB0b3JgIHdpdGggdGhlIGB2YWx1ZWAgYXMgdGhlIGZpcnN0IGFyZ3VtZW50LCBhbmQgdGhlblxuICAgICAqIHJldHVybnMgYHZhbHVlYC4gVGhlIHB1cnBvc2Ugb2YgdGhpcyBtZXRob2QgaXMgdG8gXCJ0YXAgaW50b1wiIGEgbWV0aG9kIGNoYWluLFxuICAgICAqIGluIG9yZGVyIHRvIHBlcmZvcm0gb3BlcmF0aW9ucyBvbiBpbnRlcm1lZGlhdGUgcmVzdWx0cyB3aXRoaW4gdGhlIGNoYWluLlxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGNhdGVnb3J5IENoYWluaW5nXG4gICAgICogQHBhcmFtIHtNaXhlZH0gdmFsdWUgVGhlIHZhbHVlIHRvIHBhc3MgdG8gYGludGVyY2VwdG9yYC5cbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBpbnRlcmNlcHRvciBUaGUgZnVuY3Rpb24gdG8gaW52b2tlLlxuICAgICAqIEByZXR1cm5zIHtNaXhlZH0gUmV0dXJucyBgdmFsdWVgLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfKFsxLCAyLCAzLCA0XSlcbiAgICAgKiAgLmZpbHRlcihmdW5jdGlvbihudW0pIHsgcmV0dXJuIG51bSAlIDIgPT0gMDsgfSlcbiAgICAgKiAgLnRhcChhbGVydClcbiAgICAgKiAgLm1hcChmdW5jdGlvbihudW0pIHsgcmV0dXJuIG51bSAqIG51bTsgfSlcbiAgICAgKiAgLnZhbHVlKCk7XG4gICAgICogLy8gPT4gLy8gWzIsIDRdIChhbGVydGVkKVxuICAgICAqIC8vID0+IFs0LCAxNl1cbiAgICAgKi9cbiAgICBmdW5jdGlvbiB0YXAodmFsdWUsIGludGVyY2VwdG9yKSB7XG4gICAgICBpbnRlcmNlcHRvcih2YWx1ZSk7XG4gICAgICByZXR1cm4gdmFsdWU7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUHJvZHVjZXMgdGhlIGB0b1N0cmluZ2AgcmVzdWx0IG9mIHRoZSB3cmFwcGVkIHZhbHVlLlxuICAgICAqXG4gICAgICogQG5hbWUgdG9TdHJpbmdcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEBjYXRlZ29yeSBDaGFpbmluZ1xuICAgICAqIEByZXR1cm5zIHtTdHJpbmd9IFJldHVybnMgdGhlIHN0cmluZyByZXN1bHQuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKlxuICAgICAqIF8oWzEsIDIsIDNdKS50b1N0cmluZygpO1xuICAgICAqIC8vID0+ICcxLDIsMydcbiAgICAgKi9cbiAgICBmdW5jdGlvbiB3cmFwcGVyVG9TdHJpbmcoKSB7XG4gICAgICByZXR1cm4gU3RyaW5nKHRoaXMuX193cmFwcGVkX18pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEV4dHJhY3RzIHRoZSB3cmFwcGVkIHZhbHVlLlxuICAgICAqXG4gICAgICogQG5hbWUgdmFsdWVPZlxuICAgICAqIEBtZW1iZXJPZiBfXG4gICAgICogQGFsaWFzIHZhbHVlXG4gICAgICogQGNhdGVnb3J5IENoYWluaW5nXG4gICAgICogQHJldHVybnMge01peGVkfSBSZXR1cm5zIHRoZSB3cmFwcGVkIHZhbHVlLlxuICAgICAqIEBleGFtcGxlXG4gICAgICpcbiAgICAgKiBfKFsxLCAyLCAzXSkudmFsdWVPZigpO1xuICAgICAqIC8vID0+IFsxLCAyLCAzXVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIHdyYXBwZXJWYWx1ZU9mKCkge1xuICAgICAgcmV0dXJuIHRoaXMuX193cmFwcGVkX187XG4gICAgfVxuXG4gICAgLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5cbiAgICAvLyBhZGQgZnVuY3Rpb25zIHRoYXQgcmV0dXJuIHdyYXBwZWQgdmFsdWVzIHdoZW4gY2hhaW5pbmdcbiAgICBsb2Rhc2guYWZ0ZXIgPSBhZnRlcjtcbiAgICBsb2Rhc2guYXNzaWduID0gYXNzaWduO1xuICAgIGxvZGFzaC5hdCA9IGF0O1xuICAgIGxvZGFzaC5iaW5kID0gYmluZDtcbiAgICBsb2Rhc2guYmluZEFsbCA9IGJpbmRBbGw7XG4gICAgbG9kYXNoLmJpbmRLZXkgPSBiaW5kS2V5O1xuICAgIGxvZGFzaC5jb21wYWN0ID0gY29tcGFjdDtcbiAgICBsb2Rhc2guY29tcG9zZSA9IGNvbXBvc2U7XG4gICAgbG9kYXNoLmNvdW50QnkgPSBjb3VudEJ5O1xuICAgIGxvZGFzaC5jcmVhdGVDYWxsYmFjayA9IGNyZWF0ZUNhbGxiYWNrO1xuICAgIGxvZGFzaC5kZWJvdW5jZSA9IGRlYm91bmNlO1xuICAgIGxvZGFzaC5kZWZhdWx0cyA9IGRlZmF1bHRzO1xuICAgIGxvZGFzaC5kZWZlciA9IGRlZmVyO1xuICAgIGxvZGFzaC5kZWxheSA9IGRlbGF5O1xuICAgIGxvZGFzaC5kaWZmZXJlbmNlID0gZGlmZmVyZW5jZTtcbiAgICBsb2Rhc2guZmlsdGVyID0gZmlsdGVyO1xuICAgIGxvZGFzaC5mbGF0dGVuID0gZmxhdHRlbjtcbiAgICBsb2Rhc2guZm9yRWFjaCA9IGZvckVhY2g7XG4gICAgbG9kYXNoLmZvckluID0gZm9ySW47XG4gICAgbG9kYXNoLmZvck93biA9IGZvck93bjtcbiAgICBsb2Rhc2guZnVuY3Rpb25zID0gZnVuY3Rpb25zO1xuICAgIGxvZGFzaC5ncm91cEJ5ID0gZ3JvdXBCeTtcbiAgICBsb2Rhc2guaW5pdGlhbCA9IGluaXRpYWw7XG4gICAgbG9kYXNoLmludGVyc2VjdGlvbiA9IGludGVyc2VjdGlvbjtcbiAgICBsb2Rhc2guaW52ZXJ0ID0gaW52ZXJ0O1xuICAgIGxvZGFzaC5pbnZva2UgPSBpbnZva2U7XG4gICAgbG9kYXNoLmtleXMgPSBrZXlzO1xuICAgIGxvZGFzaC5tYXAgPSBtYXA7XG4gICAgbG9kYXNoLm1heCA9IG1heDtcbiAgICBsb2Rhc2gubWVtb2l6ZSA9IG1lbW9pemU7XG4gICAgbG9kYXNoLm1lcmdlID0gbWVyZ2U7XG4gICAgbG9kYXNoLm1pbiA9IG1pbjtcbiAgICBsb2Rhc2gub21pdCA9IG9taXQ7XG4gICAgbG9kYXNoLm9uY2UgPSBvbmNlO1xuICAgIGxvZGFzaC5wYWlycyA9IHBhaXJzO1xuICAgIGxvZGFzaC5wYXJ0aWFsID0gcGFydGlhbDtcbiAgICBsb2Rhc2gucGFydGlhbFJpZ2h0ID0gcGFydGlhbFJpZ2h0O1xuICAgIGxvZGFzaC5waWNrID0gcGljaztcbiAgICBsb2Rhc2gucGx1Y2sgPSBwbHVjaztcbiAgICBsb2Rhc2gucmFuZ2UgPSByYW5nZTtcbiAgICBsb2Rhc2gucmVqZWN0ID0gcmVqZWN0O1xuICAgIGxvZGFzaC5yZXN0ID0gcmVzdDtcbiAgICBsb2Rhc2guc2h1ZmZsZSA9IHNodWZmbGU7XG4gICAgbG9kYXNoLnNvcnRCeSA9IHNvcnRCeTtcbiAgICBsb2Rhc2gudGFwID0gdGFwO1xuICAgIGxvZGFzaC50aHJvdHRsZSA9IHRocm90dGxlO1xuICAgIGxvZGFzaC50aW1lcyA9IHRpbWVzO1xuICAgIGxvZGFzaC50b0FycmF5ID0gdG9BcnJheTtcbiAgICBsb2Rhc2gudHJhbnNmb3JtID0gdHJhbnNmb3JtO1xuICAgIGxvZGFzaC51bmlvbiA9IHVuaW9uO1xuICAgIGxvZGFzaC51bmlxID0gdW5pcTtcbiAgICBsb2Rhc2gudW56aXAgPSB1bnppcDtcbiAgICBsb2Rhc2gudmFsdWVzID0gdmFsdWVzO1xuICAgIGxvZGFzaC53aGVyZSA9IHdoZXJlO1xuICAgIGxvZGFzaC53aXRob3V0ID0gd2l0aG91dDtcbiAgICBsb2Rhc2gud3JhcCA9IHdyYXA7XG4gICAgbG9kYXNoLnppcCA9IHppcDtcbiAgICBsb2Rhc2guemlwT2JqZWN0ID0gemlwT2JqZWN0O1xuXG4gICAgLy8gYWRkIGFsaWFzZXNcbiAgICBsb2Rhc2guY29sbGVjdCA9IG1hcDtcbiAgICBsb2Rhc2guZHJvcCA9IHJlc3Q7XG4gICAgbG9kYXNoLmVhY2ggPSBmb3JFYWNoO1xuICAgIGxvZGFzaC5leHRlbmQgPSBhc3NpZ247XG4gICAgbG9kYXNoLm1ldGhvZHMgPSBmdW5jdGlvbnM7XG4gICAgbG9kYXNoLm9iamVjdCA9IHppcE9iamVjdDtcbiAgICBsb2Rhc2guc2VsZWN0ID0gZmlsdGVyO1xuICAgIGxvZGFzaC50YWlsID0gcmVzdDtcbiAgICBsb2Rhc2gudW5pcXVlID0gdW5pcTtcblxuICAgIC8vIGFkZCBmdW5jdGlvbnMgdG8gYGxvZGFzaC5wcm90b3R5cGVgXG4gICAgbWl4aW4obG9kYXNoKTtcblxuICAgIC8vIGFkZCBVbmRlcnNjb3JlIGNvbXBhdFxuICAgIGxvZGFzaC5jaGFpbiA9IGxvZGFzaDtcbiAgICBsb2Rhc2gucHJvdG90eXBlLmNoYWluID0gZnVuY3Rpb24oKSB7IHJldHVybiB0aGlzOyB9O1xuXG4gICAgLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5cbiAgICAvLyBhZGQgZnVuY3Rpb25zIHRoYXQgcmV0dXJuIHVud3JhcHBlZCB2YWx1ZXMgd2hlbiBjaGFpbmluZ1xuICAgIGxvZGFzaC5jbG9uZSA9IGNsb25lO1xuICAgIGxvZGFzaC5jbG9uZURlZXAgPSBjbG9uZURlZXA7XG4gICAgbG9kYXNoLmNvbnRhaW5zID0gY29udGFpbnM7XG4gICAgbG9kYXNoLmVzY2FwZSA9IGVzY2FwZTtcbiAgICBsb2Rhc2guZXZlcnkgPSBldmVyeTtcbiAgICBsb2Rhc2guZmluZCA9IGZpbmQ7XG4gICAgbG9kYXNoLmZpbmRJbmRleCA9IGZpbmRJbmRleDtcbiAgICBsb2Rhc2guZmluZEtleSA9IGZpbmRLZXk7XG4gICAgbG9kYXNoLmhhcyA9IGhhcztcbiAgICBsb2Rhc2guaWRlbnRpdHkgPSBpZGVudGl0eTtcbiAgICBsb2Rhc2guaW5kZXhPZiA9IGluZGV4T2Y7XG4gICAgbG9kYXNoLmlzQXJndW1lbnRzID0gaXNBcmd1bWVudHM7XG4gICAgbG9kYXNoLmlzQXJyYXkgPSBpc0FycmF5O1xuICAgIGxvZGFzaC5pc0Jvb2xlYW4gPSBpc0Jvb2xlYW47XG4gICAgbG9kYXNoLmlzRGF0ZSA9IGlzRGF0ZTtcbiAgICBsb2Rhc2guaXNFbGVtZW50ID0gaXNFbGVtZW50O1xuICAgIGxvZGFzaC5pc0VtcHR5ID0gaXNFbXB0eTtcbiAgICBsb2Rhc2guaXNFcXVhbCA9IGlzRXF1YWw7XG4gICAgbG9kYXNoLmlzRmluaXRlID0gaXNGaW5pdGU7XG4gICAgbG9kYXNoLmlzRnVuY3Rpb24gPSBpc0Z1bmN0aW9uO1xuICAgIGxvZGFzaC5pc05hTiA9IGlzTmFOO1xuICAgIGxvZGFzaC5pc051bGwgPSBpc051bGw7XG4gICAgbG9kYXNoLmlzTnVtYmVyID0gaXNOdW1iZXI7XG4gICAgbG9kYXNoLmlzT2JqZWN0ID0gaXNPYmplY3Q7XG4gICAgbG9kYXNoLmlzUGxhaW5PYmplY3QgPSBpc1BsYWluT2JqZWN0O1xuICAgIGxvZGFzaC5pc1JlZ0V4cCA9IGlzUmVnRXhwO1xuICAgIGxvZGFzaC5pc1N0cmluZyA9IGlzU3RyaW5nO1xuICAgIGxvZGFzaC5pc1VuZGVmaW5lZCA9IGlzVW5kZWZpbmVkO1xuICAgIGxvZGFzaC5sYXN0SW5kZXhPZiA9IGxhc3RJbmRleE9mO1xuICAgIGxvZGFzaC5taXhpbiA9IG1peGluO1xuICAgIGxvZGFzaC5ub0NvbmZsaWN0ID0gbm9Db25mbGljdDtcbiAgICBsb2Rhc2gucGFyc2VJbnQgPSBwYXJzZUludDtcbiAgICBsb2Rhc2gucmFuZG9tID0gcmFuZG9tO1xuICAgIGxvZGFzaC5yZWR1Y2UgPSByZWR1Y2U7XG4gICAgbG9kYXNoLnJlZHVjZVJpZ2h0ID0gcmVkdWNlUmlnaHQ7XG4gICAgbG9kYXNoLnJlc3VsdCA9IHJlc3VsdDtcbiAgICBsb2Rhc2gucnVuSW5Db250ZXh0ID0gcnVuSW5Db250ZXh0O1xuICAgIGxvZGFzaC5zaXplID0gc2l6ZTtcbiAgICBsb2Rhc2guc29tZSA9IHNvbWU7XG4gICAgbG9kYXNoLnNvcnRlZEluZGV4ID0gc29ydGVkSW5kZXg7XG4gICAgbG9kYXNoLnRlbXBsYXRlID0gdGVtcGxhdGU7XG4gICAgbG9kYXNoLnVuZXNjYXBlID0gdW5lc2NhcGU7XG4gICAgbG9kYXNoLnVuaXF1ZUlkID0gdW5pcXVlSWQ7XG5cbiAgICAvLyBhZGQgYWxpYXNlc1xuICAgIGxvZGFzaC5hbGwgPSBldmVyeTtcbiAgICBsb2Rhc2guYW55ID0gc29tZTtcbiAgICBsb2Rhc2guZGV0ZWN0ID0gZmluZDtcbiAgICBsb2Rhc2guZmluZFdoZXJlID0gZmluZDtcbiAgICBsb2Rhc2guZm9sZGwgPSByZWR1Y2U7XG4gICAgbG9kYXNoLmZvbGRyID0gcmVkdWNlUmlnaHQ7XG4gICAgbG9kYXNoLmluY2x1ZGUgPSBjb250YWlucztcbiAgICBsb2Rhc2guaW5qZWN0ID0gcmVkdWNlO1xuXG4gICAgZm9yT3duKGxvZGFzaCwgZnVuY3Rpb24oZnVuYywgbWV0aG9kTmFtZSkge1xuICAgICAgaWYgKCFsb2Rhc2gucHJvdG90eXBlW21ldGhvZE5hbWVdKSB7XG4gICAgICAgIGxvZGFzaC5wcm90b3R5cGVbbWV0aG9kTmFtZV0gPSBmdW5jdGlvbigpIHtcbiAgICAgICAgICB2YXIgYXJncyA9IFt0aGlzLl9fd3JhcHBlZF9fXTtcbiAgICAgICAgICBwdXNoLmFwcGx5KGFyZ3MsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgcmV0dXJuIGZ1bmMuYXBwbHkobG9kYXNoLCBhcmdzKTtcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIC8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuXG4gICAgLy8gYWRkIGZ1bmN0aW9ucyBjYXBhYmxlIG9mIHJldHVybmluZyB3cmFwcGVkIGFuZCB1bndyYXBwZWQgdmFsdWVzIHdoZW4gY2hhaW5pbmdcbiAgICBsb2Rhc2guZmlyc3QgPSBmaXJzdDtcbiAgICBsb2Rhc2gubGFzdCA9IGxhc3Q7XG5cbiAgICAvLyBhZGQgYWxpYXNlc1xuICAgIGxvZGFzaC50YWtlID0gZmlyc3Q7XG4gICAgbG9kYXNoLmhlYWQgPSBmaXJzdDtcblxuICAgIGZvck93bihsb2Rhc2gsIGZ1bmN0aW9uKGZ1bmMsIG1ldGhvZE5hbWUpIHtcbiAgICAgIGlmICghbG9kYXNoLnByb3RvdHlwZVttZXRob2ROYW1lXSkge1xuICAgICAgICBsb2Rhc2gucHJvdG90eXBlW21ldGhvZE5hbWVdPSBmdW5jdGlvbihjYWxsYmFjaywgdGhpc0FyZykge1xuICAgICAgICAgIHZhciByZXN1bHQgPSBmdW5jKHRoaXMuX193cmFwcGVkX18sIGNhbGxiYWNrLCB0aGlzQXJnKTtcbiAgICAgICAgICByZXR1cm4gY2FsbGJhY2sgPT0gbnVsbCB8fCAodGhpc0FyZyAmJiB0eXBlb2YgY2FsbGJhY2sgIT0gJ2Z1bmN0aW9uJylcbiAgICAgICAgICAgID8gcmVzdWx0XG4gICAgICAgICAgICA6IG5ldyBsb2Rhc2hXcmFwcGVyKHJlc3VsdCk7XG4gICAgICAgIH07XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICAvKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cblxuICAgIC8qKlxuICAgICAqIFRoZSBzZW1hbnRpYyB2ZXJzaW9uIG51bWJlci5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAbWVtYmVyT2YgX1xuICAgICAqIEB0eXBlIFN0cmluZ1xuICAgICAqL1xuICAgIGxvZGFzaC5WRVJTSU9OID0gJzEuMy4xJztcblxuICAgIC8vIGFkZCBcIkNoYWluaW5nXCIgZnVuY3Rpb25zIHRvIHRoZSB3cmFwcGVyXG4gICAgbG9kYXNoLnByb3RvdHlwZS50b1N0cmluZyA9IHdyYXBwZXJUb1N0cmluZztcbiAgICBsb2Rhc2gucHJvdG90eXBlLnZhbHVlID0gd3JhcHBlclZhbHVlT2Y7XG4gICAgbG9kYXNoLnByb3RvdHlwZS52YWx1ZU9mID0gd3JhcHBlclZhbHVlT2Y7XG5cbiAgICAvLyBhZGQgYEFycmF5YCBmdW5jdGlvbnMgdGhhdCByZXR1cm4gdW53cmFwcGVkIHZhbHVlc1xuICAgIGZvckVhY2goWydqb2luJywgJ3BvcCcsICdzaGlmdCddLCBmdW5jdGlvbihtZXRob2ROYW1lKSB7XG4gICAgICB2YXIgZnVuYyA9IGFycmF5UmVmW21ldGhvZE5hbWVdO1xuICAgICAgbG9kYXNoLnByb3RvdHlwZVttZXRob2ROYW1lXSA9IGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gZnVuYy5hcHBseSh0aGlzLl9fd3JhcHBlZF9fLCBhcmd1bWVudHMpO1xuICAgICAgfTtcbiAgICB9KTtcblxuICAgIC8vIGFkZCBgQXJyYXlgIGZ1bmN0aW9ucyB0aGF0IHJldHVybiB0aGUgd3JhcHBlZCB2YWx1ZVxuICAgIGZvckVhY2goWydwdXNoJywgJ3JldmVyc2UnLCAnc29ydCcsICd1bnNoaWZ0J10sIGZ1bmN0aW9uKG1ldGhvZE5hbWUpIHtcbiAgICAgIHZhciBmdW5jID0gYXJyYXlSZWZbbWV0aG9kTmFtZV07XG4gICAgICBsb2Rhc2gucHJvdG90eXBlW21ldGhvZE5hbWVdID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIGZ1bmMuYXBwbHkodGhpcy5fX3dyYXBwZWRfXywgYXJndW1lbnRzKTtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICB9O1xuICAgIH0pO1xuXG4gICAgLy8gYWRkIGBBcnJheWAgZnVuY3Rpb25zIHRoYXQgcmV0dXJuIG5ldyB3cmFwcGVkIHZhbHVlc1xuICAgIGZvckVhY2goWydjb25jYXQnLCAnc2xpY2UnLCAnc3BsaWNlJ10sIGZ1bmN0aW9uKG1ldGhvZE5hbWUpIHtcbiAgICAgIHZhciBmdW5jID0gYXJyYXlSZWZbbWV0aG9kTmFtZV07XG4gICAgICBsb2Rhc2gucHJvdG90eXBlW21ldGhvZE5hbWVdID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiBuZXcgbG9kYXNoV3JhcHBlcihmdW5jLmFwcGx5KHRoaXMuX193cmFwcGVkX18sIGFyZ3VtZW50cykpO1xuICAgICAgfTtcbiAgICB9KTtcblxuICAgIHJldHVybiBsb2Rhc2g7XG4gIH1cblxuICAvKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cblxuICAvLyBleHBvc2UgTG8tRGFzaFxuICB2YXIgXyA9IHJ1bkluQ29udGV4dCgpO1xuXG4gIC8vIHNvbWUgQU1EIGJ1aWxkIG9wdGltaXplcnMsIGxpa2Ugci5qcywgY2hlY2sgZm9yIHNwZWNpZmljIGNvbmRpdGlvbiBwYXR0ZXJucyBsaWtlIHRoZSBmb2xsb3dpbmc6XG4gIGlmICh0eXBlb2YgZGVmaW5lID09ICdmdW5jdGlvbicgJiYgdHlwZW9mIGRlZmluZS5hbWQgPT0gJ29iamVjdCcgJiYgZGVmaW5lLmFtZCkge1xuICAgIC8vIEV4cG9zZSBMby1EYXNoIHRvIHRoZSBnbG9iYWwgb2JqZWN0IGV2ZW4gd2hlbiBhbiBBTUQgbG9hZGVyIGlzIHByZXNlbnQgaW5cbiAgICAvLyBjYXNlIExvLURhc2ggd2FzIGluamVjdGVkIGJ5IGEgdGhpcmQtcGFydHkgc2NyaXB0IGFuZCBub3QgaW50ZW5kZWQgdG8gYmVcbiAgICAvLyBsb2FkZWQgYXMgYSBtb2R1bGUuIFRoZSBnbG9iYWwgYXNzaWdubWVudCBjYW4gYmUgcmV2ZXJ0ZWQgaW4gdGhlIExvLURhc2hcbiAgICAvLyBtb2R1bGUgdmlhIGl0cyBgbm9Db25mbGljdCgpYCBtZXRob2QuXG4gICAgd2luZG93Ll8gPSBfO1xuXG4gICAgLy8gZGVmaW5lIGFzIGFuIGFub255bW91cyBtb2R1bGUgc28sIHRocm91Z2ggcGF0aCBtYXBwaW5nLCBpdCBjYW4gYmVcbiAgICAvLyByZWZlcmVuY2VkIGFzIHRoZSBcInVuZGVyc2NvcmVcIiBtb2R1bGVcbiAgICBkZWZpbmUoZnVuY3Rpb24oKSB7XG4gICAgICByZXR1cm4gXztcbiAgICB9KTtcbiAgfVxuICAvLyBjaGVjayBmb3IgYGV4cG9ydHNgIGFmdGVyIGBkZWZpbmVgIGluIGNhc2UgYSBidWlsZCBvcHRpbWl6ZXIgYWRkcyBhbiBgZXhwb3J0c2Agb2JqZWN0XG4gIGVsc2UgaWYgKGZyZWVFeHBvcnRzICYmICFmcmVlRXhwb3J0cy5ub2RlVHlwZSkge1xuICAgIC8vIGluIE5vZGUuanMgb3IgUmluZ29KUyB2MC44LjArXG4gICAgaWYgKGZyZWVNb2R1bGUpIHtcbiAgICAgIChmcmVlTW9kdWxlLmV4cG9ydHMgPSBfKS5fID0gXztcbiAgICB9XG4gICAgLy8gaW4gTmFyd2hhbCBvciBSaW5nb0pTIHYwLjcuMC1cbiAgICBlbHNlIHtcbiAgICAgIGZyZWVFeHBvcnRzLl8gPSBfO1xuICAgIH1cbiAgfVxuICBlbHNlIHtcbiAgICAvLyBpbiBhIGJyb3dzZXIgb3IgUmhpbm9cbiAgICB3aW5kb3cuXyA9IF87XG4gIH1cbn0odGhpcykpO1xuIiwiLy8gbW9tZW50LmpzXG4vLyB2ZXJzaW9uIDogMi4xLjBcbi8vIGF1dGhvciA6IFRpbSBXb29kXG4vLyBsaWNlbnNlIDogTUlUXG4vLyBtb21lbnRqcy5jb21cblxuKGZ1bmN0aW9uICh1bmRlZmluZWQpIHtcblxuICAgIC8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcbiAgICAgICAgQ29uc3RhbnRzXG4gICAgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4gICAgdmFyIG1vbWVudCxcbiAgICAgICAgVkVSU0lPTiA9IFwiMi4xLjBcIixcbiAgICAgICAgcm91bmQgPSBNYXRoLnJvdW5kLCBpLFxuICAgICAgICAvLyBpbnRlcm5hbCBzdG9yYWdlIGZvciBsYW5ndWFnZSBjb25maWcgZmlsZXNcbiAgICAgICAgbGFuZ3VhZ2VzID0ge30sXG5cbiAgICAgICAgLy8gY2hlY2sgZm9yIG5vZGVKU1xuICAgICAgICBoYXNNb2R1bGUgPSAodHlwZW9mIG1vZHVsZSAhPT0gJ3VuZGVmaW5lZCcgJiYgbW9kdWxlLmV4cG9ydHMpLFxuXG4gICAgICAgIC8vIEFTUC5ORVQganNvbiBkYXRlIGZvcm1hdCByZWdleFxuICAgICAgICBhc3BOZXRKc29uUmVnZXggPSAvXlxcLz9EYXRlXFwoKFxcLT9cXGQrKS9pLFxuICAgICAgICBhc3BOZXRUaW1lU3Bhbkpzb25SZWdleCA9IC8oXFwtKT8oXFxkKik/XFwuPyhcXGQrKVxcOihcXGQrKVxcOihcXGQrKVxcLj8oXFxkezN9KT8vLFxuXG4gICAgICAgIC8vIGZvcm1hdCB0b2tlbnNcbiAgICAgICAgZm9ybWF0dGluZ1Rva2VucyA9IC8oXFxbW15cXFtdKlxcXSl8KFxcXFwpPyhNb3xNTT9NP00/fERvfERERG98REQ/RD9EP3xkZGQ/ZD98ZG8/fHdbb3x3XT98V1tvfFddP3xZWVlZWXxZWVlZfFlZfGdnKGdnZz8pP3xHRyhHR0c/KT98ZXxFfGF8QXxoaD98SEg/fG1tP3xzcz98U1M/Uz98WHx6ej98Wlo/fC4pL2csXG4gICAgICAgIGxvY2FsRm9ybWF0dGluZ1Rva2VucyA9IC8oXFxbW15cXFtdKlxcXSl8KFxcXFwpPyhMVHxMTD9MP0w/fGx7MSw0fSkvZyxcblxuICAgICAgICAvLyBwYXJzaW5nIHRva2VuIHJlZ2V4ZXNcbiAgICAgICAgcGFyc2VUb2tlbk9uZU9yVHdvRGlnaXRzID0gL1xcZFxcZD8vLCAvLyAwIC0gOTlcbiAgICAgICAgcGFyc2VUb2tlbk9uZVRvVGhyZWVEaWdpdHMgPSAvXFxkezEsM30vLCAvLyAwIC0gOTk5XG4gICAgICAgIHBhcnNlVG9rZW5UaHJlZURpZ2l0cyA9IC9cXGR7M30vLCAvLyAwMDAgLSA5OTlcbiAgICAgICAgcGFyc2VUb2tlbkZvdXJEaWdpdHMgPSAvXFxkezEsNH0vLCAvLyAwIC0gOTk5OVxuICAgICAgICBwYXJzZVRva2VuU2l4RGlnaXRzID0gL1srXFwtXT9cXGR7MSw2fS8sIC8vIC05OTksOTk5IC0gOTk5LDk5OVxuICAgICAgICBwYXJzZVRva2VuV29yZCA9IC9bMC05XSpbJ2EtelxcdTAwQTAtXFx1MDVGRlxcdTA3MDAtXFx1RDdGRlxcdUY5MDAtXFx1RkRDRlxcdUZERjAtXFx1RkZFRl0rfFtcXHUwNjAwLVxcdTA2RkZcXC9dKyhcXHMqP1tcXHUwNjAwLVxcdTA2RkZdKyl7MSwyfS9pLCAvLyBhbnkgd29yZCAob3IgdHdvKSBjaGFyYWN0ZXJzIG9yIG51bWJlcnMgaW5jbHVkaW5nIHR3by90aHJlZSB3b3JkIG1vbnRoIGluIGFyYWJpYy5cbiAgICAgICAgcGFyc2VUb2tlblRpbWV6b25lID0gL1p8W1xcK1xcLV1cXGRcXGQ6P1xcZFxcZC9pLCAvLyArMDA6MDAgLTAwOjAwICswMDAwIC0wMDAwIG9yIFpcbiAgICAgICAgcGFyc2VUb2tlblQgPSAvVC9pLCAvLyBUIChJU08gc2VwZXJhdG9yKVxuICAgICAgICBwYXJzZVRva2VuVGltZXN0YW1wTXMgPSAvW1xcK1xcLV0/XFxkKyhcXC5cXGR7MSwzfSk/LywgLy8gMTIzNDU2Nzg5IDEyMzQ1Njc4OS4xMjNcblxuICAgICAgICAvLyBwcmVsaW1pbmFyeSBpc28gcmVnZXhcbiAgICAgICAgLy8gMDAwMC0wMC0wMCArIFQgKyAwMCBvciAwMDowMCBvciAwMDowMDowMCBvciAwMDowMDowMC4wMDAgKyArMDA6MDAgb3IgKzAwMDBcbiAgICAgICAgaXNvUmVnZXggPSAvXlxccypcXGR7NH0tXFxkXFxkLVxcZFxcZCgoVHwgKShcXGRcXGQoOlxcZFxcZCg6XFxkXFxkKFxcLlxcZFxcZD9cXGQ/KT8pPyk/KT8oW1xcK1xcLV1cXGRcXGQ6P1xcZFxcZCk/KT8vLFxuICAgICAgICBpc29Gb3JtYXQgPSAnWVlZWS1NTS1ERFRISDptbTpzc1onLFxuXG4gICAgICAgIC8vIGlzbyB0aW1lIGZvcm1hdHMgYW5kIHJlZ2V4ZXNcbiAgICAgICAgaXNvVGltZXMgPSBbXG4gICAgICAgICAgICBbJ0hIOm1tOnNzLlMnLCAvKFR8IClcXGRcXGQ6XFxkXFxkOlxcZFxcZFxcLlxcZHsxLDN9L10sXG4gICAgICAgICAgICBbJ0hIOm1tOnNzJywgLyhUfCApXFxkXFxkOlxcZFxcZDpcXGRcXGQvXSxcbiAgICAgICAgICAgIFsnSEg6bW0nLCAvKFR8IClcXGRcXGQ6XFxkXFxkL10sXG4gICAgICAgICAgICBbJ0hIJywgLyhUfCApXFxkXFxkL11cbiAgICAgICAgXSxcblxuICAgICAgICAvLyB0aW1lem9uZSBjaHVua2VyIFwiKzEwOjAwXCIgPiBbXCIxMFwiLCBcIjAwXCJdIG9yIFwiLTE1MzBcIiA+IFtcIi0xNVwiLCBcIjMwXCJdXG4gICAgICAgIHBhcnNlVGltZXpvbmVDaHVua2VyID0gLyhbXFwrXFwtXXxcXGRcXGQpL2dpLFxuXG4gICAgICAgIC8vIGdldHRlciBhbmQgc2V0dGVyIG5hbWVzXG4gICAgICAgIHByb3h5R2V0dGVyc0FuZFNldHRlcnMgPSAnRGF0ZXxIb3Vyc3xNaW51dGVzfFNlY29uZHN8TWlsbGlzZWNvbmRzJy5zcGxpdCgnfCcpLFxuICAgICAgICB1bml0TWlsbGlzZWNvbmRGYWN0b3JzID0ge1xuICAgICAgICAgICAgJ01pbGxpc2Vjb25kcycgOiAxLFxuICAgICAgICAgICAgJ1NlY29uZHMnIDogMWUzLFxuICAgICAgICAgICAgJ01pbnV0ZXMnIDogNmU0LFxuICAgICAgICAgICAgJ0hvdXJzJyA6IDM2ZTUsXG4gICAgICAgICAgICAnRGF5cycgOiA4NjRlNSxcbiAgICAgICAgICAgICdNb250aHMnIDogMjU5MmU2LFxuICAgICAgICAgICAgJ1llYXJzJyA6IDMxNTM2ZTZcbiAgICAgICAgfSxcblxuICAgICAgICB1bml0QWxpYXNlcyA9IHtcbiAgICAgICAgICAgIG1zIDogJ21pbGxpc2Vjb25kJyxcbiAgICAgICAgICAgIHMgOiAnc2Vjb25kJyxcbiAgICAgICAgICAgIG0gOiAnbWludXRlJyxcbiAgICAgICAgICAgIGggOiAnaG91cicsXG4gICAgICAgICAgICBkIDogJ2RheScsXG4gICAgICAgICAgICB3IDogJ3dlZWsnLFxuICAgICAgICAgICAgTSA6ICdtb250aCcsXG4gICAgICAgICAgICB5IDogJ3llYXInXG4gICAgICAgIH0sXG5cbiAgICAgICAgLy8gZm9ybWF0IGZ1bmN0aW9uIHN0cmluZ3NcbiAgICAgICAgZm9ybWF0RnVuY3Rpb25zID0ge30sXG5cbiAgICAgICAgLy8gdG9rZW5zIHRvIG9yZGluYWxpemUgYW5kIHBhZFxuICAgICAgICBvcmRpbmFsaXplVG9rZW5zID0gJ0RERCB3IFcgTSBEIGQnLnNwbGl0KCcgJyksXG4gICAgICAgIHBhZGRlZFRva2VucyA9ICdNIEQgSCBoIG0gcyB3IFcnLnNwbGl0KCcgJyksXG5cbiAgICAgICAgZm9ybWF0VG9rZW5GdW5jdGlvbnMgPSB7XG4gICAgICAgICAgICBNICAgIDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLm1vbnRoKCkgKyAxO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIE1NTSAgOiBmdW5jdGlvbiAoZm9ybWF0KSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMubGFuZygpLm1vbnRoc1Nob3J0KHRoaXMsIGZvcm1hdCk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgTU1NTSA6IGZ1bmN0aW9uIChmb3JtYXQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5sYW5nKCkubW9udGhzKHRoaXMsIGZvcm1hdCk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgRCAgICA6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5kYXRlKCk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgREREICA6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5kYXlPZlllYXIoKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBkICAgIDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmRheSgpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGRkICAgOiBmdW5jdGlvbiAoZm9ybWF0KSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMubGFuZygpLndlZWtkYXlzTWluKHRoaXMsIGZvcm1hdCk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgZGRkICA6IGZ1bmN0aW9uIChmb3JtYXQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5sYW5nKCkud2Vla2RheXNTaG9ydCh0aGlzLCBmb3JtYXQpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGRkZGQgOiBmdW5jdGlvbiAoZm9ybWF0KSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMubGFuZygpLndlZWtkYXlzKHRoaXMsIGZvcm1hdCk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgdyAgICA6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy53ZWVrKCk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgVyAgICA6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5pc29XZWVrKCk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgWVkgICA6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gbGVmdFplcm9GaWxsKHRoaXMueWVhcigpICUgMTAwLCAyKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBZWVlZIDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBsZWZ0WmVyb0ZpbGwodGhpcy55ZWFyKCksIDQpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFlZWVlZIDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBsZWZ0WmVyb0ZpbGwodGhpcy55ZWFyKCksIDUpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGdnICAgOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGxlZnRaZXJvRmlsbCh0aGlzLndlZWtZZWFyKCkgJSAxMDAsIDIpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGdnZ2cgOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMud2Vla1llYXIoKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBnZ2dnZyA6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gbGVmdFplcm9GaWxsKHRoaXMud2Vla1llYXIoKSwgNSk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgR0cgICA6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gbGVmdFplcm9GaWxsKHRoaXMuaXNvV2Vla1llYXIoKSAlIDEwMCwgMik7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgR0dHRyA6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5pc29XZWVrWWVhcigpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIEdHR0dHIDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBsZWZ0WmVyb0ZpbGwodGhpcy5pc29XZWVrWWVhcigpLCA1KTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBlIDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLndlZWtkYXkoKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBFIDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmlzb1dlZWtkYXkoKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBhICAgIDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmxhbmcoKS5tZXJpZGllbSh0aGlzLmhvdXJzKCksIHRoaXMubWludXRlcygpLCB0cnVlKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBBICAgIDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmxhbmcoKS5tZXJpZGllbSh0aGlzLmhvdXJzKCksIHRoaXMubWludXRlcygpLCBmYWxzZSk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgSCAgICA6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5ob3VycygpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGggICAgOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuaG91cnMoKSAlIDEyIHx8IDEyO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIG0gICAgOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMubWludXRlcygpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHMgICAgOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuc2Vjb25kcygpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFMgICAgOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIH5+KHRoaXMubWlsbGlzZWNvbmRzKCkgLyAxMDApO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFNTICAgOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGxlZnRaZXJvRmlsbCh+fih0aGlzLm1pbGxpc2Vjb25kcygpIC8gMTApLCAyKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBTU1MgIDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBsZWZ0WmVyb0ZpbGwodGhpcy5taWxsaXNlY29uZHMoKSwgMyk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgWiAgICA6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB2YXIgYSA9IC10aGlzLnpvbmUoKSxcbiAgICAgICAgICAgICAgICAgICAgYiA9IFwiK1wiO1xuICAgICAgICAgICAgICAgIGlmIChhIDwgMCkge1xuICAgICAgICAgICAgICAgICAgICBhID0gLWE7XG4gICAgICAgICAgICAgICAgICAgIGIgPSBcIi1cIjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIGIgKyBsZWZ0WmVyb0ZpbGwofn4oYSAvIDYwKSwgMikgKyBcIjpcIiArIGxlZnRaZXJvRmlsbCh+fmEgJSA2MCwgMik7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgWlogICA6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB2YXIgYSA9IC10aGlzLnpvbmUoKSxcbiAgICAgICAgICAgICAgICAgICAgYiA9IFwiK1wiO1xuICAgICAgICAgICAgICAgIGlmIChhIDwgMCkge1xuICAgICAgICAgICAgICAgICAgICBhID0gLWE7XG4gICAgICAgICAgICAgICAgICAgIGIgPSBcIi1cIjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIGIgKyBsZWZ0WmVyb0ZpbGwofn4oMTAgKiBhIC8gNiksIDQpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHogOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuem9uZUFiYnIoKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB6eiA6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy56b25lTmFtZSgpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFggICAgOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMudW5peCgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuXG4gICAgZnVuY3Rpb24gcGFkVG9rZW4oZnVuYywgY291bnQpIHtcbiAgICAgICAgcmV0dXJuIGZ1bmN0aW9uIChhKSB7XG4gICAgICAgICAgICByZXR1cm4gbGVmdFplcm9GaWxsKGZ1bmMuY2FsbCh0aGlzLCBhKSwgY291bnQpO1xuICAgICAgICB9O1xuICAgIH1cbiAgICBmdW5jdGlvbiBvcmRpbmFsaXplVG9rZW4oZnVuYywgcGVyaW9kKSB7XG4gICAgICAgIHJldHVybiBmdW5jdGlvbiAoYSkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMubGFuZygpLm9yZGluYWwoZnVuYy5jYWxsKHRoaXMsIGEpLCBwZXJpb2QpO1xuICAgICAgICB9O1xuICAgIH1cblxuICAgIHdoaWxlIChvcmRpbmFsaXplVG9rZW5zLmxlbmd0aCkge1xuICAgICAgICBpID0gb3JkaW5hbGl6ZVRva2Vucy5wb3AoKTtcbiAgICAgICAgZm9ybWF0VG9rZW5GdW5jdGlvbnNbaSArICdvJ10gPSBvcmRpbmFsaXplVG9rZW4oZm9ybWF0VG9rZW5GdW5jdGlvbnNbaV0sIGkpO1xuICAgIH1cbiAgICB3aGlsZSAocGFkZGVkVG9rZW5zLmxlbmd0aCkge1xuICAgICAgICBpID0gcGFkZGVkVG9rZW5zLnBvcCgpO1xuICAgICAgICBmb3JtYXRUb2tlbkZ1bmN0aW9uc1tpICsgaV0gPSBwYWRUb2tlbihmb3JtYXRUb2tlbkZ1bmN0aW9uc1tpXSwgMik7XG4gICAgfVxuICAgIGZvcm1hdFRva2VuRnVuY3Rpb25zLkREREQgPSBwYWRUb2tlbihmb3JtYXRUb2tlbkZ1bmN0aW9ucy5EREQsIDMpO1xuXG5cbiAgICAvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG4gICAgICAgIENvbnN0cnVjdG9yc1xuICAgICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuICAgIGZ1bmN0aW9uIExhbmd1YWdlKCkge1xuXG4gICAgfVxuXG4gICAgLy8gTW9tZW50IHByb3RvdHlwZSBvYmplY3RcbiAgICBmdW5jdGlvbiBNb21lbnQoY29uZmlnKSB7XG4gICAgICAgIGV4dGVuZCh0aGlzLCBjb25maWcpO1xuICAgIH1cblxuICAgIC8vIER1cmF0aW9uIENvbnN0cnVjdG9yXG4gICAgZnVuY3Rpb24gRHVyYXRpb24oZHVyYXRpb24pIHtcbiAgICAgICAgdmFyIHllYXJzID0gZHVyYXRpb24ueWVhcnMgfHwgZHVyYXRpb24ueWVhciB8fCBkdXJhdGlvbi55IHx8IDAsXG4gICAgICAgICAgICBtb250aHMgPSBkdXJhdGlvbi5tb250aHMgfHwgZHVyYXRpb24ubW9udGggfHwgZHVyYXRpb24uTSB8fCAwLFxuICAgICAgICAgICAgd2Vla3MgPSBkdXJhdGlvbi53ZWVrcyB8fCBkdXJhdGlvbi53ZWVrIHx8IGR1cmF0aW9uLncgfHwgMCxcbiAgICAgICAgICAgIGRheXMgPSBkdXJhdGlvbi5kYXlzIHx8IGR1cmF0aW9uLmRheSB8fCBkdXJhdGlvbi5kIHx8IDAsXG4gICAgICAgICAgICBob3VycyA9IGR1cmF0aW9uLmhvdXJzIHx8IGR1cmF0aW9uLmhvdXIgfHwgZHVyYXRpb24uaCB8fCAwLFxuICAgICAgICAgICAgbWludXRlcyA9IGR1cmF0aW9uLm1pbnV0ZXMgfHwgZHVyYXRpb24ubWludXRlIHx8IGR1cmF0aW9uLm0gfHwgMCxcbiAgICAgICAgICAgIHNlY29uZHMgPSBkdXJhdGlvbi5zZWNvbmRzIHx8IGR1cmF0aW9uLnNlY29uZCB8fCBkdXJhdGlvbi5zIHx8IDAsXG4gICAgICAgICAgICBtaWxsaXNlY29uZHMgPSBkdXJhdGlvbi5taWxsaXNlY29uZHMgfHwgZHVyYXRpb24ubWlsbGlzZWNvbmQgfHwgZHVyYXRpb24ubXMgfHwgMDtcblxuICAgICAgICAvLyBzdG9yZSByZWZlcmVuY2UgdG8gaW5wdXQgZm9yIGRldGVybWluaXN0aWMgY2xvbmluZ1xuICAgICAgICB0aGlzLl9pbnB1dCA9IGR1cmF0aW9uO1xuXG4gICAgICAgIC8vIHJlcHJlc2VudGF0aW9uIGZvciBkYXRlQWRkUmVtb3ZlXG4gICAgICAgIHRoaXMuX21pbGxpc2Vjb25kcyA9IG1pbGxpc2Vjb25kcyArXG4gICAgICAgICAgICBzZWNvbmRzICogMWUzICsgLy8gMTAwMFxuICAgICAgICAgICAgbWludXRlcyAqIDZlNCArIC8vIDEwMDAgKiA2MFxuICAgICAgICAgICAgaG91cnMgKiAzNmU1OyAvLyAxMDAwICogNjAgKiA2MFxuICAgICAgICAvLyBCZWNhdXNlIG9mIGRhdGVBZGRSZW1vdmUgdHJlYXRzIDI0IGhvdXJzIGFzIGRpZmZlcmVudCBmcm9tIGFcbiAgICAgICAgLy8gZGF5IHdoZW4gd29ya2luZyBhcm91bmQgRFNULCB3ZSBuZWVkIHRvIHN0b3JlIHRoZW0gc2VwYXJhdGVseVxuICAgICAgICB0aGlzLl9kYXlzID0gZGF5cyArXG4gICAgICAgICAgICB3ZWVrcyAqIDc7XG4gICAgICAgIC8vIEl0IGlzIGltcG9zc2libGUgdHJhbnNsYXRlIG1vbnRocyBpbnRvIGRheXMgd2l0aG91dCBrbm93aW5nXG4gICAgICAgIC8vIHdoaWNoIG1vbnRocyB5b3UgYXJlIGFyZSB0YWxraW5nIGFib3V0LCBzbyB3ZSBoYXZlIHRvIHN0b3JlXG4gICAgICAgIC8vIGl0IHNlcGFyYXRlbHkuXG4gICAgICAgIHRoaXMuX21vbnRocyA9IG1vbnRocyArXG4gICAgICAgICAgICB5ZWFycyAqIDEyO1xuXG4gICAgICAgIHRoaXMuX2RhdGEgPSB7fTtcblxuICAgICAgICB0aGlzLl9idWJibGUoKTtcbiAgICB9XG5cblxuICAgIC8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcbiAgICAgICAgSGVscGVyc1xuICAgICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuXG4gICAgZnVuY3Rpb24gZXh0ZW5kKGEsIGIpIHtcbiAgICAgICAgZm9yICh2YXIgaSBpbiBiKSB7XG4gICAgICAgICAgICBpZiAoYi5oYXNPd25Qcm9wZXJ0eShpKSkge1xuICAgICAgICAgICAgICAgIGFbaV0gPSBiW2ldO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBhO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGFic1JvdW5kKG51bWJlcikge1xuICAgICAgICBpZiAobnVtYmVyIDwgMCkge1xuICAgICAgICAgICAgcmV0dXJuIE1hdGguY2VpbChudW1iZXIpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIE1hdGguZmxvb3IobnVtYmVyKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vIGxlZnQgemVybyBmaWxsIGEgbnVtYmVyXG4gICAgLy8gc2VlIGh0dHA6Ly9qc3BlcmYuY29tL2xlZnQtemVyby1maWxsaW5nIGZvciBwZXJmb3JtYW5jZSBjb21wYXJpc29uXG4gICAgZnVuY3Rpb24gbGVmdFplcm9GaWxsKG51bWJlciwgdGFyZ2V0TGVuZ3RoKSB7XG4gICAgICAgIHZhciBvdXRwdXQgPSBudW1iZXIgKyAnJztcbiAgICAgICAgd2hpbGUgKG91dHB1dC5sZW5ndGggPCB0YXJnZXRMZW5ndGgpIHtcbiAgICAgICAgICAgIG91dHB1dCA9ICcwJyArIG91dHB1dDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gb3V0cHV0O1xuICAgIH1cblxuICAgIC8vIGhlbHBlciBmdW5jdGlvbiBmb3IgXy5hZGRUaW1lIGFuZCBfLnN1YnRyYWN0VGltZVxuICAgIGZ1bmN0aW9uIGFkZE9yU3VidHJhY3REdXJhdGlvbkZyb21Nb21lbnQobW9tLCBkdXJhdGlvbiwgaXNBZGRpbmcsIGlnbm9yZVVwZGF0ZU9mZnNldCkge1xuICAgICAgICB2YXIgbWlsbGlzZWNvbmRzID0gZHVyYXRpb24uX21pbGxpc2Vjb25kcyxcbiAgICAgICAgICAgIGRheXMgPSBkdXJhdGlvbi5fZGF5cyxcbiAgICAgICAgICAgIG1vbnRocyA9IGR1cmF0aW9uLl9tb250aHMsXG4gICAgICAgICAgICBtaW51dGVzLFxuICAgICAgICAgICAgaG91cnMsXG4gICAgICAgICAgICBjdXJyZW50RGF0ZTtcblxuICAgICAgICBpZiAobWlsbGlzZWNvbmRzKSB7XG4gICAgICAgICAgICBtb20uX2Quc2V0VGltZSgrbW9tLl9kICsgbWlsbGlzZWNvbmRzICogaXNBZGRpbmcpO1xuICAgICAgICB9XG4gICAgICAgIC8vIHN0b3JlIHRoZSBtaW51dGVzIGFuZCBob3VycyBzbyB3ZSBjYW4gcmVzdG9yZSB0aGVtXG4gICAgICAgIGlmIChkYXlzIHx8IG1vbnRocykge1xuICAgICAgICAgICAgbWludXRlcyA9IG1vbS5taW51dGUoKTtcbiAgICAgICAgICAgIGhvdXJzID0gbW9tLmhvdXIoKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoZGF5cykge1xuICAgICAgICAgICAgbW9tLmRhdGUobW9tLmRhdGUoKSArIGRheXMgKiBpc0FkZGluZyk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG1vbnRocykge1xuICAgICAgICAgICAgbW9tLm1vbnRoKG1vbS5tb250aCgpICsgbW9udGhzICogaXNBZGRpbmcpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChtaWxsaXNlY29uZHMgJiYgIWlnbm9yZVVwZGF0ZU9mZnNldCkge1xuICAgICAgICAgICAgbW9tZW50LnVwZGF0ZU9mZnNldChtb20pO1xuICAgICAgICB9XG4gICAgICAgIC8vIHJlc3RvcmUgdGhlIG1pbnV0ZXMgYW5kIGhvdXJzIGFmdGVyIHBvc3NpYmx5IGNoYW5naW5nIGRzdFxuICAgICAgICBpZiAoZGF5cyB8fCBtb250aHMpIHtcbiAgICAgICAgICAgIG1vbS5taW51dGUobWludXRlcyk7XG4gICAgICAgICAgICBtb20uaG91cihob3Vycyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBjaGVjayBpZiBpcyBhbiBhcnJheVxuICAgIGZ1bmN0aW9uIGlzQXJyYXkoaW5wdXQpIHtcbiAgICAgICAgcmV0dXJuIE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChpbnB1dCkgPT09ICdbb2JqZWN0IEFycmF5XSc7XG4gICAgfVxuXG4gICAgLy8gY29tcGFyZSB0d28gYXJyYXlzLCByZXR1cm4gdGhlIG51bWJlciBvZiBkaWZmZXJlbmNlc1xuICAgIGZ1bmN0aW9uIGNvbXBhcmVBcnJheXMoYXJyYXkxLCBhcnJheTIpIHtcbiAgICAgICAgdmFyIGxlbiA9IE1hdGgubWluKGFycmF5MS5sZW5ndGgsIGFycmF5Mi5sZW5ndGgpLFxuICAgICAgICAgICAgbGVuZ3RoRGlmZiA9IE1hdGguYWJzKGFycmF5MS5sZW5ndGggLSBhcnJheTIubGVuZ3RoKSxcbiAgICAgICAgICAgIGRpZmZzID0gMCxcbiAgICAgICAgICAgIGk7XG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCBsZW47IGkrKykge1xuICAgICAgICAgICAgaWYgKH5+YXJyYXkxW2ldICE9PSB+fmFycmF5MltpXSkge1xuICAgICAgICAgICAgICAgIGRpZmZzKys7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGRpZmZzICsgbGVuZ3RoRGlmZjtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBub3JtYWxpemVVbml0cyh1bml0cykge1xuICAgICAgICByZXR1cm4gdW5pdHMgPyB1bml0QWxpYXNlc1t1bml0c10gfHwgdW5pdHMudG9Mb3dlckNhc2UoKS5yZXBsYWNlKC8oLilzJC8sICckMScpIDogdW5pdHM7XG4gICAgfVxuXG5cbiAgICAvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG4gICAgICAgIExhbmd1YWdlc1xuICAgICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuXG4gICAgTGFuZ3VhZ2UucHJvdG90eXBlID0ge1xuICAgICAgICBzZXQgOiBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgICAgICAgICB2YXIgcHJvcCwgaTtcbiAgICAgICAgICAgIGZvciAoaSBpbiBjb25maWcpIHtcbiAgICAgICAgICAgICAgICBwcm9wID0gY29uZmlnW2ldO1xuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgcHJvcCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgICAgICAgICB0aGlzW2ldID0gcHJvcDtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICB0aGlzWydfJyArIGldID0gcHJvcDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG5cbiAgICAgICAgX21vbnRocyA6IFwiSmFudWFyeV9GZWJydWFyeV9NYXJjaF9BcHJpbF9NYXlfSnVuZV9KdWx5X0F1Z3VzdF9TZXB0ZW1iZXJfT2N0b2Jlcl9Ob3ZlbWJlcl9EZWNlbWJlclwiLnNwbGl0KFwiX1wiKSxcbiAgICAgICAgbW9udGhzIDogZnVuY3Rpb24gKG0pIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9tb250aHNbbS5tb250aCgpXTtcbiAgICAgICAgfSxcblxuICAgICAgICBfbW9udGhzU2hvcnQgOiBcIkphbl9GZWJfTWFyX0Fwcl9NYXlfSnVuX0p1bF9BdWdfU2VwX09jdF9Ob3ZfRGVjXCIuc3BsaXQoXCJfXCIpLFxuICAgICAgICBtb250aHNTaG9ydCA6IGZ1bmN0aW9uIChtKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fbW9udGhzU2hvcnRbbS5tb250aCgpXTtcbiAgICAgICAgfSxcblxuICAgICAgICBtb250aHNQYXJzZSA6IGZ1bmN0aW9uIChtb250aE5hbWUpIHtcbiAgICAgICAgICAgIHZhciBpLCBtb20sIHJlZ2V4O1xuXG4gICAgICAgICAgICBpZiAoIXRoaXMuX21vbnRoc1BhcnNlKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5fbW9udGhzUGFyc2UgPSBbXTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgZm9yIChpID0gMDsgaSA8IDEyOyBpKyspIHtcbiAgICAgICAgICAgICAgICAvLyBtYWtlIHRoZSByZWdleCBpZiB3ZSBkb24ndCBoYXZlIGl0IGFscmVhZHlcbiAgICAgICAgICAgICAgICBpZiAoIXRoaXMuX21vbnRoc1BhcnNlW2ldKSB7XG4gICAgICAgICAgICAgICAgICAgIG1vbSA9IG1vbWVudChbMjAwMCwgaV0pO1xuICAgICAgICAgICAgICAgICAgICByZWdleCA9ICdeJyArIHRoaXMubW9udGhzKG1vbSwgJycpICsgJ3xeJyArIHRoaXMubW9udGhzU2hvcnQobW9tLCAnJyk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX21vbnRoc1BhcnNlW2ldID0gbmV3IFJlZ0V4cChyZWdleC5yZXBsYWNlKCcuJywgJycpLCAnaScpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvLyB0ZXN0IHRoZSByZWdleFxuICAgICAgICAgICAgICAgIGlmICh0aGlzLl9tb250aHNQYXJzZVtpXS50ZXN0KG1vbnRoTmFtZSkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9LFxuXG4gICAgICAgIF93ZWVrZGF5cyA6IFwiU3VuZGF5X01vbmRheV9UdWVzZGF5X1dlZG5lc2RheV9UaHVyc2RheV9GcmlkYXlfU2F0dXJkYXlcIi5zcGxpdChcIl9cIiksXG4gICAgICAgIHdlZWtkYXlzIDogZnVuY3Rpb24gKG0pIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl93ZWVrZGF5c1ttLmRheSgpXTtcbiAgICAgICAgfSxcblxuICAgICAgICBfd2Vla2RheXNTaG9ydCA6IFwiU3VuX01vbl9UdWVfV2VkX1RodV9GcmlfU2F0XCIuc3BsaXQoXCJfXCIpLFxuICAgICAgICB3ZWVrZGF5c1Nob3J0IDogZnVuY3Rpb24gKG0pIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl93ZWVrZGF5c1Nob3J0W20uZGF5KCldO1xuICAgICAgICB9LFxuXG4gICAgICAgIF93ZWVrZGF5c01pbiA6IFwiU3VfTW9fVHVfV2VfVGhfRnJfU2FcIi5zcGxpdChcIl9cIiksXG4gICAgICAgIHdlZWtkYXlzTWluIDogZnVuY3Rpb24gKG0pIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl93ZWVrZGF5c01pblttLmRheSgpXTtcbiAgICAgICAgfSxcblxuICAgICAgICB3ZWVrZGF5c1BhcnNlIDogZnVuY3Rpb24gKHdlZWtkYXlOYW1lKSB7XG4gICAgICAgICAgICB2YXIgaSwgbW9tLCByZWdleDtcblxuICAgICAgICAgICAgaWYgKCF0aGlzLl93ZWVrZGF5c1BhcnNlKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5fd2Vla2RheXNQYXJzZSA9IFtdO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwgNzsgaSsrKSB7XG4gICAgICAgICAgICAgICAgLy8gbWFrZSB0aGUgcmVnZXggaWYgd2UgZG9uJ3QgaGF2ZSBpdCBhbHJlYWR5XG4gICAgICAgICAgICAgICAgaWYgKCF0aGlzLl93ZWVrZGF5c1BhcnNlW2ldKSB7XG4gICAgICAgICAgICAgICAgICAgIG1vbSA9IG1vbWVudChbMjAwMCwgMV0pLmRheShpKTtcbiAgICAgICAgICAgICAgICAgICAgcmVnZXggPSAnXicgKyB0aGlzLndlZWtkYXlzKG1vbSwgJycpICsgJ3xeJyArIHRoaXMud2Vla2RheXNTaG9ydChtb20sICcnKSArICd8XicgKyB0aGlzLndlZWtkYXlzTWluKG1vbSwgJycpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLl93ZWVrZGF5c1BhcnNlW2ldID0gbmV3IFJlZ0V4cChyZWdleC5yZXBsYWNlKCcuJywgJycpLCAnaScpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvLyB0ZXN0IHRoZSByZWdleFxuICAgICAgICAgICAgICAgIGlmICh0aGlzLl93ZWVrZGF5c1BhcnNlW2ldLnRlc3Qod2Vla2RheU5hbWUpKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcblxuICAgICAgICBfbG9uZ0RhdGVGb3JtYXQgOiB7XG4gICAgICAgICAgICBMVCA6IFwiaDptbSBBXCIsXG4gICAgICAgICAgICBMIDogXCJNTS9ERC9ZWVlZXCIsXG4gICAgICAgICAgICBMTCA6IFwiTU1NTSBEIFlZWVlcIixcbiAgICAgICAgICAgIExMTCA6IFwiTU1NTSBEIFlZWVkgTFRcIixcbiAgICAgICAgICAgIExMTEwgOiBcImRkZGQsIE1NTU0gRCBZWVlZIExUXCJcbiAgICAgICAgfSxcbiAgICAgICAgbG9uZ0RhdGVGb3JtYXQgOiBmdW5jdGlvbiAoa2V5KSB7XG4gICAgICAgICAgICB2YXIgb3V0cHV0ID0gdGhpcy5fbG9uZ0RhdGVGb3JtYXRba2V5XTtcbiAgICAgICAgICAgIGlmICghb3V0cHV0ICYmIHRoaXMuX2xvbmdEYXRlRm9ybWF0W2tleS50b1VwcGVyQ2FzZSgpXSkge1xuICAgICAgICAgICAgICAgIG91dHB1dCA9IHRoaXMuX2xvbmdEYXRlRm9ybWF0W2tleS50b1VwcGVyQ2FzZSgpXS5yZXBsYWNlKC9NTU1NfE1NfEREfGRkZGQvZywgZnVuY3Rpb24gKHZhbCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdmFsLnNsaWNlKDEpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHRoaXMuX2xvbmdEYXRlRm9ybWF0W2tleV0gPSBvdXRwdXQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gb3V0cHV0O1xuICAgICAgICB9LFxuXG4gICAgICAgIGlzUE0gOiBmdW5jdGlvbiAoaW5wdXQpIHtcbiAgICAgICAgICAgIHJldHVybiAoKGlucHV0ICsgJycpLnRvTG93ZXJDYXNlKClbMF0gPT09ICdwJyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgX21lcmlkaWVtUGFyc2UgOiAvW2FwXVxcLj9tP1xcLj8vaSxcbiAgICAgICAgbWVyaWRpZW0gOiBmdW5jdGlvbiAoaG91cnMsIG1pbnV0ZXMsIGlzTG93ZXIpIHtcbiAgICAgICAgICAgIGlmIChob3VycyA+IDExKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGlzTG93ZXIgPyAncG0nIDogJ1BNJztcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGlzTG93ZXIgPyAnYW0nIDogJ0FNJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcblxuICAgICAgICBfY2FsZW5kYXIgOiB7XG4gICAgICAgICAgICBzYW1lRGF5IDogJ1tUb2RheSBhdF0gTFQnLFxuICAgICAgICAgICAgbmV4dERheSA6ICdbVG9tb3Jyb3cgYXRdIExUJyxcbiAgICAgICAgICAgIG5leHRXZWVrIDogJ2RkZGQgW2F0XSBMVCcsXG4gICAgICAgICAgICBsYXN0RGF5IDogJ1tZZXN0ZXJkYXkgYXRdIExUJyxcbiAgICAgICAgICAgIGxhc3RXZWVrIDogJ1tMYXN0XSBkZGRkIFthdF0gTFQnLFxuICAgICAgICAgICAgc2FtZUVsc2UgOiAnTCdcbiAgICAgICAgfSxcbiAgICAgICAgY2FsZW5kYXIgOiBmdW5jdGlvbiAoa2V5LCBtb20pIHtcbiAgICAgICAgICAgIHZhciBvdXRwdXQgPSB0aGlzLl9jYWxlbmRhcltrZXldO1xuICAgICAgICAgICAgcmV0dXJuIHR5cGVvZiBvdXRwdXQgPT09ICdmdW5jdGlvbicgPyBvdXRwdXQuYXBwbHkobW9tKSA6IG91dHB1dDtcbiAgICAgICAgfSxcblxuICAgICAgICBfcmVsYXRpdmVUaW1lIDoge1xuICAgICAgICAgICAgZnV0dXJlIDogXCJpbiAlc1wiLFxuICAgICAgICAgICAgcGFzdCA6IFwiJXMgYWdvXCIsXG4gICAgICAgICAgICBzIDogXCJhIGZldyBzZWNvbmRzXCIsXG4gICAgICAgICAgICBtIDogXCJhIG1pbnV0ZVwiLFxuICAgICAgICAgICAgbW0gOiBcIiVkIG1pbnV0ZXNcIixcbiAgICAgICAgICAgIGggOiBcImFuIGhvdXJcIixcbiAgICAgICAgICAgIGhoIDogXCIlZCBob3Vyc1wiLFxuICAgICAgICAgICAgZCA6IFwiYSBkYXlcIixcbiAgICAgICAgICAgIGRkIDogXCIlZCBkYXlzXCIsXG4gICAgICAgICAgICBNIDogXCJhIG1vbnRoXCIsXG4gICAgICAgICAgICBNTSA6IFwiJWQgbW9udGhzXCIsXG4gICAgICAgICAgICB5IDogXCJhIHllYXJcIixcbiAgICAgICAgICAgIHl5IDogXCIlZCB5ZWFyc1wiXG4gICAgICAgIH0sXG4gICAgICAgIHJlbGF0aXZlVGltZSA6IGZ1bmN0aW9uIChudW1iZXIsIHdpdGhvdXRTdWZmaXgsIHN0cmluZywgaXNGdXR1cmUpIHtcbiAgICAgICAgICAgIHZhciBvdXRwdXQgPSB0aGlzLl9yZWxhdGl2ZVRpbWVbc3RyaW5nXTtcbiAgICAgICAgICAgIHJldHVybiAodHlwZW9mIG91dHB1dCA9PT0gJ2Z1bmN0aW9uJykgP1xuICAgICAgICAgICAgICAgIG91dHB1dChudW1iZXIsIHdpdGhvdXRTdWZmaXgsIHN0cmluZywgaXNGdXR1cmUpIDpcbiAgICAgICAgICAgICAgICBvdXRwdXQucmVwbGFjZSgvJWQvaSwgbnVtYmVyKTtcbiAgICAgICAgfSxcbiAgICAgICAgcGFzdEZ1dHVyZSA6IGZ1bmN0aW9uIChkaWZmLCBvdXRwdXQpIHtcbiAgICAgICAgICAgIHZhciBmb3JtYXQgPSB0aGlzLl9yZWxhdGl2ZVRpbWVbZGlmZiA+IDAgPyAnZnV0dXJlJyA6ICdwYXN0J107XG4gICAgICAgICAgICByZXR1cm4gdHlwZW9mIGZvcm1hdCA9PT0gJ2Z1bmN0aW9uJyA/IGZvcm1hdChvdXRwdXQpIDogZm9ybWF0LnJlcGxhY2UoLyVzL2ksIG91dHB1dCk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgb3JkaW5hbCA6IGZ1bmN0aW9uIChudW1iZXIpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9vcmRpbmFsLnJlcGxhY2UoXCIlZFwiLCBudW1iZXIpO1xuICAgICAgICB9LFxuICAgICAgICBfb3JkaW5hbCA6IFwiJWRcIixcblxuICAgICAgICBwcmVwYXJzZSA6IGZ1bmN0aW9uIChzdHJpbmcpIHtcbiAgICAgICAgICAgIHJldHVybiBzdHJpbmc7XG4gICAgICAgIH0sXG5cbiAgICAgICAgcG9zdGZvcm1hdCA6IGZ1bmN0aW9uIChzdHJpbmcpIHtcbiAgICAgICAgICAgIHJldHVybiBzdHJpbmc7XG4gICAgICAgIH0sXG5cbiAgICAgICAgd2VlayA6IGZ1bmN0aW9uIChtb20pIHtcbiAgICAgICAgICAgIHJldHVybiB3ZWVrT2ZZZWFyKG1vbSwgdGhpcy5fd2Vlay5kb3csIHRoaXMuX3dlZWsuZG95KS53ZWVrO1xuICAgICAgICB9LFxuICAgICAgICBfd2VlayA6IHtcbiAgICAgICAgICAgIGRvdyA6IDAsIC8vIFN1bmRheSBpcyB0aGUgZmlyc3QgZGF5IG9mIHRoZSB3ZWVrLlxuICAgICAgICAgICAgZG95IDogNiAgLy8gVGhlIHdlZWsgdGhhdCBjb250YWlucyBKYW4gMXN0IGlzIHRoZSBmaXJzdCB3ZWVrIG9mIHRoZSB5ZWFyLlxuICAgICAgICB9XG4gICAgfTtcblxuICAgIC8vIExvYWRzIGEgbGFuZ3VhZ2UgZGVmaW5pdGlvbiBpbnRvIHRoZSBgbGFuZ3VhZ2VzYCBjYWNoZS4gIFRoZSBmdW5jdGlvblxuICAgIC8vIHRha2VzIGEga2V5IGFuZCBvcHRpb25hbGx5IHZhbHVlcy4gIElmIG5vdCBpbiB0aGUgYnJvd3NlciBhbmQgbm8gdmFsdWVzXG4gICAgLy8gYXJlIHByb3ZpZGVkLCBpdCB3aWxsIGxvYWQgdGhlIGxhbmd1YWdlIGZpbGUgbW9kdWxlLiAgQXMgYSBjb252ZW5pZW5jZSxcbiAgICAvLyB0aGlzIGZ1bmN0aW9uIGFsc28gcmV0dXJucyB0aGUgbGFuZ3VhZ2UgdmFsdWVzLlxuICAgIGZ1bmN0aW9uIGxvYWRMYW5nKGtleSwgdmFsdWVzKSB7XG4gICAgICAgIHZhbHVlcy5hYmJyID0ga2V5O1xuICAgICAgICBpZiAoIWxhbmd1YWdlc1trZXldKSB7XG4gICAgICAgICAgICBsYW5ndWFnZXNba2V5XSA9IG5ldyBMYW5ndWFnZSgpO1xuICAgICAgICB9XG4gICAgICAgIGxhbmd1YWdlc1trZXldLnNldCh2YWx1ZXMpO1xuICAgICAgICByZXR1cm4gbGFuZ3VhZ2VzW2tleV07XG4gICAgfVxuXG4gICAgLy8gRGV0ZXJtaW5lcyB3aGljaCBsYW5ndWFnZSBkZWZpbml0aW9uIHRvIHVzZSBhbmQgcmV0dXJucyBpdC5cbiAgICAvL1xuICAgIC8vIFdpdGggbm8gcGFyYW1ldGVycywgaXQgd2lsbCByZXR1cm4gdGhlIGdsb2JhbCBsYW5ndWFnZS4gIElmIHlvdVxuICAgIC8vIHBhc3MgaW4gYSBsYW5ndWFnZSBrZXksIHN1Y2ggYXMgJ2VuJywgaXQgd2lsbCByZXR1cm4gdGhlXG4gICAgLy8gZGVmaW5pdGlvbiBmb3IgJ2VuJywgc28gbG9uZyBhcyAnZW4nIGhhcyBhbHJlYWR5IGJlZW4gbG9hZGVkIHVzaW5nXG4gICAgLy8gbW9tZW50LmxhbmcuXG4gICAgZnVuY3Rpb24gZ2V0TGFuZ0RlZmluaXRpb24oa2V5KSB7XG4gICAgICAgIGlmICgha2V5KSB7XG4gICAgICAgICAgICByZXR1cm4gbW9tZW50LmZuLl9sYW5nO1xuICAgICAgICB9XG4gICAgICAgIGlmICghbGFuZ3VhZ2VzW2tleV0gJiYgaGFzTW9kdWxlKSB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIHJlcXVpcmUoJy4vbGFuZy8nICsga2V5KTtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICAvLyBjYWxsIHdpdGggbm8gcGFyYW1zIHRvIHNldCB0byBkZWZhdWx0XG4gICAgICAgICAgICAgICAgcmV0dXJuIG1vbWVudC5mbi5fbGFuZztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbGFuZ3VhZ2VzW2tleV07XG4gICAgfVxuXG5cbiAgICAvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG4gICAgICAgIEZvcm1hdHRpbmdcbiAgICAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cblxuICAgIGZ1bmN0aW9uIHJlbW92ZUZvcm1hdHRpbmdUb2tlbnMoaW5wdXQpIHtcbiAgICAgICAgaWYgKGlucHV0Lm1hdGNoKC9cXFsuKlxcXS8pKSB7XG4gICAgICAgICAgICByZXR1cm4gaW5wdXQucmVwbGFjZSgvXlxcW3xcXF0kL2csIFwiXCIpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBpbnB1dC5yZXBsYWNlKC9cXFxcL2csIFwiXCIpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIG1ha2VGb3JtYXRGdW5jdGlvbihmb3JtYXQpIHtcbiAgICAgICAgdmFyIGFycmF5ID0gZm9ybWF0Lm1hdGNoKGZvcm1hdHRpbmdUb2tlbnMpLCBpLCBsZW5ndGg7XG5cbiAgICAgICAgZm9yIChpID0gMCwgbGVuZ3RoID0gYXJyYXkubGVuZ3RoOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGlmIChmb3JtYXRUb2tlbkZ1bmN0aW9uc1thcnJheVtpXV0pIHtcbiAgICAgICAgICAgICAgICBhcnJheVtpXSA9IGZvcm1hdFRva2VuRnVuY3Rpb25zW2FycmF5W2ldXTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgYXJyYXlbaV0gPSByZW1vdmVGb3JtYXR0aW5nVG9rZW5zKGFycmF5W2ldKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBmdW5jdGlvbiAobW9tKSB7XG4gICAgICAgICAgICB2YXIgb3V0cHV0ID0gXCJcIjtcbiAgICAgICAgICAgIGZvciAoaSA9IDA7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIG91dHB1dCArPSBhcnJheVtpXSBpbnN0YW5jZW9mIEZ1bmN0aW9uID8gYXJyYXlbaV0uY2FsbChtb20sIGZvcm1hdCkgOiBhcnJheVtpXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBvdXRwdXQ7XG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgLy8gZm9ybWF0IGRhdGUgdXNpbmcgbmF0aXZlIGRhdGUgb2JqZWN0XG4gICAgZnVuY3Rpb24gZm9ybWF0TW9tZW50KG0sIGZvcm1hdCkge1xuICAgICAgICB2YXIgaSA9IDU7XG5cbiAgICAgICAgZnVuY3Rpb24gcmVwbGFjZUxvbmdEYXRlRm9ybWF0VG9rZW5zKGlucHV0KSB7XG4gICAgICAgICAgICByZXR1cm4gbS5sYW5nKCkubG9uZ0RhdGVGb3JtYXQoaW5wdXQpIHx8IGlucHV0O1xuICAgICAgICB9XG5cbiAgICAgICAgd2hpbGUgKGktLSAmJiBsb2NhbEZvcm1hdHRpbmdUb2tlbnMudGVzdChmb3JtYXQpKSB7XG4gICAgICAgICAgICBmb3JtYXQgPSBmb3JtYXQucmVwbGFjZShsb2NhbEZvcm1hdHRpbmdUb2tlbnMsIHJlcGxhY2VMb25nRGF0ZUZvcm1hdFRva2Vucyk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIWZvcm1hdEZ1bmN0aW9uc1tmb3JtYXRdKSB7XG4gICAgICAgICAgICBmb3JtYXRGdW5jdGlvbnNbZm9ybWF0XSA9IG1ha2VGb3JtYXRGdW5jdGlvbihmb3JtYXQpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGZvcm1hdEZ1bmN0aW9uc1tmb3JtYXRdKG0pO1xuICAgIH1cblxuXG4gICAgLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuICAgICAgICBQYXJzaW5nXG4gICAgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5cbiAgICAvLyBnZXQgdGhlIHJlZ2V4IHRvIGZpbmQgdGhlIG5leHQgdG9rZW5cbiAgICBmdW5jdGlvbiBnZXRQYXJzZVJlZ2V4Rm9yVG9rZW4odG9rZW4sIGNvbmZpZykge1xuICAgICAgICBzd2l0Y2ggKHRva2VuKSB7XG4gICAgICAgIGNhc2UgJ0REREQnOlxuICAgICAgICAgICAgcmV0dXJuIHBhcnNlVG9rZW5UaHJlZURpZ2l0cztcbiAgICAgICAgY2FzZSAnWVlZWSc6XG4gICAgICAgICAgICByZXR1cm4gcGFyc2VUb2tlbkZvdXJEaWdpdHM7XG4gICAgICAgIGNhc2UgJ1lZWVlZJzpcbiAgICAgICAgICAgIHJldHVybiBwYXJzZVRva2VuU2l4RGlnaXRzO1xuICAgICAgICBjYXNlICdTJzpcbiAgICAgICAgY2FzZSAnU1MnOlxuICAgICAgICBjYXNlICdTU1MnOlxuICAgICAgICBjYXNlICdEREQnOlxuICAgICAgICAgICAgcmV0dXJuIHBhcnNlVG9rZW5PbmVUb1RocmVlRGlnaXRzO1xuICAgICAgICBjYXNlICdNTU0nOlxuICAgICAgICBjYXNlICdNTU1NJzpcbiAgICAgICAgY2FzZSAnZGQnOlxuICAgICAgICBjYXNlICdkZGQnOlxuICAgICAgICBjYXNlICdkZGRkJzpcbiAgICAgICAgICAgIHJldHVybiBwYXJzZVRva2VuV29yZDtcbiAgICAgICAgY2FzZSAnYSc6XG4gICAgICAgIGNhc2UgJ0EnOlxuICAgICAgICAgICAgcmV0dXJuIGdldExhbmdEZWZpbml0aW9uKGNvbmZpZy5fbCkuX21lcmlkaWVtUGFyc2U7XG4gICAgICAgIGNhc2UgJ1gnOlxuICAgICAgICAgICAgcmV0dXJuIHBhcnNlVG9rZW5UaW1lc3RhbXBNcztcbiAgICAgICAgY2FzZSAnWic6XG4gICAgICAgIGNhc2UgJ1paJzpcbiAgICAgICAgICAgIHJldHVybiBwYXJzZVRva2VuVGltZXpvbmU7XG4gICAgICAgIGNhc2UgJ1QnOlxuICAgICAgICAgICAgcmV0dXJuIHBhcnNlVG9rZW5UO1xuICAgICAgICBjYXNlICdNTSc6XG4gICAgICAgIGNhc2UgJ0REJzpcbiAgICAgICAgY2FzZSAnWVknOlxuICAgICAgICBjYXNlICdISCc6XG4gICAgICAgIGNhc2UgJ2hoJzpcbiAgICAgICAgY2FzZSAnbW0nOlxuICAgICAgICBjYXNlICdzcyc6XG4gICAgICAgIGNhc2UgJ00nOlxuICAgICAgICBjYXNlICdEJzpcbiAgICAgICAgY2FzZSAnZCc6XG4gICAgICAgIGNhc2UgJ0gnOlxuICAgICAgICBjYXNlICdoJzpcbiAgICAgICAgY2FzZSAnbSc6XG4gICAgICAgIGNhc2UgJ3MnOlxuICAgICAgICAgICAgcmV0dXJuIHBhcnNlVG9rZW5PbmVPclR3b0RpZ2l0cztcbiAgICAgICAgZGVmYXVsdCA6XG4gICAgICAgICAgICByZXR1cm4gbmV3IFJlZ0V4cCh0b2tlbi5yZXBsYWNlKCdcXFxcJywgJycpKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIHRpbWV6b25lTWludXRlc0Zyb21TdHJpbmcoc3RyaW5nKSB7XG4gICAgICAgIHZhciB0emNodW5rID0gKHBhcnNlVG9rZW5UaW1lem9uZS5leGVjKHN0cmluZykgfHwgW10pWzBdLFxuICAgICAgICAgICAgcGFydHMgPSAodHpjaHVuayArICcnKS5tYXRjaChwYXJzZVRpbWV6b25lQ2h1bmtlcikgfHwgWyctJywgMCwgMF0sXG4gICAgICAgICAgICBtaW51dGVzID0gKyhwYXJ0c1sxXSAqIDYwKSArIH5+cGFydHNbMl07XG5cbiAgICAgICAgcmV0dXJuIHBhcnRzWzBdID09PSAnKycgPyAtbWludXRlcyA6IG1pbnV0ZXM7XG4gICAgfVxuXG4gICAgLy8gZnVuY3Rpb24gdG8gY29udmVydCBzdHJpbmcgaW5wdXQgdG8gZGF0ZVxuICAgIGZ1bmN0aW9uIGFkZFRpbWVUb0FycmF5RnJvbVRva2VuKHRva2VuLCBpbnB1dCwgY29uZmlnKSB7XG4gICAgICAgIHZhciBhLCBkYXRlUGFydEFycmF5ID0gY29uZmlnLl9hO1xuXG4gICAgICAgIHN3aXRjaCAodG9rZW4pIHtcbiAgICAgICAgLy8gTU9OVEhcbiAgICAgICAgY2FzZSAnTScgOiAvLyBmYWxsIHRocm91Z2ggdG8gTU1cbiAgICAgICAgY2FzZSAnTU0nIDpcbiAgICAgICAgICAgIGRhdGVQYXJ0QXJyYXlbMV0gPSAoaW5wdXQgPT0gbnVsbCkgPyAwIDogfn5pbnB1dCAtIDE7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAnTU1NJyA6IC8vIGZhbGwgdGhyb3VnaCB0byBNTU1NXG4gICAgICAgIGNhc2UgJ01NTU0nIDpcbiAgICAgICAgICAgIGEgPSBnZXRMYW5nRGVmaW5pdGlvbihjb25maWcuX2wpLm1vbnRoc1BhcnNlKGlucHV0KTtcbiAgICAgICAgICAgIC8vIGlmIHdlIGRpZG4ndCBmaW5kIGEgbW9udGggbmFtZSwgbWFyayB0aGUgZGF0ZSBhcyBpbnZhbGlkLlxuICAgICAgICAgICAgaWYgKGEgIT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIGRhdGVQYXJ0QXJyYXlbMV0gPSBhO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBjb25maWcuX2lzVmFsaWQgPSBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAvLyBEQVkgT0YgTU9OVEhcbiAgICAgICAgY2FzZSAnRCcgOiAvLyBmYWxsIHRocm91Z2ggdG8gRERERFxuICAgICAgICBjYXNlICdERCcgOiAvLyBmYWxsIHRocm91Z2ggdG8gRERERFxuICAgICAgICBjYXNlICdEREQnIDogLy8gZmFsbCB0aHJvdWdoIHRvIERERERcbiAgICAgICAgY2FzZSAnRERERCcgOlxuICAgICAgICAgICAgaWYgKGlucHV0ICE9IG51bGwpIHtcbiAgICAgICAgICAgICAgICBkYXRlUGFydEFycmF5WzJdID0gfn5pbnB1dDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAvLyBZRUFSXG4gICAgICAgIGNhc2UgJ1lZJyA6XG4gICAgICAgICAgICBkYXRlUGFydEFycmF5WzBdID0gfn5pbnB1dCArICh+fmlucHV0ID4gNjggPyAxOTAwIDogMjAwMCk7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAnWVlZWScgOlxuICAgICAgICBjYXNlICdZWVlZWScgOlxuICAgICAgICAgICAgZGF0ZVBhcnRBcnJheVswXSA9IH5+aW5wdXQ7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgLy8gQU0gLyBQTVxuICAgICAgICBjYXNlICdhJyA6IC8vIGZhbGwgdGhyb3VnaCB0byBBXG4gICAgICAgIGNhc2UgJ0EnIDpcbiAgICAgICAgICAgIGNvbmZpZy5faXNQbSA9IGdldExhbmdEZWZpbml0aW9uKGNvbmZpZy5fbCkuaXNQTShpbnB1dCk7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgLy8gMjQgSE9VUlxuICAgICAgICBjYXNlICdIJyA6IC8vIGZhbGwgdGhyb3VnaCB0byBoaFxuICAgICAgICBjYXNlICdISCcgOiAvLyBmYWxsIHRocm91Z2ggdG8gaGhcbiAgICAgICAgY2FzZSAnaCcgOiAvLyBmYWxsIHRocm91Z2ggdG8gaGhcbiAgICAgICAgY2FzZSAnaGgnIDpcbiAgICAgICAgICAgIGRhdGVQYXJ0QXJyYXlbM10gPSB+fmlucHV0O1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIC8vIE1JTlVURVxuICAgICAgICBjYXNlICdtJyA6IC8vIGZhbGwgdGhyb3VnaCB0byBtbVxuICAgICAgICBjYXNlICdtbScgOlxuICAgICAgICAgICAgZGF0ZVBhcnRBcnJheVs0XSA9IH5+aW5wdXQ7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgLy8gU0VDT05EXG4gICAgICAgIGNhc2UgJ3MnIDogLy8gZmFsbCB0aHJvdWdoIHRvIHNzXG4gICAgICAgIGNhc2UgJ3NzJyA6XG4gICAgICAgICAgICBkYXRlUGFydEFycmF5WzVdID0gfn5pbnB1dDtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAvLyBNSUxMSVNFQ09ORFxuICAgICAgICBjYXNlICdTJyA6XG4gICAgICAgIGNhc2UgJ1NTJyA6XG4gICAgICAgIGNhc2UgJ1NTUycgOlxuICAgICAgICAgICAgZGF0ZVBhcnRBcnJheVs2XSA9IH5+ICgoJzAuJyArIGlucHV0KSAqIDEwMDApO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIC8vIFVOSVggVElNRVNUQU1QIFdJVEggTVNcbiAgICAgICAgY2FzZSAnWCc6XG4gICAgICAgICAgICBjb25maWcuX2QgPSBuZXcgRGF0ZShwYXJzZUZsb2F0KGlucHV0KSAqIDEwMDApO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIC8vIFRJTUVaT05FXG4gICAgICAgIGNhc2UgJ1onIDogLy8gZmFsbCB0aHJvdWdoIHRvIFpaXG4gICAgICAgIGNhc2UgJ1paJyA6XG4gICAgICAgICAgICBjb25maWcuX3VzZVVUQyA9IHRydWU7XG4gICAgICAgICAgICBjb25maWcuX3R6bSA9IHRpbWV6b25lTWludXRlc0Zyb21TdHJpbmcoaW5wdXQpO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBpZiB0aGUgaW5wdXQgaXMgbnVsbCwgdGhlIGRhdGUgaXMgbm90IHZhbGlkXG4gICAgICAgIGlmIChpbnB1dCA9PSBudWxsKSB7XG4gICAgICAgICAgICBjb25maWcuX2lzVmFsaWQgPSBmYWxzZTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vIGNvbnZlcnQgYW4gYXJyYXkgdG8gYSBkYXRlLlxuICAgIC8vIHRoZSBhcnJheSBzaG91bGQgbWlycm9yIHRoZSBwYXJhbWV0ZXJzIGJlbG93XG4gICAgLy8gbm90ZTogYWxsIHZhbHVlcyBwYXN0IHRoZSB5ZWFyIGFyZSBvcHRpb25hbCBhbmQgd2lsbCBkZWZhdWx0IHRvIHRoZSBsb3dlc3QgcG9zc2libGUgdmFsdWUuXG4gICAgLy8gW3llYXIsIG1vbnRoLCBkYXkgLCBob3VyLCBtaW51dGUsIHNlY29uZCwgbWlsbGlzZWNvbmRdXG4gICAgZnVuY3Rpb24gZGF0ZUZyb21BcnJheShjb25maWcpIHtcbiAgICAgICAgdmFyIGksIGRhdGUsIGlucHV0ID0gW107XG5cbiAgICAgICAgaWYgKGNvbmZpZy5fZCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgZm9yIChpID0gMDsgaSA8IDc7IGkrKykge1xuICAgICAgICAgICAgY29uZmlnLl9hW2ldID0gaW5wdXRbaV0gPSAoY29uZmlnLl9hW2ldID09IG51bGwpID8gKGkgPT09IDIgPyAxIDogMCkgOiBjb25maWcuX2FbaV07XG4gICAgICAgIH1cblxuICAgICAgICAvLyBhZGQgdGhlIG9mZnNldHMgdG8gdGhlIHRpbWUgdG8gYmUgcGFyc2VkIHNvIHRoYXQgd2UgY2FuIGhhdmUgYSBjbGVhbiBhcnJheSBmb3IgY2hlY2tpbmcgaXNWYWxpZFxuICAgICAgICBpbnB1dFszXSArPSB+figoY29uZmlnLl90em0gfHwgMCkgLyA2MCk7XG4gICAgICAgIGlucHV0WzRdICs9IH5+KChjb25maWcuX3R6bSB8fCAwKSAlIDYwKTtcblxuICAgICAgICBkYXRlID0gbmV3IERhdGUoMCk7XG5cbiAgICAgICAgaWYgKGNvbmZpZy5fdXNlVVRDKSB7XG4gICAgICAgICAgICBkYXRlLnNldFVUQ0Z1bGxZZWFyKGlucHV0WzBdLCBpbnB1dFsxXSwgaW5wdXRbMl0pO1xuICAgICAgICAgICAgZGF0ZS5zZXRVVENIb3VycyhpbnB1dFszXSwgaW5wdXRbNF0sIGlucHV0WzVdLCBpbnB1dFs2XSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBkYXRlLnNldEZ1bGxZZWFyKGlucHV0WzBdLCBpbnB1dFsxXSwgaW5wdXRbMl0pO1xuICAgICAgICAgICAgZGF0ZS5zZXRIb3VycyhpbnB1dFszXSwgaW5wdXRbNF0sIGlucHV0WzVdLCBpbnB1dFs2XSk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25maWcuX2QgPSBkYXRlO1xuICAgIH1cblxuICAgIC8vIGRhdGUgZnJvbSBzdHJpbmcgYW5kIGZvcm1hdCBzdHJpbmdcbiAgICBmdW5jdGlvbiBtYWtlRGF0ZUZyb21TdHJpbmdBbmRGb3JtYXQoY29uZmlnKSB7XG4gICAgICAgIC8vIFRoaXMgYXJyYXkgaXMgdXNlZCB0byBtYWtlIGEgRGF0ZSwgZWl0aGVyIHdpdGggYG5ldyBEYXRlYCBvciBgRGF0ZS5VVENgXG4gICAgICAgIHZhciB0b2tlbnMgPSBjb25maWcuX2YubWF0Y2goZm9ybWF0dGluZ1Rva2VucyksXG4gICAgICAgICAgICBzdHJpbmcgPSBjb25maWcuX2ksXG4gICAgICAgICAgICBpLCBwYXJzZWRJbnB1dDtcblxuICAgICAgICBjb25maWcuX2EgPSBbXTtcblxuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgdG9rZW5zLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBwYXJzZWRJbnB1dCA9IChnZXRQYXJzZVJlZ2V4Rm9yVG9rZW4odG9rZW5zW2ldLCBjb25maWcpLmV4ZWMoc3RyaW5nKSB8fCBbXSlbMF07XG4gICAgICAgICAgICBpZiAocGFyc2VkSW5wdXQpIHtcbiAgICAgICAgICAgICAgICBzdHJpbmcgPSBzdHJpbmcuc2xpY2Uoc3RyaW5nLmluZGV4T2YocGFyc2VkSW5wdXQpICsgcGFyc2VkSW5wdXQubGVuZ3RoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIGRvbid0IHBhcnNlIGlmIGl0cyBub3QgYSBrbm93biB0b2tlblxuICAgICAgICAgICAgaWYgKGZvcm1hdFRva2VuRnVuY3Rpb25zW3Rva2Vuc1tpXV0pIHtcbiAgICAgICAgICAgICAgICBhZGRUaW1lVG9BcnJheUZyb21Ub2tlbih0b2tlbnNbaV0sIHBhcnNlZElucHV0LCBjb25maWcpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gYWRkIHJlbWFpbmluZyB1bnBhcnNlZCBpbnB1dCB0byB0aGUgc3RyaW5nXG4gICAgICAgIGlmIChzdHJpbmcpIHtcbiAgICAgICAgICAgIGNvbmZpZy5faWwgPSBzdHJpbmc7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBoYW5kbGUgYW0gcG1cbiAgICAgICAgaWYgKGNvbmZpZy5faXNQbSAmJiBjb25maWcuX2FbM10gPCAxMikge1xuICAgICAgICAgICAgY29uZmlnLl9hWzNdICs9IDEyO1xuICAgICAgICB9XG4gICAgICAgIC8vIGlmIGlzIDEyIGFtLCBjaGFuZ2UgaG91cnMgdG8gMFxuICAgICAgICBpZiAoY29uZmlnLl9pc1BtID09PSBmYWxzZSAmJiBjb25maWcuX2FbM10gPT09IDEyKSB7XG4gICAgICAgICAgICBjb25maWcuX2FbM10gPSAwO1xuICAgICAgICB9XG4gICAgICAgIC8vIHJldHVyblxuICAgICAgICBkYXRlRnJvbUFycmF5KGNvbmZpZyk7XG4gICAgfVxuXG4gICAgLy8gZGF0ZSBmcm9tIHN0cmluZyBhbmQgYXJyYXkgb2YgZm9ybWF0IHN0cmluZ3NcbiAgICBmdW5jdGlvbiBtYWtlRGF0ZUZyb21TdHJpbmdBbmRBcnJheShjb25maWcpIHtcbiAgICAgICAgdmFyIHRlbXBDb25maWcsXG4gICAgICAgICAgICB0ZW1wTW9tZW50LFxuICAgICAgICAgICAgYmVzdE1vbWVudCxcblxuICAgICAgICAgICAgc2NvcmVUb0JlYXQgPSA5OSxcbiAgICAgICAgICAgIGksXG4gICAgICAgICAgICBjdXJyZW50U2NvcmU7XG5cbiAgICAgICAgZm9yIChpID0gMDsgaSA8IGNvbmZpZy5fZi5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgdGVtcENvbmZpZyA9IGV4dGVuZCh7fSwgY29uZmlnKTtcbiAgICAgICAgICAgIHRlbXBDb25maWcuX2YgPSBjb25maWcuX2ZbaV07XG4gICAgICAgICAgICBtYWtlRGF0ZUZyb21TdHJpbmdBbmRGb3JtYXQodGVtcENvbmZpZyk7XG4gICAgICAgICAgICB0ZW1wTW9tZW50ID0gbmV3IE1vbWVudCh0ZW1wQ29uZmlnKTtcblxuICAgICAgICAgICAgY3VycmVudFNjb3JlID0gY29tcGFyZUFycmF5cyh0ZW1wQ29uZmlnLl9hLCB0ZW1wTW9tZW50LnRvQXJyYXkoKSk7XG5cbiAgICAgICAgICAgIC8vIGlmIHRoZXJlIGlzIGFueSBpbnB1dCB0aGF0IHdhcyBub3QgcGFyc2VkXG4gICAgICAgICAgICAvLyBhZGQgYSBwZW5hbHR5IGZvciB0aGF0IGZvcm1hdFxuICAgICAgICAgICAgaWYgKHRlbXBNb21lbnQuX2lsKSB7XG4gICAgICAgICAgICAgICAgY3VycmVudFNjb3JlICs9IHRlbXBNb21lbnQuX2lsLmxlbmd0aDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKGN1cnJlbnRTY29yZSA8IHNjb3JlVG9CZWF0KSB7XG4gICAgICAgICAgICAgICAgc2NvcmVUb0JlYXQgPSBjdXJyZW50U2NvcmU7XG4gICAgICAgICAgICAgICAgYmVzdE1vbWVudCA9IHRlbXBNb21lbnQ7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBleHRlbmQoY29uZmlnLCBiZXN0TW9tZW50KTtcbiAgICB9XG5cbiAgICAvLyBkYXRlIGZyb20gaXNvIGZvcm1hdFxuICAgIGZ1bmN0aW9uIG1ha2VEYXRlRnJvbVN0cmluZyhjb25maWcpIHtcbiAgICAgICAgdmFyIGksXG4gICAgICAgICAgICBzdHJpbmcgPSBjb25maWcuX2ksXG4gICAgICAgICAgICBtYXRjaCA9IGlzb1JlZ2V4LmV4ZWMoc3RyaW5nKTtcblxuICAgICAgICBpZiAobWF0Y2gpIHtcbiAgICAgICAgICAgIC8vIG1hdGNoWzJdIHNob3VsZCBiZSBcIlRcIiBvciB1bmRlZmluZWRcbiAgICAgICAgICAgIGNvbmZpZy5fZiA9ICdZWVlZLU1NLUREJyArIChtYXRjaFsyXSB8fCBcIiBcIik7XG4gICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwgNDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgaWYgKGlzb1RpbWVzW2ldWzFdLmV4ZWMoc3RyaW5nKSkge1xuICAgICAgICAgICAgICAgICAgICBjb25maWcuX2YgKz0gaXNvVGltZXNbaV1bMF07XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChwYXJzZVRva2VuVGltZXpvbmUuZXhlYyhzdHJpbmcpKSB7XG4gICAgICAgICAgICAgICAgY29uZmlnLl9mICs9IFwiIFpcIjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIG1ha2VEYXRlRnJvbVN0cmluZ0FuZEZvcm1hdChjb25maWcpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY29uZmlnLl9kID0gbmV3IERhdGUoc3RyaW5nKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIG1ha2VEYXRlRnJvbUlucHV0KGNvbmZpZykge1xuICAgICAgICB2YXIgaW5wdXQgPSBjb25maWcuX2ksXG4gICAgICAgICAgICBtYXRjaGVkID0gYXNwTmV0SnNvblJlZ2V4LmV4ZWMoaW5wdXQpO1xuXG4gICAgICAgIGlmIChpbnB1dCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBjb25maWcuX2QgPSBuZXcgRGF0ZSgpO1xuICAgICAgICB9IGVsc2UgaWYgKG1hdGNoZWQpIHtcbiAgICAgICAgICAgIGNvbmZpZy5fZCA9IG5ldyBEYXRlKCttYXRjaGVkWzFdKTtcbiAgICAgICAgfSBlbHNlIGlmICh0eXBlb2YgaW5wdXQgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICBtYWtlRGF0ZUZyb21TdHJpbmcoY29uZmlnKTtcbiAgICAgICAgfSBlbHNlIGlmIChpc0FycmF5KGlucHV0KSkge1xuICAgICAgICAgICAgY29uZmlnLl9hID0gaW5wdXQuc2xpY2UoMCk7XG4gICAgICAgICAgICBkYXRlRnJvbUFycmF5KGNvbmZpZyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25maWcuX2QgPSBpbnB1dCBpbnN0YW5jZW9mIERhdGUgPyBuZXcgRGF0ZSgraW5wdXQpIDogbmV3IERhdGUoaW5wdXQpO1xuICAgICAgICB9XG4gICAgfVxuXG5cbiAgICAvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG4gICAgICAgIFJlbGF0aXZlIFRpbWVcbiAgICAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cblxuICAgIC8vIGhlbHBlciBmdW5jdGlvbiBmb3IgbW9tZW50LmZuLmZyb20sIG1vbWVudC5mbi5mcm9tTm93LCBhbmQgbW9tZW50LmR1cmF0aW9uLmZuLmh1bWFuaXplXG4gICAgZnVuY3Rpb24gc3Vic3RpdHV0ZVRpbWVBZ28oc3RyaW5nLCBudW1iZXIsIHdpdGhvdXRTdWZmaXgsIGlzRnV0dXJlLCBsYW5nKSB7XG4gICAgICAgIHJldHVybiBsYW5nLnJlbGF0aXZlVGltZShudW1iZXIgfHwgMSwgISF3aXRob3V0U3VmZml4LCBzdHJpbmcsIGlzRnV0dXJlKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiByZWxhdGl2ZVRpbWUobWlsbGlzZWNvbmRzLCB3aXRob3V0U3VmZml4LCBsYW5nKSB7XG4gICAgICAgIHZhciBzZWNvbmRzID0gcm91bmQoTWF0aC5hYnMobWlsbGlzZWNvbmRzKSAvIDEwMDApLFxuICAgICAgICAgICAgbWludXRlcyA9IHJvdW5kKHNlY29uZHMgLyA2MCksXG4gICAgICAgICAgICBob3VycyA9IHJvdW5kKG1pbnV0ZXMgLyA2MCksXG4gICAgICAgICAgICBkYXlzID0gcm91bmQoaG91cnMgLyAyNCksXG4gICAgICAgICAgICB5ZWFycyA9IHJvdW5kKGRheXMgLyAzNjUpLFxuICAgICAgICAgICAgYXJncyA9IHNlY29uZHMgPCA0NSAmJiBbJ3MnLCBzZWNvbmRzXSB8fFxuICAgICAgICAgICAgICAgIG1pbnV0ZXMgPT09IDEgJiYgWydtJ10gfHxcbiAgICAgICAgICAgICAgICBtaW51dGVzIDwgNDUgJiYgWydtbScsIG1pbnV0ZXNdIHx8XG4gICAgICAgICAgICAgICAgaG91cnMgPT09IDEgJiYgWydoJ10gfHxcbiAgICAgICAgICAgICAgICBob3VycyA8IDIyICYmIFsnaGgnLCBob3Vyc10gfHxcbiAgICAgICAgICAgICAgICBkYXlzID09PSAxICYmIFsnZCddIHx8XG4gICAgICAgICAgICAgICAgZGF5cyA8PSAyNSAmJiBbJ2RkJywgZGF5c10gfHxcbiAgICAgICAgICAgICAgICBkYXlzIDw9IDQ1ICYmIFsnTSddIHx8XG4gICAgICAgICAgICAgICAgZGF5cyA8IDM0NSAmJiBbJ01NJywgcm91bmQoZGF5cyAvIDMwKV0gfHxcbiAgICAgICAgICAgICAgICB5ZWFycyA9PT0gMSAmJiBbJ3knXSB8fCBbJ3l5JywgeWVhcnNdO1xuICAgICAgICBhcmdzWzJdID0gd2l0aG91dFN1ZmZpeDtcbiAgICAgICAgYXJnc1szXSA9IG1pbGxpc2Vjb25kcyA+IDA7XG4gICAgICAgIGFyZ3NbNF0gPSBsYW5nO1xuICAgICAgICByZXR1cm4gc3Vic3RpdHV0ZVRpbWVBZ28uYXBwbHkoe30sIGFyZ3MpO1xuICAgIH1cblxuXG4gICAgLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuICAgICAgICBXZWVrIG9mIFllYXJcbiAgICAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cblxuICAgIC8vIGZpcnN0RGF5T2ZXZWVrICAgICAgIDAgPSBzdW4sIDYgPSBzYXRcbiAgICAvLyAgICAgICAgICAgICAgICAgICAgICB0aGUgZGF5IG9mIHRoZSB3ZWVrIHRoYXQgc3RhcnRzIHRoZSB3ZWVrXG4gICAgLy8gICAgICAgICAgICAgICAgICAgICAgKHVzdWFsbHkgc3VuZGF5IG9yIG1vbmRheSlcbiAgICAvLyBmaXJzdERheU9mV2Vla09mWWVhciAwID0gc3VuLCA2ID0gc2F0XG4gICAgLy8gICAgICAgICAgICAgICAgICAgICAgdGhlIGZpcnN0IHdlZWsgaXMgdGhlIHdlZWsgdGhhdCBjb250YWlucyB0aGUgZmlyc3RcbiAgICAvLyAgICAgICAgICAgICAgICAgICAgICBvZiB0aGlzIGRheSBvZiB0aGUgd2Vla1xuICAgIC8vICAgICAgICAgICAgICAgICAgICAgIChlZy4gSVNPIHdlZWtzIHVzZSB0aHVyc2RheSAoNCkpXG4gICAgZnVuY3Rpb24gd2Vla09mWWVhcihtb20sIGZpcnN0RGF5T2ZXZWVrLCBmaXJzdERheU9mV2Vla09mWWVhcikge1xuICAgICAgICB2YXIgZW5kID0gZmlyc3REYXlPZldlZWtPZlllYXIgLSBmaXJzdERheU9mV2VlayxcbiAgICAgICAgICAgIGRheXNUb0RheU9mV2VlayA9IGZpcnN0RGF5T2ZXZWVrT2ZZZWFyIC0gbW9tLmRheSgpLFxuICAgICAgICAgICAgYWRqdXN0ZWRNb21lbnQ7XG5cblxuICAgICAgICBpZiAoZGF5c1RvRGF5T2ZXZWVrID4gZW5kKSB7XG4gICAgICAgICAgICBkYXlzVG9EYXlPZldlZWsgLT0gNztcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChkYXlzVG9EYXlPZldlZWsgPCBlbmQgLSA3KSB7XG4gICAgICAgICAgICBkYXlzVG9EYXlPZldlZWsgKz0gNztcbiAgICAgICAgfVxuXG4gICAgICAgIGFkanVzdGVkTW9tZW50ID0gbW9tZW50KG1vbSkuYWRkKCdkJywgZGF5c1RvRGF5T2ZXZWVrKTtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHdlZWs6IE1hdGguY2VpbChhZGp1c3RlZE1vbWVudC5kYXlPZlllYXIoKSAvIDcpLFxuICAgICAgICAgICAgeWVhcjogYWRqdXN0ZWRNb21lbnQueWVhcigpXG4gICAgICAgIH07XG4gICAgfVxuXG5cbiAgICAvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG4gICAgICAgIFRvcCBMZXZlbCBGdW5jdGlvbnNcbiAgICAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbiAgICBmdW5jdGlvbiBtYWtlTW9tZW50KGNvbmZpZykge1xuICAgICAgICB2YXIgaW5wdXQgPSBjb25maWcuX2ksXG4gICAgICAgICAgICBmb3JtYXQgPSBjb25maWcuX2Y7XG5cbiAgICAgICAgaWYgKGlucHV0ID09PSBudWxsIHx8IGlucHV0ID09PSAnJykge1xuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHlwZW9mIGlucHV0ID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgY29uZmlnLl9pID0gaW5wdXQgPSBnZXRMYW5nRGVmaW5pdGlvbigpLnByZXBhcnNlKGlucHV0KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChtb21lbnQuaXNNb21lbnQoaW5wdXQpKSB7XG4gICAgICAgICAgICBjb25maWcgPSBleHRlbmQoe30sIGlucHV0KTtcbiAgICAgICAgICAgIGNvbmZpZy5fZCA9IG5ldyBEYXRlKCtpbnB1dC5fZCk7XG4gICAgICAgIH0gZWxzZSBpZiAoZm9ybWF0KSB7XG4gICAgICAgICAgICBpZiAoaXNBcnJheShmb3JtYXQpKSB7XG4gICAgICAgICAgICAgICAgbWFrZURhdGVGcm9tU3RyaW5nQW5kQXJyYXkoY29uZmlnKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgbWFrZURhdGVGcm9tU3RyaW5nQW5kRm9ybWF0KGNvbmZpZyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBtYWtlRGF0ZUZyb21JbnB1dChjb25maWcpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG5ldyBNb21lbnQoY29uZmlnKTtcbiAgICB9XG5cbiAgICBtb21lbnQgPSBmdW5jdGlvbiAoaW5wdXQsIGZvcm1hdCwgbGFuZykge1xuICAgICAgICByZXR1cm4gbWFrZU1vbWVudCh7XG4gICAgICAgICAgICBfaSA6IGlucHV0LFxuICAgICAgICAgICAgX2YgOiBmb3JtYXQsXG4gICAgICAgICAgICBfbCA6IGxhbmcsXG4gICAgICAgICAgICBfaXNVVEMgOiBmYWxzZVxuICAgICAgICB9KTtcbiAgICB9O1xuXG4gICAgLy8gY3JlYXRpbmcgd2l0aCB1dGNcbiAgICBtb21lbnQudXRjID0gZnVuY3Rpb24gKGlucHV0LCBmb3JtYXQsIGxhbmcpIHtcbiAgICAgICAgcmV0dXJuIG1ha2VNb21lbnQoe1xuICAgICAgICAgICAgX3VzZVVUQyA6IHRydWUsXG4gICAgICAgICAgICBfaXNVVEMgOiB0cnVlLFxuICAgICAgICAgICAgX2wgOiBsYW5nLFxuICAgICAgICAgICAgX2kgOiBpbnB1dCxcbiAgICAgICAgICAgIF9mIDogZm9ybWF0XG4gICAgICAgIH0pO1xuICAgIH07XG5cbiAgICAvLyBjcmVhdGluZyB3aXRoIHVuaXggdGltZXN0YW1wIChpbiBzZWNvbmRzKVxuICAgIG1vbWVudC51bml4ID0gZnVuY3Rpb24gKGlucHV0KSB7XG4gICAgICAgIHJldHVybiBtb21lbnQoaW5wdXQgKiAxMDAwKTtcbiAgICB9O1xuXG4gICAgLy8gZHVyYXRpb25cbiAgICBtb21lbnQuZHVyYXRpb24gPSBmdW5jdGlvbiAoaW5wdXQsIGtleSkge1xuICAgICAgICB2YXIgaXNEdXJhdGlvbiA9IG1vbWVudC5pc0R1cmF0aW9uKGlucHV0KSxcbiAgICAgICAgICAgIGlzTnVtYmVyID0gKHR5cGVvZiBpbnB1dCA9PT0gJ251bWJlcicpLFxuICAgICAgICAgICAgZHVyYXRpb24gPSAoaXNEdXJhdGlvbiA/IGlucHV0Ll9pbnB1dCA6IChpc051bWJlciA/IHt9IDogaW5wdXQpKSxcbiAgICAgICAgICAgIG1hdGNoZWQgPSBhc3BOZXRUaW1lU3Bhbkpzb25SZWdleC5leGVjKGlucHV0KSxcbiAgICAgICAgICAgIHNpZ24sXG4gICAgICAgICAgICByZXQ7XG5cbiAgICAgICAgaWYgKGlzTnVtYmVyKSB7XG4gICAgICAgICAgICBpZiAoa2V5KSB7XG4gICAgICAgICAgICAgICAgZHVyYXRpb25ba2V5XSA9IGlucHV0O1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBkdXJhdGlvbi5taWxsaXNlY29uZHMgPSBpbnB1dDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChtYXRjaGVkKSB7XG4gICAgICAgICAgICBzaWduID0gKG1hdGNoZWRbMV0gPT09IFwiLVwiKSA/IC0xIDogMTtcbiAgICAgICAgICAgIGR1cmF0aW9uID0ge1xuICAgICAgICAgICAgICAgIHk6IDAsXG4gICAgICAgICAgICAgICAgZDogfn5tYXRjaGVkWzJdICogc2lnbixcbiAgICAgICAgICAgICAgICBoOiB+fm1hdGNoZWRbM10gKiBzaWduLFxuICAgICAgICAgICAgICAgIG06IH5+bWF0Y2hlZFs0XSAqIHNpZ24sXG4gICAgICAgICAgICAgICAgczogfn5tYXRjaGVkWzVdICogc2lnbixcbiAgICAgICAgICAgICAgICBtczogfn5tYXRjaGVkWzZdICogc2lnblxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldCA9IG5ldyBEdXJhdGlvbihkdXJhdGlvbik7XG5cbiAgICAgICAgaWYgKGlzRHVyYXRpb24gJiYgaW5wdXQuaGFzT3duUHJvcGVydHkoJ19sYW5nJykpIHtcbiAgICAgICAgICAgIHJldC5fbGFuZyA9IGlucHV0Ll9sYW5nO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHJldDtcbiAgICB9O1xuXG4gICAgLy8gdmVyc2lvbiBudW1iZXJcbiAgICBtb21lbnQudmVyc2lvbiA9IFZFUlNJT047XG5cbiAgICAvLyBkZWZhdWx0IGZvcm1hdFxuICAgIG1vbWVudC5kZWZhdWx0Rm9ybWF0ID0gaXNvRm9ybWF0O1xuXG4gICAgLy8gVGhpcyBmdW5jdGlvbiB3aWxsIGJlIGNhbGxlZCB3aGVuZXZlciBhIG1vbWVudCBpcyBtdXRhdGVkLlxuICAgIC8vIEl0IGlzIGludGVuZGVkIHRvIGtlZXAgdGhlIG9mZnNldCBpbiBzeW5jIHdpdGggdGhlIHRpbWV6b25lLlxuICAgIG1vbWVudC51cGRhdGVPZmZzZXQgPSBmdW5jdGlvbiAoKSB7fTtcblxuICAgIC8vIFRoaXMgZnVuY3Rpb24gd2lsbCBsb2FkIGxhbmd1YWdlcyBhbmQgdGhlbiBzZXQgdGhlIGdsb2JhbCBsYW5ndWFnZS4gIElmXG4gICAgLy8gbm8gYXJndW1lbnRzIGFyZSBwYXNzZWQgaW4sIGl0IHdpbGwgc2ltcGx5IHJldHVybiB0aGUgY3VycmVudCBnbG9iYWxcbiAgICAvLyBsYW5ndWFnZSBrZXkuXG4gICAgbW9tZW50LmxhbmcgPSBmdW5jdGlvbiAoa2V5LCB2YWx1ZXMpIHtcbiAgICAgICAgaWYgKCFrZXkpIHtcbiAgICAgICAgICAgIHJldHVybiBtb21lbnQuZm4uX2xhbmcuX2FiYnI7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHZhbHVlcykge1xuICAgICAgICAgICAgbG9hZExhbmcoa2V5LCB2YWx1ZXMpO1xuICAgICAgICB9IGVsc2UgaWYgKCFsYW5ndWFnZXNba2V5XSkge1xuICAgICAgICAgICAgZ2V0TGFuZ0RlZmluaXRpb24oa2V5KTtcbiAgICAgICAgfVxuICAgICAgICBtb21lbnQuZHVyYXRpb24uZm4uX2xhbmcgPSBtb21lbnQuZm4uX2xhbmcgPSBnZXRMYW5nRGVmaW5pdGlvbihrZXkpO1xuICAgIH07XG5cbiAgICAvLyByZXR1cm5zIGxhbmd1YWdlIGRhdGFcbiAgICBtb21lbnQubGFuZ0RhdGEgPSBmdW5jdGlvbiAoa2V5KSB7XG4gICAgICAgIGlmIChrZXkgJiYga2V5Ll9sYW5nICYmIGtleS5fbGFuZy5fYWJicikge1xuICAgICAgICAgICAga2V5ID0ga2V5Ll9sYW5nLl9hYmJyO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBnZXRMYW5nRGVmaW5pdGlvbihrZXkpO1xuICAgIH07XG5cbiAgICAvLyBjb21wYXJlIG1vbWVudCBvYmplY3RcbiAgICBtb21lbnQuaXNNb21lbnQgPSBmdW5jdGlvbiAob2JqKSB7XG4gICAgICAgIHJldHVybiBvYmogaW5zdGFuY2VvZiBNb21lbnQ7XG4gICAgfTtcblxuICAgIC8vIGZvciB0eXBlY2hlY2tpbmcgRHVyYXRpb24gb2JqZWN0c1xuICAgIG1vbWVudC5pc0R1cmF0aW9uID0gZnVuY3Rpb24gKG9iaikge1xuICAgICAgICByZXR1cm4gb2JqIGluc3RhbmNlb2YgRHVyYXRpb247XG4gICAgfTtcblxuXG4gICAgLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuICAgICAgICBNb21lbnQgUHJvdG90eXBlXG4gICAgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5cbiAgICBtb21lbnQuZm4gPSBNb21lbnQucHJvdG90eXBlID0ge1xuXG4gICAgICAgIGNsb25lIDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIG1vbWVudCh0aGlzKTtcbiAgICAgICAgfSxcblxuICAgICAgICB2YWx1ZU9mIDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuICt0aGlzLl9kICsgKCh0aGlzLl9vZmZzZXQgfHwgMCkgKiA2MDAwMCk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgdW5peCA6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBNYXRoLmZsb29yKCt0aGlzIC8gMTAwMCk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgdG9TdHJpbmcgOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5mb3JtYXQoXCJkZGQgTU1NIEREIFlZWVkgSEg6bW06c3MgW0dNVF1aWlwiKTtcbiAgICAgICAgfSxcblxuICAgICAgICB0b0RhdGUgOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fb2Zmc2V0ID8gbmV3IERhdGUoK3RoaXMpIDogdGhpcy5fZDtcbiAgICAgICAgfSxcblxuICAgICAgICB0b0lTT1N0cmluZyA6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBmb3JtYXRNb21lbnQobW9tZW50KHRoaXMpLnV0YygpLCAnWVlZWS1NTS1ERFtUXUhIOm1tOnNzLlNTU1taXScpO1xuICAgICAgICB9LFxuXG4gICAgICAgIHRvQXJyYXkgOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgbSA9IHRoaXM7XG4gICAgICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgICAgIG0ueWVhcigpLFxuICAgICAgICAgICAgICAgIG0ubW9udGgoKSxcbiAgICAgICAgICAgICAgICBtLmRhdGUoKSxcbiAgICAgICAgICAgICAgICBtLmhvdXJzKCksXG4gICAgICAgICAgICAgICAgbS5taW51dGVzKCksXG4gICAgICAgICAgICAgICAgbS5zZWNvbmRzKCksXG4gICAgICAgICAgICAgICAgbS5taWxsaXNlY29uZHMoKVxuICAgICAgICAgICAgXTtcbiAgICAgICAgfSxcblxuICAgICAgICBpc1ZhbGlkIDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgaWYgKHRoaXMuX2lzVmFsaWQgPT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLl9hKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX2lzVmFsaWQgPSAhY29tcGFyZUFycmF5cyh0aGlzLl9hLCAodGhpcy5faXNVVEMgPyBtb21lbnQudXRjKHRoaXMuX2EpIDogbW9tZW50KHRoaXMuX2EpKS50b0FycmF5KCkpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX2lzVmFsaWQgPSAhaXNOYU4odGhpcy5fZC5nZXRUaW1lKCkpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiAhIXRoaXMuX2lzVmFsaWQ7XG4gICAgICAgIH0sXG5cbiAgICAgICAgdXRjIDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuem9uZSgwKTtcbiAgICAgICAgfSxcblxuICAgICAgICBsb2NhbCA6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHRoaXMuem9uZSgwKTtcbiAgICAgICAgICAgIHRoaXMuX2lzVVRDID0gZmFsc2U7XG4gICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfSxcblxuICAgICAgICBmb3JtYXQgOiBmdW5jdGlvbiAoaW5wdXRTdHJpbmcpIHtcbiAgICAgICAgICAgIHZhciBvdXRwdXQgPSBmb3JtYXRNb21lbnQodGhpcywgaW5wdXRTdHJpbmcgfHwgbW9tZW50LmRlZmF1bHRGb3JtYXQpO1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMubGFuZygpLnBvc3Rmb3JtYXQob3V0cHV0KTtcbiAgICAgICAgfSxcblxuICAgICAgICBhZGQgOiBmdW5jdGlvbiAoaW5wdXQsIHZhbCkge1xuICAgICAgICAgICAgdmFyIGR1cjtcbiAgICAgICAgICAgIC8vIHN3aXRjaCBhcmdzIHRvIHN1cHBvcnQgYWRkKCdzJywgMSkgYW5kIGFkZCgxLCAncycpXG4gICAgICAgICAgICBpZiAodHlwZW9mIGlucHV0ID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICAgIGR1ciA9IG1vbWVudC5kdXJhdGlvbigrdmFsLCBpbnB1dCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGR1ciA9IG1vbWVudC5kdXJhdGlvbihpbnB1dCwgdmFsKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGFkZE9yU3VidHJhY3REdXJhdGlvbkZyb21Nb21lbnQodGhpcywgZHVyLCAxKTtcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9LFxuXG4gICAgICAgIHN1YnRyYWN0IDogZnVuY3Rpb24gKGlucHV0LCB2YWwpIHtcbiAgICAgICAgICAgIHZhciBkdXI7XG4gICAgICAgICAgICAvLyBzd2l0Y2ggYXJncyB0byBzdXBwb3J0IHN1YnRyYWN0KCdzJywgMSkgYW5kIHN1YnRyYWN0KDEsICdzJylcbiAgICAgICAgICAgIGlmICh0eXBlb2YgaW5wdXQgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAgICAgZHVyID0gbW9tZW50LmR1cmF0aW9uKCt2YWwsIGlucHV0KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgZHVyID0gbW9tZW50LmR1cmF0aW9uKGlucHV0LCB2YWwpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgYWRkT3JTdWJ0cmFjdER1cmF0aW9uRnJvbU1vbWVudCh0aGlzLCBkdXIsIC0xKTtcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9LFxuXG4gICAgICAgIGRpZmYgOiBmdW5jdGlvbiAoaW5wdXQsIHVuaXRzLCBhc0Zsb2F0KSB7XG4gICAgICAgICAgICB2YXIgdGhhdCA9IHRoaXMuX2lzVVRDID8gbW9tZW50KGlucHV0KS56b25lKHRoaXMuX29mZnNldCB8fCAwKSA6IG1vbWVudChpbnB1dCkubG9jYWwoKSxcbiAgICAgICAgICAgICAgICB6b25lRGlmZiA9ICh0aGlzLnpvbmUoKSAtIHRoYXQuem9uZSgpKSAqIDZlNCxcbiAgICAgICAgICAgICAgICBkaWZmLCBvdXRwdXQ7XG5cbiAgICAgICAgICAgIHVuaXRzID0gbm9ybWFsaXplVW5pdHModW5pdHMpO1xuXG4gICAgICAgICAgICBpZiAodW5pdHMgPT09ICd5ZWFyJyB8fCB1bml0cyA9PT0gJ21vbnRoJykge1xuICAgICAgICAgICAgICAgIC8vIGF2ZXJhZ2UgbnVtYmVyIG9mIGRheXMgaW4gdGhlIG1vbnRocyBpbiB0aGUgZ2l2ZW4gZGF0ZXNcbiAgICAgICAgICAgICAgICBkaWZmID0gKHRoaXMuZGF5c0luTW9udGgoKSArIHRoYXQuZGF5c0luTW9udGgoKSkgKiA0MzJlNTsgLy8gMjQgKiA2MCAqIDYwICogMTAwMCAvIDJcbiAgICAgICAgICAgICAgICAvLyBkaWZmZXJlbmNlIGluIG1vbnRoc1xuICAgICAgICAgICAgICAgIG91dHB1dCA9ICgodGhpcy55ZWFyKCkgLSB0aGF0LnllYXIoKSkgKiAxMikgKyAodGhpcy5tb250aCgpIC0gdGhhdC5tb250aCgpKTtcbiAgICAgICAgICAgICAgICAvLyBhZGp1c3QgYnkgdGFraW5nIGRpZmZlcmVuY2UgaW4gZGF5cywgYXZlcmFnZSBudW1iZXIgb2YgZGF5c1xuICAgICAgICAgICAgICAgIC8vIGFuZCBkc3QgaW4gdGhlIGdpdmVuIG1vbnRocy5cbiAgICAgICAgICAgICAgICBvdXRwdXQgKz0gKCh0aGlzIC0gbW9tZW50KHRoaXMpLnN0YXJ0T2YoJ21vbnRoJykpIC1cbiAgICAgICAgICAgICAgICAgICAgICAgICh0aGF0IC0gbW9tZW50KHRoYXQpLnN0YXJ0T2YoJ21vbnRoJykpKSAvIGRpZmY7XG4gICAgICAgICAgICAgICAgLy8gc2FtZSBhcyBhYm92ZSBidXQgd2l0aCB6b25lcywgdG8gbmVnYXRlIGFsbCBkc3RcbiAgICAgICAgICAgICAgICBvdXRwdXQgLT0gKCh0aGlzLnpvbmUoKSAtIG1vbWVudCh0aGlzKS5zdGFydE9mKCdtb250aCcpLnpvbmUoKSkgLVxuICAgICAgICAgICAgICAgICAgICAgICAgKHRoYXQuem9uZSgpIC0gbW9tZW50KHRoYXQpLnN0YXJ0T2YoJ21vbnRoJykuem9uZSgpKSkgKiA2ZTQgLyBkaWZmO1xuICAgICAgICAgICAgICAgIGlmICh1bml0cyA9PT0gJ3llYXInKSB7XG4gICAgICAgICAgICAgICAgICAgIG91dHB1dCA9IG91dHB1dCAvIDEyO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgZGlmZiA9ICh0aGlzIC0gdGhhdCk7XG4gICAgICAgICAgICAgICAgb3V0cHV0ID0gdW5pdHMgPT09ICdzZWNvbmQnID8gZGlmZiAvIDFlMyA6IC8vIDEwMDBcbiAgICAgICAgICAgICAgICAgICAgdW5pdHMgPT09ICdtaW51dGUnID8gZGlmZiAvIDZlNCA6IC8vIDEwMDAgKiA2MFxuICAgICAgICAgICAgICAgICAgICB1bml0cyA9PT0gJ2hvdXInID8gZGlmZiAvIDM2ZTUgOiAvLyAxMDAwICogNjAgKiA2MFxuICAgICAgICAgICAgICAgICAgICB1bml0cyA9PT0gJ2RheScgPyAoZGlmZiAtIHpvbmVEaWZmKSAvIDg2NGU1IDogLy8gMTAwMCAqIDYwICogNjAgKiAyNCwgbmVnYXRlIGRzdFxuICAgICAgICAgICAgICAgICAgICB1bml0cyA9PT0gJ3dlZWsnID8gKGRpZmYgLSB6b25lRGlmZikgLyA2MDQ4ZTUgOiAvLyAxMDAwICogNjAgKiA2MCAqIDI0ICogNywgbmVnYXRlIGRzdFxuICAgICAgICAgICAgICAgICAgICBkaWZmO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGFzRmxvYXQgPyBvdXRwdXQgOiBhYnNSb3VuZChvdXRwdXQpO1xuICAgICAgICB9LFxuXG4gICAgICAgIGZyb20gOiBmdW5jdGlvbiAodGltZSwgd2l0aG91dFN1ZmZpeCkge1xuICAgICAgICAgICAgcmV0dXJuIG1vbWVudC5kdXJhdGlvbih0aGlzLmRpZmYodGltZSkpLmxhbmcodGhpcy5sYW5nKCkuX2FiYnIpLmh1bWFuaXplKCF3aXRob3V0U3VmZml4KTtcbiAgICAgICAgfSxcblxuICAgICAgICBmcm9tTm93IDogZnVuY3Rpb24gKHdpdGhvdXRTdWZmaXgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmZyb20obW9tZW50KCksIHdpdGhvdXRTdWZmaXgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIGNhbGVuZGFyIDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGRpZmYgPSB0aGlzLmRpZmYobW9tZW50KCkuc3RhcnRPZignZGF5JyksICdkYXlzJywgdHJ1ZSksXG4gICAgICAgICAgICAgICAgZm9ybWF0ID0gZGlmZiA8IC02ID8gJ3NhbWVFbHNlJyA6XG4gICAgICAgICAgICAgICAgZGlmZiA8IC0xID8gJ2xhc3RXZWVrJyA6XG4gICAgICAgICAgICAgICAgZGlmZiA8IDAgPyAnbGFzdERheScgOlxuICAgICAgICAgICAgICAgIGRpZmYgPCAxID8gJ3NhbWVEYXknIDpcbiAgICAgICAgICAgICAgICBkaWZmIDwgMiA/ICduZXh0RGF5JyA6XG4gICAgICAgICAgICAgICAgZGlmZiA8IDcgPyAnbmV4dFdlZWsnIDogJ3NhbWVFbHNlJztcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmZvcm1hdCh0aGlzLmxhbmcoKS5jYWxlbmRhcihmb3JtYXQsIHRoaXMpKTtcbiAgICAgICAgfSxcblxuICAgICAgICBpc0xlYXBZZWFyIDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHllYXIgPSB0aGlzLnllYXIoKTtcbiAgICAgICAgICAgIHJldHVybiAoeWVhciAlIDQgPT09IDAgJiYgeWVhciAlIDEwMCAhPT0gMCkgfHwgeWVhciAlIDQwMCA9PT0gMDtcbiAgICAgICAgfSxcblxuICAgICAgICBpc0RTVCA6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiAodGhpcy56b25lKCkgPCB0aGlzLmNsb25lKCkubW9udGgoMCkuem9uZSgpIHx8XG4gICAgICAgICAgICAgICAgdGhpcy56b25lKCkgPCB0aGlzLmNsb25lKCkubW9udGgoNSkuem9uZSgpKTtcbiAgICAgICAgfSxcblxuICAgICAgICBkYXkgOiBmdW5jdGlvbiAoaW5wdXQpIHtcbiAgICAgICAgICAgIHZhciBkYXkgPSB0aGlzLl9pc1VUQyA/IHRoaXMuX2QuZ2V0VVRDRGF5KCkgOiB0aGlzLl9kLmdldERheSgpO1xuICAgICAgICAgICAgaWYgKGlucHV0ICE9IG51bGwpIHtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIGlucHV0ID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICAgICAgICBpbnB1dCA9IHRoaXMubGFuZygpLndlZWtkYXlzUGFyc2UoaW5wdXQpO1xuICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIGlucHV0ICE9PSAnbnVtYmVyJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuYWRkKHsgZCA6IGlucHV0IC0gZGF5IH0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZGF5O1xuICAgICAgICAgICAgfVxuICAgICAgICB9LFxuXG4gICAgICAgIG1vbnRoIDogZnVuY3Rpb24gKGlucHV0KSB7XG4gICAgICAgICAgICB2YXIgdXRjID0gdGhpcy5faXNVVEMgPyAnVVRDJyA6ICcnLFxuICAgICAgICAgICAgICAgIGRheU9mTW9udGgsXG4gICAgICAgICAgICAgICAgZGF5c0luTW9udGg7XG5cbiAgICAgICAgICAgIGlmIChpbnB1dCAhPSBudWxsKSB7XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBpbnB1dCA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICAgICAgaW5wdXQgPSB0aGlzLmxhbmcoKS5tb250aHNQYXJzZShpbnB1dCk7XG4gICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgaW5wdXQgIT09ICdudW1iZXInKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGRheU9mTW9udGggPSB0aGlzLmRhdGUoKTtcbiAgICAgICAgICAgICAgICB0aGlzLmRhdGUoMSk7XG4gICAgICAgICAgICAgICAgdGhpcy5fZFsnc2V0JyArIHV0YyArICdNb250aCddKGlucHV0KTtcbiAgICAgICAgICAgICAgICB0aGlzLmRhdGUoTWF0aC5taW4oZGF5T2ZNb250aCwgdGhpcy5kYXlzSW5Nb250aCgpKSk7XG5cbiAgICAgICAgICAgICAgICBtb21lbnQudXBkYXRlT2Zmc2V0KHRoaXMpO1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5fZFsnZ2V0JyArIHV0YyArICdNb250aCddKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG5cbiAgICAgICAgc3RhcnRPZjogZnVuY3Rpb24gKHVuaXRzKSB7XG4gICAgICAgICAgICB1bml0cyA9IG5vcm1hbGl6ZVVuaXRzKHVuaXRzKTtcbiAgICAgICAgICAgIC8vIHRoZSBmb2xsb3dpbmcgc3dpdGNoIGludGVudGlvbmFsbHkgb21pdHMgYnJlYWsga2V5d29yZHNcbiAgICAgICAgICAgIC8vIHRvIHV0aWxpemUgZmFsbGluZyB0aHJvdWdoIHRoZSBjYXNlcy5cbiAgICAgICAgICAgIHN3aXRjaCAodW5pdHMpIHtcbiAgICAgICAgICAgIGNhc2UgJ3llYXInOlxuICAgICAgICAgICAgICAgIHRoaXMubW9udGgoMCk7XG4gICAgICAgICAgICAgICAgLyogZmFsbHMgdGhyb3VnaCAqL1xuICAgICAgICAgICAgY2FzZSAnbW9udGgnOlxuICAgICAgICAgICAgICAgIHRoaXMuZGF0ZSgxKTtcbiAgICAgICAgICAgICAgICAvKiBmYWxscyB0aHJvdWdoICovXG4gICAgICAgICAgICBjYXNlICd3ZWVrJzpcbiAgICAgICAgICAgIGNhc2UgJ2RheSc6XG4gICAgICAgICAgICAgICAgdGhpcy5ob3VycygwKTtcbiAgICAgICAgICAgICAgICAvKiBmYWxscyB0aHJvdWdoICovXG4gICAgICAgICAgICBjYXNlICdob3VyJzpcbiAgICAgICAgICAgICAgICB0aGlzLm1pbnV0ZXMoMCk7XG4gICAgICAgICAgICAgICAgLyogZmFsbHMgdGhyb3VnaCAqL1xuICAgICAgICAgICAgY2FzZSAnbWludXRlJzpcbiAgICAgICAgICAgICAgICB0aGlzLnNlY29uZHMoMCk7XG4gICAgICAgICAgICAgICAgLyogZmFsbHMgdGhyb3VnaCAqL1xuICAgICAgICAgICAgY2FzZSAnc2Vjb25kJzpcbiAgICAgICAgICAgICAgICB0aGlzLm1pbGxpc2Vjb25kcygwKTtcbiAgICAgICAgICAgICAgICAvKiBmYWxscyB0aHJvdWdoICovXG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIHdlZWtzIGFyZSBhIHNwZWNpYWwgY2FzZVxuICAgICAgICAgICAgaWYgKHVuaXRzID09PSAnd2VlaycpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndlZWtkYXkoMCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9LFxuXG4gICAgICAgIGVuZE9mOiBmdW5jdGlvbiAodW5pdHMpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnN0YXJ0T2YodW5pdHMpLmFkZCh1bml0cywgMSkuc3VidHJhY3QoJ21zJywgMSk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgaXNBZnRlcjogZnVuY3Rpb24gKGlucHV0LCB1bml0cykge1xuICAgICAgICAgICAgdW5pdHMgPSB0eXBlb2YgdW5pdHMgIT09ICd1bmRlZmluZWQnID8gdW5pdHMgOiAnbWlsbGlzZWNvbmQnO1xuICAgICAgICAgICAgcmV0dXJuICt0aGlzLmNsb25lKCkuc3RhcnRPZih1bml0cykgPiArbW9tZW50KGlucHV0KS5zdGFydE9mKHVuaXRzKTtcbiAgICAgICAgfSxcblxuICAgICAgICBpc0JlZm9yZTogZnVuY3Rpb24gKGlucHV0LCB1bml0cykge1xuICAgICAgICAgICAgdW5pdHMgPSB0eXBlb2YgdW5pdHMgIT09ICd1bmRlZmluZWQnID8gdW5pdHMgOiAnbWlsbGlzZWNvbmQnO1xuICAgICAgICAgICAgcmV0dXJuICt0aGlzLmNsb25lKCkuc3RhcnRPZih1bml0cykgPCArbW9tZW50KGlucHV0KS5zdGFydE9mKHVuaXRzKTtcbiAgICAgICAgfSxcblxuICAgICAgICBpc1NhbWU6IGZ1bmN0aW9uIChpbnB1dCwgdW5pdHMpIHtcbiAgICAgICAgICAgIHVuaXRzID0gdHlwZW9mIHVuaXRzICE9PSAndW5kZWZpbmVkJyA/IHVuaXRzIDogJ21pbGxpc2Vjb25kJztcbiAgICAgICAgICAgIHJldHVybiArdGhpcy5jbG9uZSgpLnN0YXJ0T2YodW5pdHMpID09PSArbW9tZW50KGlucHV0KS5zdGFydE9mKHVuaXRzKTtcbiAgICAgICAgfSxcblxuICAgICAgICBtaW46IGZ1bmN0aW9uIChvdGhlcikge1xuICAgICAgICAgICAgb3RoZXIgPSBtb21lbnQuYXBwbHkobnVsbCwgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIHJldHVybiBvdGhlciA8IHRoaXMgPyB0aGlzIDogb3RoZXI7XG4gICAgICAgIH0sXG5cbiAgICAgICAgbWF4OiBmdW5jdGlvbiAob3RoZXIpIHtcbiAgICAgICAgICAgIG90aGVyID0gbW9tZW50LmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICByZXR1cm4gb3RoZXIgPiB0aGlzID8gdGhpcyA6IG90aGVyO1xuICAgICAgICB9LFxuXG4gICAgICAgIHpvbmUgOiBmdW5jdGlvbiAoaW5wdXQpIHtcbiAgICAgICAgICAgIHZhciBvZmZzZXQgPSB0aGlzLl9vZmZzZXQgfHwgMDtcbiAgICAgICAgICAgIGlmIChpbnB1dCAhPSBudWxsKSB7XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBpbnB1dCA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgICAgICAgICBpbnB1dCA9IHRpbWV6b25lTWludXRlc0Zyb21TdHJpbmcoaW5wdXQpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoTWF0aC5hYnMoaW5wdXQpIDwgMTYpIHtcbiAgICAgICAgICAgICAgICAgICAgaW5wdXQgPSBpbnB1dCAqIDYwO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB0aGlzLl9vZmZzZXQgPSBpbnB1dDtcbiAgICAgICAgICAgICAgICB0aGlzLl9pc1VUQyA9IHRydWU7XG4gICAgICAgICAgICAgICAgaWYgKG9mZnNldCAhPT0gaW5wdXQpIHtcbiAgICAgICAgICAgICAgICAgICAgYWRkT3JTdWJ0cmFjdER1cmF0aW9uRnJvbU1vbWVudCh0aGlzLCBtb21lbnQuZHVyYXRpb24ob2Zmc2V0IC0gaW5wdXQsICdtJyksIDEsIHRydWUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2lzVVRDID8gb2Zmc2V0IDogdGhpcy5fZC5nZXRUaW1lem9uZU9mZnNldCgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH0sXG5cbiAgICAgICAgem9uZUFiYnIgOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5faXNVVEMgPyBcIlVUQ1wiIDogXCJcIjtcbiAgICAgICAgfSxcblxuICAgICAgICB6b25lTmFtZSA6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9pc1VUQyA/IFwiQ29vcmRpbmF0ZWQgVW5pdmVyc2FsIFRpbWVcIiA6IFwiXCI7XG4gICAgICAgIH0sXG5cbiAgICAgICAgZGF5c0luTW9udGggOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gbW9tZW50LnV0YyhbdGhpcy55ZWFyKCksIHRoaXMubW9udGgoKSArIDEsIDBdKS5kYXRlKCk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgZGF5T2ZZZWFyIDogZnVuY3Rpb24gKGlucHV0KSB7XG4gICAgICAgICAgICB2YXIgZGF5T2ZZZWFyID0gcm91bmQoKG1vbWVudCh0aGlzKS5zdGFydE9mKCdkYXknKSAtIG1vbWVudCh0aGlzKS5zdGFydE9mKCd5ZWFyJykpIC8gODY0ZTUpICsgMTtcbiAgICAgICAgICAgIHJldHVybiBpbnB1dCA9PSBudWxsID8gZGF5T2ZZZWFyIDogdGhpcy5hZGQoXCJkXCIsIChpbnB1dCAtIGRheU9mWWVhcikpO1xuICAgICAgICB9LFxuXG4gICAgICAgIHdlZWtZZWFyIDogZnVuY3Rpb24gKGlucHV0KSB7XG4gICAgICAgICAgICB2YXIgeWVhciA9IHdlZWtPZlllYXIodGhpcywgdGhpcy5sYW5nKCkuX3dlZWsuZG93LCB0aGlzLmxhbmcoKS5fd2Vlay5kb3kpLnllYXI7XG4gICAgICAgICAgICByZXR1cm4gaW5wdXQgPT0gbnVsbCA/IHllYXIgOiB0aGlzLmFkZChcInlcIiwgKGlucHV0IC0geWVhcikpO1xuICAgICAgICB9LFxuXG4gICAgICAgIGlzb1dlZWtZZWFyIDogZnVuY3Rpb24gKGlucHV0KSB7XG4gICAgICAgICAgICB2YXIgeWVhciA9IHdlZWtPZlllYXIodGhpcywgMSwgNCkueWVhcjtcbiAgICAgICAgICAgIHJldHVybiBpbnB1dCA9PSBudWxsID8geWVhciA6IHRoaXMuYWRkKFwieVwiLCAoaW5wdXQgLSB5ZWFyKSk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgd2VlayA6IGZ1bmN0aW9uIChpbnB1dCkge1xuICAgICAgICAgICAgdmFyIHdlZWsgPSB0aGlzLmxhbmcoKS53ZWVrKHRoaXMpO1xuICAgICAgICAgICAgcmV0dXJuIGlucHV0ID09IG51bGwgPyB3ZWVrIDogdGhpcy5hZGQoXCJkXCIsIChpbnB1dCAtIHdlZWspICogNyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgaXNvV2VlayA6IGZ1bmN0aW9uIChpbnB1dCkge1xuICAgICAgICAgICAgdmFyIHdlZWsgPSB3ZWVrT2ZZZWFyKHRoaXMsIDEsIDQpLndlZWs7XG4gICAgICAgICAgICByZXR1cm4gaW5wdXQgPT0gbnVsbCA/IHdlZWsgOiB0aGlzLmFkZChcImRcIiwgKGlucHV0IC0gd2VlaykgKiA3KTtcbiAgICAgICAgfSxcblxuICAgICAgICB3ZWVrZGF5IDogZnVuY3Rpb24gKGlucHV0KSB7XG4gICAgICAgICAgICB2YXIgd2Vla2RheSA9ICh0aGlzLl9kLmdldERheSgpICsgNyAtIHRoaXMubGFuZygpLl93ZWVrLmRvdykgJSA3O1xuICAgICAgICAgICAgcmV0dXJuIGlucHV0ID09IG51bGwgPyB3ZWVrZGF5IDogdGhpcy5hZGQoXCJkXCIsIGlucHV0IC0gd2Vla2RheSk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgaXNvV2Vla2RheSA6IGZ1bmN0aW9uIChpbnB1dCkge1xuICAgICAgICAgICAgLy8gYmVoYXZlcyB0aGUgc2FtZSBhcyBtb21lbnQjZGF5IGV4Y2VwdFxuICAgICAgICAgICAgLy8gYXMgYSBnZXR0ZXIsIHJldHVybnMgNyBpbnN0ZWFkIG9mIDAgKDEtNyByYW5nZSBpbnN0ZWFkIG9mIDAtNilcbiAgICAgICAgICAgIC8vIGFzIGEgc2V0dGVyLCBzdW5kYXkgc2hvdWxkIGJlbG9uZyB0byB0aGUgcHJldmlvdXMgd2Vlay5cbiAgICAgICAgICAgIHJldHVybiBpbnB1dCA9PSBudWxsID8gdGhpcy5kYXkoKSB8fCA3IDogdGhpcy5kYXkodGhpcy5kYXkoKSAlIDcgPyBpbnB1dCA6IGlucHV0IC0gNyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLy8gSWYgcGFzc2VkIGEgbGFuZ3VhZ2Uga2V5LCBpdCB3aWxsIHNldCB0aGUgbGFuZ3VhZ2UgZm9yIHRoaXNcbiAgICAgICAgLy8gaW5zdGFuY2UuICBPdGhlcndpc2UsIGl0IHdpbGwgcmV0dXJuIHRoZSBsYW5ndWFnZSBjb25maWd1cmF0aW9uXG4gICAgICAgIC8vIHZhcmlhYmxlcyBmb3IgdGhpcyBpbnN0YW5jZS5cbiAgICAgICAgbGFuZyA6IGZ1bmN0aW9uIChrZXkpIHtcbiAgICAgICAgICAgIGlmIChrZXkgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLl9sYW5nO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLl9sYW5nID0gZ2V0TGFuZ0RlZmluaXRpb24oa2V5KTtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvLyBoZWxwZXIgZm9yIGFkZGluZyBzaG9ydGN1dHNcbiAgICBmdW5jdGlvbiBtYWtlR2V0dGVyQW5kU2V0dGVyKG5hbWUsIGtleSkge1xuICAgICAgICBtb21lbnQuZm5bbmFtZV0gPSBtb21lbnQuZm5bbmFtZSArICdzJ10gPSBmdW5jdGlvbiAoaW5wdXQpIHtcbiAgICAgICAgICAgIHZhciB1dGMgPSB0aGlzLl9pc1VUQyA/ICdVVEMnIDogJyc7XG4gICAgICAgICAgICBpZiAoaW5wdXQgIT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIHRoaXMuX2RbJ3NldCcgKyB1dGMgKyBrZXldKGlucHV0KTtcbiAgICAgICAgICAgICAgICBtb21lbnQudXBkYXRlT2Zmc2V0KHRoaXMpO1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5fZFsnZ2V0JyArIHV0YyArIGtleV0oKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICAvLyBsb29wIHRocm91Z2ggYW5kIGFkZCBzaG9ydGN1dHMgKE1vbnRoLCBEYXRlLCBIb3VycywgTWludXRlcywgU2Vjb25kcywgTWlsbGlzZWNvbmRzKVxuICAgIGZvciAoaSA9IDA7IGkgPCBwcm94eUdldHRlcnNBbmRTZXR0ZXJzLmxlbmd0aDsgaSArKykge1xuICAgICAgICBtYWtlR2V0dGVyQW5kU2V0dGVyKHByb3h5R2V0dGVyc0FuZFNldHRlcnNbaV0udG9Mb3dlckNhc2UoKS5yZXBsYWNlKC9zJC8sICcnKSwgcHJveHlHZXR0ZXJzQW5kU2V0dGVyc1tpXSk7XG4gICAgfVxuXG4gICAgLy8gYWRkIHNob3J0Y3V0IGZvciB5ZWFyICh1c2VzIGRpZmZlcmVudCBzeW50YXggdGhhbiB0aGUgZ2V0dGVyL3NldHRlciAneWVhcicgPT0gJ0Z1bGxZZWFyJylcbiAgICBtYWtlR2V0dGVyQW5kU2V0dGVyKCd5ZWFyJywgJ0Z1bGxZZWFyJyk7XG5cbiAgICAvLyBhZGQgcGx1cmFsIG1ldGhvZHNcbiAgICBtb21lbnQuZm4uZGF5cyA9IG1vbWVudC5mbi5kYXk7XG4gICAgbW9tZW50LmZuLm1vbnRocyA9IG1vbWVudC5mbi5tb250aDtcbiAgICBtb21lbnQuZm4ud2Vla3MgPSBtb21lbnQuZm4ud2VlaztcbiAgICBtb21lbnQuZm4uaXNvV2Vla3MgPSBtb21lbnQuZm4uaXNvV2VlaztcblxuICAgIC8vIGFkZCBhbGlhc2VkIGZvcm1hdCBtZXRob2RzXG4gICAgbW9tZW50LmZuLnRvSlNPTiA9IG1vbWVudC5mbi50b0lTT1N0cmluZztcblxuICAgIC8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcbiAgICAgICAgRHVyYXRpb24gUHJvdG90eXBlXG4gICAgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5cbiAgICBtb21lbnQuZHVyYXRpb24uZm4gPSBEdXJhdGlvbi5wcm90b3R5cGUgPSB7XG4gICAgICAgIF9idWJibGUgOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgbWlsbGlzZWNvbmRzID0gdGhpcy5fbWlsbGlzZWNvbmRzLFxuICAgICAgICAgICAgICAgIGRheXMgPSB0aGlzLl9kYXlzLFxuICAgICAgICAgICAgICAgIG1vbnRocyA9IHRoaXMuX21vbnRocyxcbiAgICAgICAgICAgICAgICBkYXRhID0gdGhpcy5fZGF0YSxcbiAgICAgICAgICAgICAgICBzZWNvbmRzLCBtaW51dGVzLCBob3VycywgeWVhcnM7XG5cbiAgICAgICAgICAgIC8vIFRoZSBmb2xsb3dpbmcgY29kZSBidWJibGVzIHVwIHZhbHVlcywgc2VlIHRoZSB0ZXN0cyBmb3JcbiAgICAgICAgICAgIC8vIGV4YW1wbGVzIG9mIHdoYXQgdGhhdCBtZWFucy5cbiAgICAgICAgICAgIGRhdGEubWlsbGlzZWNvbmRzID0gbWlsbGlzZWNvbmRzICUgMTAwMDtcblxuICAgICAgICAgICAgc2Vjb25kcyA9IGFic1JvdW5kKG1pbGxpc2Vjb25kcyAvIDEwMDApO1xuICAgICAgICAgICAgZGF0YS5zZWNvbmRzID0gc2Vjb25kcyAlIDYwO1xuXG4gICAgICAgICAgICBtaW51dGVzID0gYWJzUm91bmQoc2Vjb25kcyAvIDYwKTtcbiAgICAgICAgICAgIGRhdGEubWludXRlcyA9IG1pbnV0ZXMgJSA2MDtcblxuICAgICAgICAgICAgaG91cnMgPSBhYnNSb3VuZChtaW51dGVzIC8gNjApO1xuICAgICAgICAgICAgZGF0YS5ob3VycyA9IGhvdXJzICUgMjQ7XG5cbiAgICAgICAgICAgIGRheXMgKz0gYWJzUm91bmQoaG91cnMgLyAyNCk7XG4gICAgICAgICAgICBkYXRhLmRheXMgPSBkYXlzICUgMzA7XG5cbiAgICAgICAgICAgIG1vbnRocyArPSBhYnNSb3VuZChkYXlzIC8gMzApO1xuICAgICAgICAgICAgZGF0YS5tb250aHMgPSBtb250aHMgJSAxMjtcblxuICAgICAgICAgICAgeWVhcnMgPSBhYnNSb3VuZChtb250aHMgLyAxMik7XG4gICAgICAgICAgICBkYXRhLnllYXJzID0geWVhcnM7XG4gICAgICAgIH0sXG5cbiAgICAgICAgd2Vla3MgOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gYWJzUm91bmQodGhpcy5kYXlzKCkgLyA3KTtcbiAgICAgICAgfSxcblxuICAgICAgICB2YWx1ZU9mIDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX21pbGxpc2Vjb25kcyArXG4gICAgICAgICAgICAgIHRoaXMuX2RheXMgKiA4NjRlNSArXG4gICAgICAgICAgICAgICh0aGlzLl9tb250aHMgJSAxMikgKiAyNTkyZTYgK1xuICAgICAgICAgICAgICB+fih0aGlzLl9tb250aHMgLyAxMikgKiAzMTUzNmU2O1xuICAgICAgICB9LFxuXG4gICAgICAgIGh1bWFuaXplIDogZnVuY3Rpb24gKHdpdGhTdWZmaXgpIHtcbiAgICAgICAgICAgIHZhciBkaWZmZXJlbmNlID0gK3RoaXMsXG4gICAgICAgICAgICAgICAgb3V0cHV0ID0gcmVsYXRpdmVUaW1lKGRpZmZlcmVuY2UsICF3aXRoU3VmZml4LCB0aGlzLmxhbmcoKSk7XG5cbiAgICAgICAgICAgIGlmICh3aXRoU3VmZml4KSB7XG4gICAgICAgICAgICAgICAgb3V0cHV0ID0gdGhpcy5sYW5nKCkucGFzdEZ1dHVyZShkaWZmZXJlbmNlLCBvdXRwdXQpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5sYW5nKCkucG9zdGZvcm1hdChvdXRwdXQpO1xuICAgICAgICB9LFxuXG4gICAgICAgIGFkZCA6IGZ1bmN0aW9uIChpbnB1dCwgdmFsKSB7XG4gICAgICAgICAgICAvLyBzdXBwb3J0cyBvbmx5IDIuMC1zdHlsZSBhZGQoMSwgJ3MnKSBvciBhZGQobW9tZW50KVxuICAgICAgICAgICAgdmFyIGR1ciA9IG1vbWVudC5kdXJhdGlvbihpbnB1dCwgdmFsKTtcblxuICAgICAgICAgICAgdGhpcy5fbWlsbGlzZWNvbmRzICs9IGR1ci5fbWlsbGlzZWNvbmRzO1xuICAgICAgICAgICAgdGhpcy5fZGF5cyArPSBkdXIuX2RheXM7XG4gICAgICAgICAgICB0aGlzLl9tb250aHMgKz0gZHVyLl9tb250aHM7XG5cbiAgICAgICAgICAgIHRoaXMuX2J1YmJsZSgpO1xuXG4gICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfSxcblxuICAgICAgICBzdWJ0cmFjdCA6IGZ1bmN0aW9uIChpbnB1dCwgdmFsKSB7XG4gICAgICAgICAgICB2YXIgZHVyID0gbW9tZW50LmR1cmF0aW9uKGlucHV0LCB2YWwpO1xuXG4gICAgICAgICAgICB0aGlzLl9taWxsaXNlY29uZHMgLT0gZHVyLl9taWxsaXNlY29uZHM7XG4gICAgICAgICAgICB0aGlzLl9kYXlzIC09IGR1ci5fZGF5cztcbiAgICAgICAgICAgIHRoaXMuX21vbnRocyAtPSBkdXIuX21vbnRocztcblxuICAgICAgICAgICAgdGhpcy5fYnViYmxlKCk7XG5cbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9LFxuXG4gICAgICAgIGdldCA6IGZ1bmN0aW9uICh1bml0cykge1xuICAgICAgICAgICAgdW5pdHMgPSBub3JtYWxpemVVbml0cyh1bml0cyk7XG4gICAgICAgICAgICByZXR1cm4gdGhpc1t1bml0cy50b0xvd2VyQ2FzZSgpICsgJ3MnXSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIGFzIDogZnVuY3Rpb24gKHVuaXRzKSB7XG4gICAgICAgICAgICB1bml0cyA9IG5vcm1hbGl6ZVVuaXRzKHVuaXRzKTtcbiAgICAgICAgICAgIHJldHVybiB0aGlzWydhcycgKyB1bml0cy5jaGFyQXQoMCkudG9VcHBlckNhc2UoKSArIHVuaXRzLnNsaWNlKDEpICsgJ3MnXSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIGxhbmcgOiBtb21lbnQuZm4ubGFuZ1xuICAgIH07XG5cbiAgICBmdW5jdGlvbiBtYWtlRHVyYXRpb25HZXR0ZXIobmFtZSkge1xuICAgICAgICBtb21lbnQuZHVyYXRpb24uZm5bbmFtZV0gPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fZGF0YVtuYW1lXTtcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBtYWtlRHVyYXRpb25Bc0dldHRlcihuYW1lLCBmYWN0b3IpIHtcbiAgICAgICAgbW9tZW50LmR1cmF0aW9uLmZuWydhcycgKyBuYW1lXSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiArdGhpcyAvIGZhY3RvcjtcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBmb3IgKGkgaW4gdW5pdE1pbGxpc2Vjb25kRmFjdG9ycykge1xuICAgICAgICBpZiAodW5pdE1pbGxpc2Vjb25kRmFjdG9ycy5oYXNPd25Qcm9wZXJ0eShpKSkge1xuICAgICAgICAgICAgbWFrZUR1cmF0aW9uQXNHZXR0ZXIoaSwgdW5pdE1pbGxpc2Vjb25kRmFjdG9yc1tpXSk7XG4gICAgICAgICAgICBtYWtlRHVyYXRpb25HZXR0ZXIoaS50b0xvd2VyQ2FzZSgpKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIG1ha2VEdXJhdGlvbkFzR2V0dGVyKCdXZWVrcycsIDYwNDhlNSk7XG4gICAgbW9tZW50LmR1cmF0aW9uLmZuLmFzTW9udGhzID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gKCt0aGlzIC0gdGhpcy55ZWFycygpICogMzE1MzZlNikgLyAyNTkyZTYgKyB0aGlzLnllYXJzKCkgKiAxMjtcbiAgICB9O1xuXG5cbiAgICAvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG4gICAgICAgIERlZmF1bHQgTGFuZ1xuICAgICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuXG4gICAgLy8gU2V0IGRlZmF1bHQgbGFuZ3VhZ2UsIG90aGVyIGxhbmd1YWdlcyB3aWxsIGluaGVyaXQgZnJvbSBFbmdsaXNoLlxuICAgIG1vbWVudC5sYW5nKCdlbicsIHtcbiAgICAgICAgb3JkaW5hbCA6IGZ1bmN0aW9uIChudW1iZXIpIHtcbiAgICAgICAgICAgIHZhciBiID0gbnVtYmVyICUgMTAsXG4gICAgICAgICAgICAgICAgb3V0cHV0ID0gKH5+IChudW1iZXIgJSAxMDAgLyAxMCkgPT09IDEpID8gJ3RoJyA6XG4gICAgICAgICAgICAgICAgKGIgPT09IDEpID8gJ3N0JyA6XG4gICAgICAgICAgICAgICAgKGIgPT09IDIpID8gJ25kJyA6XG4gICAgICAgICAgICAgICAgKGIgPT09IDMpID8gJ3JkJyA6ICd0aCc7XG4gICAgICAgICAgICByZXR1cm4gbnVtYmVyICsgb3V0cHV0O1xuICAgICAgICB9XG4gICAgfSk7XG5cblxuICAgIC8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcbiAgICAgICAgRXhwb3NpbmcgTW9tZW50XG4gICAgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5cbiAgICAvLyBDb21tb25KUyBtb2R1bGUgaXMgZGVmaW5lZFxuICAgIGlmIChoYXNNb2R1bGUpIHtcbiAgICAgICAgbW9kdWxlLmV4cG9ydHMgPSBtb21lbnQ7XG4gICAgfVxuICAgIC8qZ2xvYmFsIGVuZGVyOmZhbHNlICovXG4gICAgaWYgKHR5cGVvZiBlbmRlciA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgLy8gaGVyZSwgYHRoaXNgIG1lYW5zIGB3aW5kb3dgIGluIHRoZSBicm93c2VyLCBvciBgZ2xvYmFsYCBvbiB0aGUgc2VydmVyXG4gICAgICAgIC8vIGFkZCBgbW9tZW50YCBhcyBhIGdsb2JhbCBvYmplY3QgdmlhIGEgc3RyaW5nIGlkZW50aWZpZXIsXG4gICAgICAgIC8vIGZvciBDbG9zdXJlIENvbXBpbGVyIFwiYWR2YW5jZWRcIiBtb2RlXG4gICAgICAgIHRoaXNbJ21vbWVudCddID0gbW9tZW50O1xuICAgIH1cbiAgICAvKmdsb2JhbCBkZWZpbmU6ZmFsc2UgKi9cbiAgICBpZiAodHlwZW9mIGRlZmluZSA9PT0gXCJmdW5jdGlvblwiICYmIGRlZmluZS5hbWQpIHtcbiAgICAgICAgZGVmaW5lKFwibW9tZW50XCIsIFtdLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gbW9tZW50O1xuICAgICAgICB9KTtcbiAgICB9XG59KS5jYWxsKHRoaXMpO1xuIiwidmFyIHJlbGF0aXZlRGF0ZSA9IChmdW5jdGlvbih1bmRlZmluZWQpe1xuXG4gIHZhciBTRUNPTkQgPSAxMDAwLFxuICAgICAgTUlOVVRFID0gNjAgKiBTRUNPTkQsXG4gICAgICBIT1VSID0gNjAgKiBNSU5VVEUsXG4gICAgICBEQVkgPSAyNCAqIEhPVVIsXG4gICAgICBXRUVLID0gNyAqIERBWSxcbiAgICAgIFlFQVIgPSBEQVkgKiAzNjUsXG4gICAgICBNT05USCA9IFlFQVIgLyAxMjtcblxuICB2YXIgZm9ybWF0cyA9IFtcbiAgICBbIDAuNyAqIE1JTlVURSwgJ2p1c3Qgbm93JyBdLFxuICAgIFsgMS41ICogTUlOVVRFLCAnYSBtaW51dGUgYWdvJyBdLFxuICAgIFsgNjAgKiBNSU5VVEUsICdtaW51dGVzIGFnbycsIE1JTlVURSBdLFxuICAgIFsgMS41ICogSE9VUiwgJ2FuIGhvdXIgYWdvJyBdLFxuICAgIFsgREFZLCAnaG91cnMgYWdvJywgSE9VUiBdLFxuICAgIFsgMiAqIERBWSwgJ3llc3RlcmRheScgXSxcbiAgICBbIDcgKiBEQVksICdkYXlzIGFnbycsIERBWSBdLFxuICAgIFsgMS41ICogV0VFSywgJ2Egd2VlayBhZ28nXSxcbiAgICBbIE1PTlRILCAnd2Vla3MgYWdvJywgV0VFSyBdLFxuICAgIFsgMS41ICogTU9OVEgsICdhIG1vbnRoIGFnbycgXSxcbiAgICBbIFlFQVIsICdtb250aHMgYWdvJywgTU9OVEggXSxcbiAgICBbIDEuNSAqIFlFQVIsICdhIHllYXIgYWdvJyBdLFxuICAgIFsgTnVtYmVyLk1BWF9WQUxVRSwgJ3llYXJzIGFnbycsIFlFQVIgXVxuICBdO1xuXG4gIGZ1bmN0aW9uIHJlbGF0aXZlRGF0ZShpbnB1dCxyZWZlcmVuY2Upe1xuICAgICFyZWZlcmVuY2UgJiYgKCByZWZlcmVuY2UgPSAobmV3IERhdGUpLmdldFRpbWUoKSApO1xuICAgIHJlZmVyZW5jZSBpbnN0YW5jZW9mIERhdGUgJiYgKCByZWZlcmVuY2UgPSByZWZlcmVuY2UuZ2V0VGltZSgpICk7XG4gICAgaW5wdXQgaW5zdGFuY2VvZiBEYXRlICYmICggaW5wdXQgPSBpbnB1dC5nZXRUaW1lKCkgKTtcbiAgICBcbiAgICB2YXIgZGVsdGEgPSByZWZlcmVuY2UgLSBpbnB1dCxcbiAgICAgICAgZm9ybWF0LCBpLCBsZW47XG5cbiAgICBmb3IoaSA9IC0xLCBsZW49Zm9ybWF0cy5sZW5ndGg7ICsraSA8IGxlbjsgKXtcbiAgICAgIGZvcm1hdCA9IGZvcm1hdHNbaV07XG4gICAgICBpZihkZWx0YSA8IGZvcm1hdFswXSl7XG4gICAgICAgIHJldHVybiBmb3JtYXRbMl0gPT0gdW5kZWZpbmVkID8gZm9ybWF0WzFdIDogTWF0aC5yb3VuZChkZWx0YS9mb3JtYXRbMl0pICsgJyAnICsgZm9ybWF0WzFdO1xuICAgICAgfVxuICAgIH07XG4gIH1cblxuICByZXR1cm4gcmVsYXRpdmVEYXRlO1xuXG59KSgpO1xuXG5pZih0eXBlb2YgbW9kdWxlICE9ICd1bmRlZmluZWQnICYmIG1vZHVsZS5leHBvcnRzKXtcbiAgbW9kdWxlLmV4cG9ydHMgPSByZWxhdGl2ZURhdGU7XG59XG4iLCJtb21lbnQgPSByZXF1aXJlKCdtb21lbnQnKVxuXyA9IHJlcXVpcmUoJ2xvZGFzaCcpXG5oZWxwZXJzID0gcmVxdWlyZSgnLi9oZWxwZXJzLmNvZmZlZScpXG5pdGVtcyA9IHJlcXVpcmUoJy4vaXRlbXMuY29mZmVlJylcbntwZXRzLCBoYXRjaGluZ1BvdGlvbnN9ID0gaXRlbXMuaXRlbXNcblxuWFAgPSAxNVxuSFAgPSAyXG5vYmogPSBtb2R1bGUuZXhwb3J0cyA9IHt9XG5cbm9iai5yZXZpdmUgPSAodXNlciwgb3B0aW9ucz17fSktPlxuICBwYXRocyA9IG9wdGlvbnMucGF0aHMgfHwge31cblxuICAjIFJlc2V0IHN0YXRzXG4gIHVzZXIuc3RhdHMuaHAgPSA1MFxuICB1c2VyLnN0YXRzLmV4cCA9IDBcbiAgdXNlci5zdGF0cy5ncCA9IDBcbiAgdXNlci5zdGF0cy5sdmwtLSBpZiB1c2VyLnN0YXRzLmx2bCA+IDFcblxuICAjIyBMb3NlIGEgcmFuZG9tIGl0ZW1cbiAgbG9zZVRoaXNJdGVtID0gZmFsc2VcbiAgb3duZWQgPSB1c2VyLml0ZW1zXG4gICMgdW5sZXNzIHRoZXkncmUgYWxyZWFkeSBhdCAwLWV2ZXJ5dGhpbmdcbiAgaWYgfn5vd25lZC5hcm1vciA+IDAgb3Igfn5vd25lZC5oZWFkID4gMCBvciB+fm93bmVkLnNoaWVsZCA+IDAgb3Igfn5vd25lZC53ZWFwb24gPiAwXG4gICAgIyBmaW5kIGEgcmFuZG9tIGl0ZW0gdG8gbG9zZVxuICAgIHVudGlsIGxvc2VUaGlzSXRlbVxuICAgICAgI2NhbmRpZGF0ZSA9IHswOidpdGVtcy5hcm1vcicsIDE6J2l0ZW1zLmhlYWQnLCAyOidpdGVtcy5zaGllbGQnLCAzOidpdGVtcy53ZWFwb24nLCA0OidzdGF0cy5ncCd9W01hdGgucmFuZG9tKCkqNXwwXVxuICAgICAgY2FuZGlkYXRlID0gezA6J2FybW9yJywgMTonaGVhZCcsIDI6J3NoaWVsZCcsIDM6J3dlYXBvbid9W01hdGgucmFuZG9tKCkqNHwwXVxuICAgICAgbG9zZVRoaXNJdGVtID0gY2FuZGlkYXRlIGlmIG93bmVkW2NhbmRpZGF0ZV0gPiAwXG4gICAgdXNlci5pdGVtc1tsb3NlVGhpc0l0ZW1dID0gMFxuICBcInN0YXRzLmhwIHN0YXRzLmV4cCBzdGF0cy5ncCBzdGF0cy5sdmwgaXRlbXMuI3tsb3NlVGhpc0l0ZW19XCIuc3BsaXQoJyAnKS5mb3JFYWNoIChwYXRoKSAtPlxuICAgIHBhdGhzW3BhdGhdID0gMVxuXG5cbm9iai5wcmlvcml0eVZhbHVlID0gKHByaW9yaXR5ID0gJyEnKSAtPlxuICBzd2l0Y2ggcHJpb3JpdHlcbiAgICB3aGVuICchJyB0aGVuIDFcbiAgICB3aGVuICchIScgdGhlbiAxLjVcbiAgICB3aGVuICchISEnIHRoZW4gMlxuICAgIGVsc2UgMVxuXG5vYmoudG5sID0gKGxldmVsKSAtPlxuICBpZiBsZXZlbCA+PSAxMDBcbiAgICB2YWx1ZSA9IDBcbiAgZWxzZVxuICAgIHZhbHVlID0gTWF0aC5yb3VuZCgoKE1hdGgucG93KGxldmVsLCAyKSAqIDAuMjUpICsgKDEwICogbGV2ZWwpICsgMTM5Ljc1KSAvIDEwKSAqIDEwXG4gICMgcm91bmQgdG8gbmVhcmVzdCAxMFxuICByZXR1cm4gdmFsdWVcblxuIyMjXG4gIENhbGN1bGF0ZXMgRXhwIG1vZGlmaWNhaXRvbiBiYXNlZCBvbiBsZXZlbCBhbmQgd2VhcG9uIHN0cmVuZ3RoXG4gIHt2YWx1ZX0gdGFzay52YWx1ZSBmb3IgZXhwIGdhaW5cbiAge3dlYXBvblN0cmVuZ3RoKSB3ZWFwb24gc3RyZW5ndGhcbiAge2xldmVsfSBjdXJyZW50IHVzZXIgbGV2ZWxcbiAge3ByaW9yaXR5fSB1c2VyLWRlZmluZWQgcHJpb3JpdHkgbXVsdGlwbGllclxuIyMjXG5vYmouZXhwTW9kaWZpZXIgPSAodmFsdWUsIHdlYXBvblN0ciwgbGV2ZWwsIHByaW9yaXR5ID0gJyEnKSAtPlxuICBzdHIgPSAobGV2ZWwgLSAxKSAvIDJcbiAgIyB1bHRpbWF0ZWx5IGdldCB0aGlzIGZyb20gdXNlclxuICB0b3RhbFN0ciA9IChzdHIgKyB3ZWFwb25TdHIpIC8gMTAwXG4gIHN0ck1vZCA9IDEgKyB0b3RhbFN0clxuICBleHAgPSB2YWx1ZSAqIFhQICogc3RyTW9kICogb2JqLnByaW9yaXR5VmFsdWUocHJpb3JpdHkpXG4gIHJldHVybiBNYXRoLnJvdW5kKGV4cClcblxuIyMjXG4gIENhbGN1bGF0ZXMgSFAgbW9kaWZpY2F0aW9uIGJhc2VkIG9uIGxldmVsIGFuZCBhcm1vciBkZWZlbmNlXG4gIHt2YWx1ZX0gdGFzay52YWx1ZSBmb3IgaHAgbG9zc1xuICB7YXJtb3JEZWZlbnNlfSBkZWZlbnNlIGZyb20gYXJtb3JcbiAge2hlbG1EZWZlbnNlfSBkZWZlbnNlIGZyb20gaGVsbVxuICB7bGV2ZWx9IGN1cnJlbnQgdXNlciBsZXZlbFxuICB7cHJpb3JpdHl9IHVzZXItZGVmaW5lZCBwcmlvcml0eSBtdWx0aXBsaWVyXG4jIyNcbm9iai5ocE1vZGlmaWVyID0gKHZhbHVlLCBhcm1vckRlZiwgaGVsbURlZiwgc2hpZWxkRGVmLCBsZXZlbCwgcHJpb3JpdHkgPSAnIScpIC0+XG4gIGRlZiA9IChsZXZlbCAtIDEpIC8gMlxuICAjIHVsdGltYXRlbHkgZ2V0IHRoaXMgZnJvbSB1c2VyP1xuICB0b3RhbERlZiA9IChkZWYgKyBhcm1vckRlZiArIGhlbG1EZWYgKyBzaGllbGREZWYpIC8gMTAwXG4gICN1bHRpbWF0ZSBnZXQgdGhpcyBmcm9tIHVzZXJcbiAgZGVmTW9kID0gMSAtIHRvdGFsRGVmXG4gIGhwID0gdmFsdWUgKiBIUCAqIGRlZk1vZCAqIG9iai5wcmlvcml0eVZhbHVlKHByaW9yaXR5KVxuICByZXR1cm4gTWF0aC5yb3VuZChocCAqIDEwKSAvIDEwXG4jIHJvdW5kIHRvIDFkcFxuXG4jIyNcbiAgRnV0dXJlIHVzZVxuICB7cHJpb3JpdHl9IHVzZXItZGVmaW5lZCBwcmlvcml0eSBtdWx0aXBsaWVyXG4jIyNcbm9iai5ncE1vZGlmaWVyID0gKHZhbHVlLCBtb2RpZmllciwgcHJpb3JpdHkgPSAnIScsIHN0cmVhaywgdXNlcikgLT5cbiAgdmFsID0gdmFsdWUgKiBtb2RpZmllciAqIG9iai5wcmlvcml0eVZhbHVlKHByaW9yaXR5KVxuICBpZiBzdHJlYWsgYW5kIHVzZXJcbiAgICBzdHJlYWtCb251cyA9IHN0cmVhayAvIDEwMCArIDEgIyBlZywgMS1kYXkgc3RyZWFrIGlzIDEuMSwgMi1kYXkgaXMgMS4yLCBldGNcbiAgICBhZnRlclN0cmVhayA9IHZhbCAqIHN0cmVha0JvbnVzXG4gICAgKHVzZXIuX3RtcD89e30pLnN0cmVha0JvbnVzID0gYWZ0ZXJTdHJlYWsgLSB2YWwgaWYgKHZhbCA+IDApICMga2VlcCB0aGlzIG9uLWhhbmQgZm9yIGxhdGVyLCBzbyB3ZSBjYW4gbm90aWZ5IHN0cmVhay1ib251c1xuICAgIHJldHVybiBhZnRlclN0cmVha1xuICBlbHNlXG4gICAgcmV0dXJuIHZhbFxuXG4jIyNcbiAgQ2FsY3VsYXRlcyB0aGUgbmV4dCB0YXNrLnZhbHVlIGJhc2VkIG9uIGRpcmVjdGlvblxuICBVc2VzIGEgY2FwcGVkIGludmVyc2UgbG9nIHk9Ljk1XngsIHk+PSAtNVxuICB7Y3VycmVudFZhbHVlfSB0aGUgY3VycmVudCB2YWx1ZSBvZiB0aGUgdGFza1xuICB7ZGlyZWN0aW9ufSB1cCBvciBkb3duXG4jIyNcbm9iai50YXNrRGVsdGFGb3JtdWxhID0gKGN1cnJlbnRWYWx1ZSwgZGlyZWN0aW9uKSAtPlxuICBpZiBjdXJyZW50VmFsdWUgPCAtNDcuMjcgdGhlbiBjdXJyZW50VmFsdWUgPSAtNDcuMjdcbiAgZWxzZSBpZiBjdXJyZW50VmFsdWUgPiAyMS4yNyB0aGVuIGN1cnJlbnRWYWx1ZSA9IDIxLjI3XG4gIGRlbHRhID0gTWF0aC5wb3coMC45NzQ3LCBjdXJyZW50VmFsdWUpXG4gIHJldHVybiBkZWx0YSBpZiBkaXJlY3Rpb24gaXMgJ3VwJ1xuICByZXR1cm4gLWRlbHRhXG5cblxuIyMjXG4gIERyb3AgU3lzdGVtXG4jIyNcblxucmFuZG9tRHJvcCA9ICh1c2VyLCBkZWx0YSwgcHJpb3JpdHksIHN0cmVhayA9IDAsIG9wdGlvbnM9e30pIC0+XG4gIHBhdGhzID0gb3B0aW9ucy5wYXRocyB8fCB7fVxuICAjIGxpbWl0IGRyb3BzIHRvIDIgLyBkYXlcbiAgdXNlci5pdGVtcy5sYXN0RHJvcCA/PVxuICAgIGRhdGU6ICttb21lbnQoKS5zdWJ0cmFjdCgnZCcsIDEpICMgdHJpY2sgLSBzZXQgaXQgdG8geWVzdGVyZGF5IG9uIGZpcnN0IHJ1biwgdGhhdCB3YXkgdGhleSBjYW4gZ2V0IGRyb3BzIHRvZGF5XG4gICAgY291bnQ6IDBcbiAgcGF0aHNbJ2l0ZW1zLmxhc3REcm9wJ10gPSB0cnVlXG5cbiAgcmVhY2hlZERyb3BMaW1pdCA9IChoZWxwZXJzLmRheXNTaW5jZSh1c2VyLml0ZW1zLmxhc3REcm9wLmRhdGUsIHVzZXIucHJlZmVyZW5jZXMpIGlzIDApIGFuZCAodXNlci5pdGVtcy5sYXN0RHJvcC5jb3VudCA+PSAyKVxuICByZXR1cm4gaWYgcmVhY2hlZERyb3BMaW1pdFxuXG4gICMgJSBjaGFuY2Ugb2YgZ2V0dGluZyBhIHBldCBvciBtZWF0XG4gIGNoYW5jZU11bHRpcGxpZXIgPSBNYXRoLmFicyhkZWx0YSlcbiAgY2hhbmNlTXVsdGlwbGllciAqPSBvYmoucHJpb3JpdHlWYWx1ZShwcmlvcml0eSkgIyBtdWx0aXBseSBjaGFuY2UgYnkgcmVkZG5lc3NcbiAgY2hhbmNlTXVsdGlwbGllciArPSBzdHJlYWsgIyBzdHJlYWsgYm9udXNcblxuICBpZiB1c2VyLmZsYWdzPy5kcm9wc0VuYWJsZWQgYW5kIE1hdGgucmFuZG9tKCkgPCAoLjA1ICogY2hhbmNlTXVsdGlwbGllcilcbiAgICAjIGN1cnJlbnQgYnJlYWtkb3duIC0gMSUgKGFkanVzdGFibGUpIGNoYW5jZSBvbiBkcm9wXG4gICAgIyBJZiB0aGV5IGdvdCBhIGRyb3A6IDUwJSBjaGFuY2Ugb2YgZWdnLCA1MCUgSGF0Y2hpbmcgUG90aW9uLiBJZiBoYXRjaGluZ1BvdGlvbiwgYnJva2VuIGRvd24gZnVydGhlciBldmVuIGZ1cnRoZXJcbiAgICByYXJpdHkgPSBNYXRoLnJhbmRvbSgpXG5cbiAgICAjIEVnZywgNTAlIGNoYW5jZVxuICAgIGlmIHJhcml0eSA+IC41XG4gICAgICBkcm9wID0gaGVscGVycy5yYW5kb21WYWwocGV0cylcbiAgICAgICh1c2VyLml0ZW1zLmVnZ3MgPz0gW10pLnB1c2ggZHJvcDsgcGF0aHNbJ2l0ZW1zLmVnZ3MnXSA9IHRydWVcbiAgICAgIGRyb3AudHlwZSA9ICdFZ2cnXG4gICAgICBkcm9wLmRpYWxvZyA9IFwiWW91J3ZlIGZvdW5kIGEgI3tkcm9wLnRleHR9IEVnZyEgI3tkcm9wLm5vdGVzfVwiXG5cbiAgICAgICMgSGF0Y2hpbmcgUG90aW9uLCA1MCUgY2hhbmNlIC0gYnJlYWsgZG93biBieSByYXJpdHkgZXZlbiBtb3JlLiBGSVhNRSB0aGlzIG1heSBub3QgYmUgdGhlIGJlc3QgbWV0aG9kLCBzbyByZXZpc2l0XG4gICAgZWxzZVxuICAgICAgYWNjZXB0YWJsZURyb3BzID0gW11cblxuICAgICAgIyBUaWVyIDUgKEJsdWUgTW9vbiBSYXJlKVxuICAgICAgaWYgcmFyaXR5IDwgLjFcbiAgICAgICAgYWNjZXB0YWJsZURyb3BzID1cbiAgICAgICAgICBbJ0Jhc2UnLCAnV2hpdGUnLCAnRGVzZXJ0JywgJ1JlZCcsICdTaGFkZScsICdTa2VsZXRvbicsICdab21iaWUnLCAnQ290dG9uQ2FuZHlQaW5rJywgJ0NvdHRvbkNhbmR5Qmx1ZScsXG4gICAgICAgICAgICdHb2xkZW4nXVxuXG4gICAgICAgICMgVGllciA0IChWZXJ5IFJhcmUpXG4gICAgICBlbHNlIGlmIHJhcml0eSA8IC4yXG4gICAgICAgIGFjY2VwdGFibGVEcm9wcyA9XG4gICAgICAgICAgWydCYXNlJywgJ1doaXRlJywgJ0Rlc2VydCcsICdSZWQnLCAnU2hhZGUnLCAnU2tlbGV0b24nLCAnWm9tYmllJywgJ0NvdHRvbkNhbmR5UGluaycsICdDb3R0b25DYW5keUJsdWUnXVxuXG4gICAgICAgICMgVGllciAzIChSYXJlKVxuICAgICAgZWxzZSBpZiByYXJpdHkgPCAuM1xuICAgICAgICBhY2NlcHRhYmxlRHJvcHMgPSBbJ0Jhc2UnLCAnV2hpdGUnLCAnRGVzZXJ0JywgJ1JlZCcsICdTaGFkZScsICdTa2VsZXRvbiddXG5cbiAgICAgICMgQ29tbWVudGVkIG91dCBmb3IgdGVzdGluZyB3aXRoIGluY3JlYXNlZCBlZ2cgZHJvcCwgZGVsZXRlIGlmIHN1Y2Nlc3NmdWxcbiAgICAgICAgIyBUaWVyIDIgKFNjYXJjZSlcbiAgICAgICMgZWxzZSBpZiByYXJpdHkgPCAuNFxuICAgICAgIyAgIGFjY2VwdGFibGVEcm9wcyA9IFsnQmFzZScsICdXaGl0ZScsICdEZXNlcnQnXVxuXG4gICAgICAgICMgVGllciAxIChDb21tb24pXG4gICAgICBlbHNlXG4gICAgICAgIGFjY2VwdGFibGVEcm9wcyA9IFsnQmFzZScsICdXaGl0ZScsICdEZXNlcnQnXVxuXG4gICAgICBhY2NlcHRhYmxlRHJvcHMgPSBoYXRjaGluZ1BvdGlvbnMuZmlsdGVyIChoYXRjaGluZ1BvdGlvbikgLT5cbiAgICAgICAgaGF0Y2hpbmdQb3Rpb24ubmFtZSBpbiBhY2NlcHRhYmxlRHJvcHNcbiAgICAgIGRyb3AgPSBoZWxwZXJzLnJhbmRvbVZhbCBhY2NlcHRhYmxlRHJvcHNcbiAgICAgICh1c2VyLml0ZW1zLmhhdGNoaW5nUG90aW9ucyA/PSBbXSkucHVzaCBkcm9wLm5hbWU7IHBhdGhzWydpdGVtcy5oYXRjaGluZ1BvdGlvbnMnXSA9IHRydWVcbiAgICAgIGRyb3AudHlwZSA9ICdIYXRjaGluZ1BvdGlvbidcbiAgICAgIGRyb3AuZGlhbG9nID0gXCJZb3UndmUgZm91bmQgYSAje2Ryb3AudGV4dH0gSGF0Y2hpbmcgUG90aW9uISAje2Ryb3Aubm90ZXN9XCJcblxuICAgICMgaWYgdGhleSd2ZSBkcm9wcGVkIHNvbWV0aGluZywgd2Ugd2FudCB0aGUgY29uc3VtaW5nIGNsaWVudCB0byBrbm93IHNvIHRoZXkgY2FuIG5vdGlmeSB0aGUgdXNlci4gU2VlIGhvdyB0aGUgRGVyYnlcbiAgICAjIGFwcCBoYW5kbGVzIGl0IGZvciBleGFtcGxlLiBXb3VsZCB0aGlzIGJlIGJldHRlciBoYW5kbGVkIGFzIGFuIGVtaXQoKSA/XG4gICAgKHVzZXIuX3RtcD89e30pLmRyb3AgPSBkcm9wXG5cbiAgICB1c2VyLml0ZW1zLmxhc3REcm9wLmRhdGUgPSArbmV3IERhdGVcbiAgICB1c2VyLml0ZW1zLmxhc3REcm9wLmNvdW50KytcbiAgICBwYXRoc1snaXRlbXMubGFzdERyb3AnXSA9IHRydWVcblxuXG4jICB7dGFza30gdGFzayB5b3Ugd2FudCB0byBzY29yZVxuIyAge2RpcmVjdGlvbn0gJ3VwJyBvciAnZG93bidcbm9iai5zY29yZSA9ICh1c2VyLCB0YXNrLCBkaXJlY3Rpb24sIG9wdGlvbnM9e30pIC0+XG4gIFtncCwgaHAsIGV4cCwgbHZsXSA9IFsrdXNlci5zdGF0cy5ncCwgK3VzZXIuc3RhdHMuaHAsICt1c2VyLnN0YXRzLmV4cCwgfn51c2VyLnN0YXRzLmx2bF1cbiAgW3R5cGUsIHZhbHVlLCBzdHJlYWssIHByaW9yaXR5XSA9IFt0YXNrLnR5cGUsICt0YXNrLnZhbHVlLCB+fnRhc2suc3RyZWFrLCB0YXNrLnByaW9yaXR5IG9yICchJ11cbiAgW3BhdGhzLCB0aW1lcywgY3Jvbl0gPSBbb3B0aW9ucy5wYXRocyB8fCB7fSwgb3B0aW9ucy50aW1lcyB8fCAxLCBvcHRpb25zLmNyb24gfHwgZmFsc2VdXG5cbiAgIyBIYW5kbGUgY29ycnVwdCB0YXNrc1xuICAjIFRoaXMgdHlwZSBvZiBjbGVhbnVwLWNvZGUgc2hvdWxkbid0IGJlIG5lY2Vzc2FyeSwgcmV2aXNpdCBvbmNlIHdlJ3JlIG9mZiBEZXJieVxuICByZXR1cm4gMCB1bmxlc3MgdGFzay5pZFxuICBpZiAhXy5pc051bWJlcih2YWx1ZSkgb3IgXy5pc05hTih2YWx1ZSlcbiAgICB0YXNrLnZhbHVlID0gdmFsdWUgPSAwO1xuICAgIHBhdGhzW1widGFza3MuI3t0YXNrLmlkfS52YWx1ZVwiXSA9IHRydWVcbiAgXy5lYWNoIHVzZXIuc3RhdHMsICh2LGspIC0+XG4gICAgaWYgIV8uaXNOdW1iZXIodikgb3IgXy5pc05hTih2KVxuICAgICAgdXNlci5zdGF0c1trXSA9IDA7IHBhdGhzW1wic3RhdHMuI3trfVwiXSA9IHRydWVcblxuICAjIElmIHRoZXkncmUgdHJ5aW5nIHRvIHB1cmhjYXNlIGEgdG9vLWV4cGVuc2l2ZSByZXdhcmQsIGRvbid0IGFsbG93IHRoZW0gdG8gZG8gdGhhdC5cbiAgaWYgdGFzay52YWx1ZSA+IHVzZXIuc3RhdHMuZ3AgYW5kIHRhc2sudHlwZSBpcyAncmV3YXJkJ1xuICAgIHJldHVyblxuXG4gIGRlbHRhID0gMFxuICBjYWxjdWxhdGVEZWx0YSA9IChhZGp1c3R2YWx1ZSA9IHRydWUpIC0+XG4gICAgIyBJZiBtdWx0aXBsZSBkYXlzIGhhdmUgcGFzc2VkLCBtdWx0aXBseSB0aW1lcyBkYXlzIG1pc3NlZFxuICAgIF8udGltZXMgdGltZXMsIC0+XG4gICAgICAjIEVhY2ggaXRlcmF0aW9uIGNhbGN1bGF0ZSB0aGUgZGVsdGEgKG5leHREZWx0YSksIHdoaWNoIGlzIHRoZW4gYWNjdW11bGF0ZWQgaW4gZGVsdGFcbiAgICAgICMgKGFrYSwgdGhlIHRvdGFsIGRlbHRhKS4gVGhpcyB3ZWlyZG5lc3Mgd29uJ3QgYmUgbmVjZXNzYXJ5IHdoZW4gY2FsY3VsYXRpbmcgbWF0aGVtYXRpY2FsbHlcbiAgICAgICMgcmF0aGVyIHRoYW4gaXRlcmF0aXZlbHlcbiAgICAgIG5leHREZWx0YSA9IG9iai50YXNrRGVsdGFGb3JtdWxhKHZhbHVlLCBkaXJlY3Rpb24pXG4gICAgICB2YWx1ZSArPSBuZXh0RGVsdGEgaWYgYWRqdXN0dmFsdWVcbiAgICAgIGRlbHRhICs9IG5leHREZWx0YVxuXG4gIGFkZFBvaW50cyA9IC0+XG4gICAgd2VhcG9uU3RyID0gaXRlbXMuZ2V0SXRlbSgnd2VhcG9uJywgdXNlci5pdGVtcy53ZWFwb24pLnN0cmVuZ3RoXG4gICAgZXhwICs9IG9iai5leHBNb2RpZmllcihkZWx0YSwgd2VhcG9uU3RyLCB1c2VyLnN0YXRzLmx2bCwgcHJpb3JpdHkpIC8gMiAjIC8yIGhhY2sgZm9yIG5vdywgcGVvcGxlIGxldmVsaW5nIHRvbyBmYXN0XG4gICAgaWYgc3RyZWFrXG4gICAgICBncCArPSBvYmouZ3BNb2RpZmllcihkZWx0YSwgMSwgcHJpb3JpdHksIHN0cmVhaywgdXNlcilcbiAgICBlbHNlXG4gICAgICBncCArPSBvYmouZ3BNb2RpZmllcihkZWx0YSwgMSwgcHJpb3JpdHkpXG5cblxuICBzdWJ0cmFjdFBvaW50cyA9IC0+XG4gICAgYXJtb3JEZWYgPSBpdGVtcy5nZXRJdGVtKCdhcm1vcicsIHVzZXIuaXRlbXMuYXJtb3IpLmRlZmVuc2VcbiAgICBoZWFkRGVmID0gaXRlbXMuZ2V0SXRlbSgnaGVhZCcsIHVzZXIuaXRlbXMuaGVhZCkuZGVmZW5zZVxuICAgIHNoaWVsZERlZiA9IGl0ZW1zLmdldEl0ZW0oJ3NoaWVsZCcsIHVzZXIuaXRlbXMuc2hpZWxkKS5kZWZlbnNlXG4gICAgaHAgKz0gb2JqLmhwTW9kaWZpZXIoZGVsdGEsIGFybW9yRGVmLCBoZWFkRGVmLCBzaGllbGREZWYsIHVzZXIuc3RhdHMubHZsLCBwcmlvcml0eSlcblxuICBzd2l0Y2ggdHlwZVxuICAgIHdoZW4gJ2hhYml0J1xuICAgICAgY2FsY3VsYXRlRGVsdGEoKVxuICAgICAgIyBBZGQgaGFiaXQgdmFsdWUgdG8gaGFiaXQtaGlzdG9yeSAoaWYgZGlmZmVyZW50KVxuICAgICAgaWYgKGRlbHRhID4gMCkgdGhlbiBhZGRQb2ludHMoKSBlbHNlIHN1YnRyYWN0UG9pbnRzKClcbiAgICAgIGlmIHRhc2sudmFsdWUgIT0gdmFsdWVcbiAgICAgICAgKHRhc2suaGlzdG9yeSA/PSBbXSkucHVzaCB7IGRhdGU6ICtuZXcgRGF0ZSwgdmFsdWU6IHZhbHVlIH07IHBhdGhzW1widGFza3MuI3t0YXNrLmlkfS5oaXN0b3J5XCJdID0gdHJ1ZVxuXG4gICAgd2hlbiAnZGFpbHknXG4gICAgICBpZiBjcm9uXG4gICAgICAgIGNhbGN1bGF0ZURlbHRhKClcbiAgICAgICAgc3VidHJhY3RQb2ludHMoKVxuICAgICAgICB0YXNrLnN0cmVhayA9IDBcbiAgICAgIGVsc2VcbiAgICAgICAgY2FsY3VsYXRlRGVsdGEoKVxuICAgICAgICBhZGRQb2ludHMoKSAjIG9idmlvdXNseSBmb3IgZGVsdGE+MCwgYnV0IGFsc28gYSB0cmljayB0byB1bmRvIGFjY2lkZW50YWwgY2hlY2tib3hlc1xuICAgICAgICBpZiBkaXJlY3Rpb24gaXMgJ3VwJ1xuICAgICAgICAgIHN0cmVhayA9IGlmIHN0cmVhayB0aGVuIHN0cmVhayArIDEgZWxzZSAxXG4gICAgICAgIGVsc2VcbiAgICAgICAgICBzdHJlYWsgPSBpZiBzdHJlYWsgdGhlbiBzdHJlYWsgLSAxIGVsc2UgMFxuICAgICAgICB0YXNrLnN0cmVhayA9IHN0cmVha1xuICAgICAgcGF0aHNbXCJ0YXNrcy4je3Rhc2suaWR9LnN0cmVha1wiXSA9IHRydWVcblxuICAgIHdoZW4gJ3RvZG8nXG4gICAgICBpZiBjcm9uXG4gICAgICAgIGNhbGN1bGF0ZURlbHRhKClcbiAgICAgICAgI2Rvbid0IHRvdWNoIHN0YXRzIG9uIGNyb25cbiAgICAgIGVsc2VcbiAgICAgICAgY2FsY3VsYXRlRGVsdGEoKVxuICAgICAgICBhZGRQb2ludHMoKSAjIG9idmlvdXNseSBmb3IgZGVsdGE+MCwgYnV0IGFsc28gYSB0cmljayB0byB1bmRvIGFjY2lkZW50YWwgY2hlY2tib3hlc1xuXG4gICAgd2hlbiAncmV3YXJkJ1xuICAgICMgRG9uJ3QgYWRqdXN0IHZhbHVlcyBmb3IgcmV3YXJkc1xuICAgICAgY2FsY3VsYXRlRGVsdGEoZmFsc2UpXG4gICAgICAjIHB1cmNoYXNlIGl0ZW1cbiAgICAgIGdwIC09IE1hdGguYWJzKHRhc2sudmFsdWUpXG4gICAgICBudW0gPSBwYXJzZUZsb2F0KHRhc2sudmFsdWUpLnRvRml4ZWQoMilcbiAgICAgICMgaWYgdG9vIGV4cGVuc2l2ZSwgcmVkdWNlIGhlYWx0aCAmIHplcm8gZ3BcbiAgICAgIGlmIGdwIDwgMFxuICAgICAgICBocCArPSBncFxuICAgICAgICAjIGhwIC0gZ3AgZGlmZmVyZW5jZVxuICAgICAgICBncCA9IDBcblxuICB0YXNrLnZhbHVlID0gdmFsdWU7IHBhdGhzW1widGFza3MuI3t0YXNrLmlkfS52YWx1ZVwiXSA9IHRydWVcbiAgdXBkYXRlU3RhdHMgdXNlciwgeyBocCwgZXhwLCBncCB9LCB7cGF0aHM6IHBhdGhzfVxuXG4gICMgRHJvcCBzeXN0ZW0gI0ZJWE1FXG4gIHJhbmRvbURyb3AodXNlciwgZGVsdGEsIHByaW9yaXR5LCBzdHJlYWssIHtwYXRoczogcGF0aHN9KSBpZiBkaXJlY3Rpb24gaXMgJ3VwJ1xuXG4gIHJldHVybiBkZWx0YVxuXG4jIyNcbiAgVXBkYXRlcyB1c2VyIHN0YXRzIHdpdGggbmV3IHN0YXRzLiBIYW5kbGVzIGRlYXRoLCBsZXZlbGluZyB1cCwgZXRjXG4gIHtzdGF0c30gbmV3IHN0YXRzXG4gIHt1cGRhdGV9IGlmIGFnZ3JlZ2F0ZWQgY2hhbmdlcywgcGFzcyBpbiB1c2VyT2JqIGFzIHVwZGF0ZS4gb3RoZXJ3aXNlIGNvbW1pdHMgd2lsbCBiZSBtYWRlIGltbWVkaWF0ZWx5XG4jIyNcbnVwZGF0ZVN0YXRzID0gKHVzZXIsIG5ld1N0YXRzLCBvcHRpb25zPXt9KSAtPlxuICBwYXRocyA9IG9wdGlvbnMucGF0aHMgfHwge31cbiAgIyBpZiB1c2VyIGlzIGRlYWQsIGRvbnQgZG8gYW55dGhpbmdcbiAgcmV0dXJuIGlmIHVzZXIuc3RhdHMuaHAgPD0gMFxuXG4gIGlmIG5ld1N0YXRzLmhwP1xuICAgICMgR2FtZSBPdmVyXG4gICAgaWYgbmV3U3RhdHMuaHAgPD0gMFxuICAgICAgdXNlci5zdGF0cy5ocCA9IDA7IHBhdGhzWydzdGF0cy5ocCddID0gdHJ1ZSAjIHNpZ25pZmllcyBkZWFkXG4gICAgICByZXR1cm5cbiAgICBlbHNlXG4gICAgICB1c2VyLnN0YXRzLmhwID0gbmV3U3RhdHMuaHA7IHBhdGhzWydzdGF0cy5ocCddID0gdHJ1ZVxuXG4gIGlmIG5ld1N0YXRzLmV4cD9cbiAgICB0bmwgPSBvYmoudG5sKHVzZXIuc3RhdHMubHZsKVxuICAgICNzaWxlbnQgPSBmYWxzZVxuICAgICMgaWYgd2UncmUgYXQgbGV2ZWwgMTAwLCB0dXJuIHhwIHRvIGdvbGRcbiAgICBpZiB1c2VyLnN0YXRzLmx2bCA+PSAxMDBcbiAgICAgIG5ld1N0YXRzLmdwICs9IG5ld1N0YXRzLmV4cCAvIDE1XG4gICAgICBuZXdTdGF0cy5leHAgPSAwXG4gICAgICB1c2VyLnN0YXRzLmx2bCA9IDEwMFxuICAgIGVsc2VcbiAgICAgICMgbGV2ZWwgdXAgJiBjYXJyeS1vdmVyIGV4cFxuICAgICAgaWYgbmV3U3RhdHMuZXhwID49IHRubFxuICAgICAgICAjc2lsZW50ID0gdHJ1ZSAjIHB1c2ggdGhyb3VnaCB0aGUgbmVnYXRpdmUgeHAgc2lsZW50bHlcbiAgICAgICAgdXNlci5zdGF0cy5leHAgPSBuZXdTdGF0cy5leHAgIyBwdXNoIG5vcm1hbCArIG5vdGlmaWNhdGlvblxuICAgICAgICB3aGlsZSBuZXdTdGF0cy5leHAgPj0gdG5sIGFuZCB1c2VyLnN0YXRzLmx2bCA8IDEwMCAjIGtlZXAgbGV2ZWxsaW5nIHVwXG4gICAgICAgICAgbmV3U3RhdHMuZXhwIC09IHRubFxuICAgICAgICAgIHVzZXIuc3RhdHMubHZsKytcbiAgICAgICAgICB0bmwgPSBvYmoudG5sKHVzZXIuc3RhdHMubHZsKVxuICAgICAgICBpZiB1c2VyLnN0YXRzLmx2bCA9PSAxMDBcbiAgICAgICAgICBuZXdTdGF0cy5leHAgPSAwXG4gICAgICAgIHVzZXIuc3RhdHMuaHAgPSA1MFxuXG4gICAgdXNlci5zdGF0cy5leHAgPSBuZXdTdGF0cy5leHBcblxuICAgIHBhdGhzW1wic3RhdHMuZXhwXCJdPXRydWU7IHBhdGhzWydzdGF0cy5sdmwnXT10cnVlOyBwYXRoc1snc3RhdHMuZ3AnXT10cnVlOyBwYXRoc1snc3RhdHMuaHAnXT10cnVlO1xuICAgICNpZiBzaWxlbnRcbiAgICAjY29uc29sZS5sb2coXCJwdXNoaW5nIHNpbGVudCA6XCIgICsgb2JqLnN0YXRzLmV4cClcblxuXG4gICAgIyBTZXQgZmxhZ3Mgd2hlbiB0aGV5IHVubG9jayBmZWF0dXJlc1xuICAgIHVzZXIuZmxhZ3MgPz0ge31cbiAgICBpZiAhdXNlci5mbGFncy5jdXN0b21pemF0aW9uc05vdGlmaWNhdGlvbiBhbmQgKHVzZXIuc3RhdHMuZXhwID4gMTAgb3IgdXNlci5zdGF0cy5sdmwgPiAxKVxuICAgICAgdXNlci5mbGFncy5jdXN0b21pemF0aW9uc05vdGlmaWNhdGlvbiA9IHRydWU7IHBhdGhzWydmbGFncy5jdXN0b21pemF0aW9uc05vdGlmaWNhdGlvbiddPXRydWU7XG4gICAgaWYgIXVzZXIuZmxhZ3MuaXRlbXNFbmFibGVkIGFuZCB1c2VyLnN0YXRzLmx2bCA+PSAyXG4gICAgICB1c2VyLmZsYWdzLml0ZW1zRW5hYmxlZCA9IHRydWU7IHBhdGhzWydmbGFncy5pdGVtc0VuYWJsZWQnXT10cnVlO1xuICAgIGlmICF1c2VyLmZsYWdzLnBhcnR5RW5hYmxlZCBhbmQgdXNlci5zdGF0cy5sdmwgPj0gM1xuICAgICAgdXNlci5mbGFncy5wYXJ0eUVuYWJsZWQgPSB0cnVlOyBwYXRoc1snZmxhZ3MucGFydHlFbmFibGVkJ109dHJ1ZTtcbiAgICBpZiAhdXNlci5mbGFncy5kcm9wc0VuYWJsZWQgYW5kIHVzZXIuc3RhdHMubHZsID49IDRcbiAgICAgIHVzZXIuZmxhZ3MuZHJvcHNFbmFibGVkID0gdHJ1ZTsgcGF0aHNbJ2ZsYWdzLmRyb3BzRW5hYmxlZCddPXRydWU7XG5cbiAgaWYgbmV3U3RhdHMuZ3A/XG4gICAgI0ZJWE1FIHdoYXQgd2FzIEkgZG9pbmcgaGVyZT8gSSBjYW4ndCByZW1lbWJlciwgZ3AgaXNuJ3QgZGVmaW5lZFxuICAgIGdwID0gMC4wIGlmICghZ3A/IG9yIGdwIDwgMClcbiAgICB1c2VyLnN0YXRzLmdwID0gbmV3U3RhdHMuZ3BcblxuIyMjXG4gIEF0IGVuZCBvZiBkYXksIGFkZCB2YWx1ZSB0byBhbGwgaW5jb21wbGV0ZSBEYWlseSAmIFRvZG8gdGFza3MgKGZ1cnRoZXIgaW5jZW50aXZlKVxuICBGb3IgaW5jb21wbGV0ZSBEYWlseXMsIGRlZHVjdCBleHBlcmllbmNlXG4gIE1ha2Ugc3VyZSB0byBydW4gdGhpcyBmdW5jdGlvbiBvbmNlIGluIGEgd2hpbGUgYXMgc2VydmVyIHdpbGwgbm90IHRha2UgY2FyZSBvZiBvdmVybmlnaHQgY2FsY3VsYXRpb25zLlxuICBBbmQgeW91IGhhdmUgdG8gcnVuIGl0IGV2ZXJ5IHRpbWUgY2xpZW50IGNvbm5lY3RzLlxuICB7dXNlcn1cbiMjI1xub2JqLmNyb24gPSAodXNlciwgb3B0aW9ucz17fSkgLT5cbiAgW3BhdGhzLCBub3ddID0gW29wdGlvbnMucGF0aHMgfHwge30sICtvcHRpb25zLm5vdyB8fCArbmV3IERhdGVdXG5cbiAgIyBOZXcgdXNlciAoIWxhc3RDcm9uLCBsYXN0Q3Jvbj09bmV3KSBvciBpdCBnb3QgYnVzdGVkIHNvbWVob3csIG1heWJlIHRoZXkgd2VudCB0byBhIGRpZmZlcmVudCB0aW1lem9uZVxuICAjIEZJWE1FIG1vdmUgdGhpcyB0byBwcmUtc2F2ZSBpbiBtb25nb29zZVxuICBpZiAhdXNlci5sYXN0Q3Jvbj8gb3IgdXNlci5sYXN0Q3JvbiBpcyAnbmV3JyBvciBtb21lbnQodXNlci5sYXN0Q3JvbikuaXNBZnRlcihub3cpXG4gICAgdXNlci5sYXN0Q3JvbiA9IG5vdzsgcGF0aHNbJ2xhc3RDcm9uJ10gPSB0cnVlXG4gICAgcmV0dXJuXG5cbiAgZGF5c01pc3NlZCA9IGhlbHBlcnMuZGF5c1NpbmNlIHVzZXIubGFzdENyb24sIF8uZGVmYXVsdHMoe25vd30sIHVzZXIucHJlZmVyZW5jZXMpXG4gIHJldHVybiB1bmxlc3MgZGF5c01pc3NlZCA+IDBcblxuICB1c2VyLmxhc3RDcm9uID0gbm93OyBwYXRoc1snbGFzdENyb24nXSA9IHRydWVcblxuICAjIFVzZXIgaXMgcmVzdGluZyBhdCB0aGUgaW5uLiBVc2VkIHRvIGJlIHdlIHVuLWNoZWNrZWQgZWFjaCBkYWlseSB3aXRob3V0IHBlcmZvcm1pbmcgY2FsY3VsYXRpb24gKHNlZSBjb21taXRzIGJlZm9yZSBmYjI5ZTM1KVxuICAjIGJ1dCB0byBwcmV2ZW50IGFidXNpbmcgdGhlIGlubiAoaHR0cDovL2dvby5nbC9HRGI5eCkgd2Ugbm93IGRvICpub3QqIGNhbGN1bGF0ZSBkYWlsaWVzLCBhbmQgc2ltcGx5IHNldCBsYXN0Q3JvbiB0byB0b2RheVxuICByZXR1cm4gaWYgdXNlci5mbGFncy5yZXN0IGlzIHRydWVcblxuICAjIFRhbGx5IGVhY2ggdGFza1xuICB0b2RvVGFsbHkgPSAwXG4gIHVzZXIudG9kb3MuY29uY2F0KHVzZXIuZGFpbHlzKS5mb3JFYWNoICh0YXNrKSAtPlxuICAgIHJldHVybiB1bmxlc3MgdGFza1xuICAgIHtpZCwgdHlwZSwgY29tcGxldGVkLCByZXBlYXR9ID0gdGFza1xuICAgICMgRGVkdWN0IGV4cGVyaWVuY2UgZm9yIG1pc3NlZCBEYWlseSB0YXNrcywgYnV0IG5vdCBmb3IgVG9kb3MgKGp1c3QgaW5jcmVhc2UgdG9kbydzIHZhbHVlKVxuICAgIHVubGVzcyBjb21wbGV0ZWRcbiAgICAgIHNjaGVkdWxlTWlzc2VzID0gZGF5c01pc3NlZFxuICAgICAgIyBmb3IgZGFpbHlzIHdoaWNoIGhhdmUgcmVwZWF0IGRhdGVzLCBuZWVkIHRvIGNhbGN1bGF0ZSBob3cgbWFueSB0aGV5J3ZlIG1pc3NlZCBhY2NvcmRpbmcgdG8gdGhlaXIgb3duIHNjaGVkdWxlXG4gICAgICBpZiAodHlwZSBpcyAnZGFpbHknKSBhbmQgcmVwZWF0XG4gICAgICAgIHNjaGVkdWxlTWlzc2VzID0gMFxuICAgICAgICBfLnRpbWVzIGRheXNNaXNzZWQsIChuKSAtPlxuICAgICAgICAgIHRoYXREYXkgPSBtb21lbnQobm93KS5zdWJ0cmFjdCgnZGF5cycsIG4gKyAxKVxuICAgICAgICAgIHNjaGVkdWxlTWlzc2VzKysgaWYgaGVscGVycy5zaG91bGREbyh0aGF0RGF5LCByZXBlYXQsIHVzZXIucHJlZmVyZW5jZXMpXG4gICAgICBvYmouc2NvcmUodXNlciwgdGFzaywgJ2Rvd24nLCB7dGltZXM6c2NoZWR1bGVNaXNzZXMsIGNyb246dHJ1ZSwgcGF0aHM6cGF0aHN9KSBpZiBzY2hlZHVsZU1pc3NlcyA+IDBcblxuICAgIHN3aXRjaCB0eXBlXG4gICAgICB3aGVuICdkYWlseSdcbiAgICAgICAgKHRhc2suaGlzdG9yeSA/PSBbXSkucHVzaCh7IGRhdGU6ICtuZXcgRGF0ZSwgdmFsdWU6IHRhc2sudmFsdWUgfSk7IHBhdGhzW1widGFza3MuI3t0YXNrLmlkfS5oaXN0b3J5XCJdID0gdHJ1ZVxuICAgICAgICB0YXNrLmNvbXBsZXRlZCA9IGZhbHNlOyBwYXRoc1tcInRhc2tzLiN7dGFzay5pZH0uY29tcGxldGVkXCJdID0gdHJ1ZTtcbiAgICAgIHdoZW4gJ3RvZG8nXG4gICAgICAgICNnZXQgdXBkYXRlZCB2YWx1ZVxuICAgICAgICBhYnNWYWwgPSBpZiAoY29tcGxldGVkKSB0aGVuIE1hdGguYWJzKHRhc2sudmFsdWUpIGVsc2UgdGFzay52YWx1ZVxuICAgICAgICB0b2RvVGFsbHkgKz0gYWJzVmFsXG5cbiAgdXNlci5oYWJpdHMuZm9yRWFjaCAodGFzaykgLT4gIyBzbG93bHkgcmVzZXQgJ29ubGllcycgdmFsdWUgdG8gMFxuICAgIGlmIHRhc2sudXAgaXMgZmFsc2Ugb3IgdGFzay5kb3duIGlzIGZhbHNlXG4gICAgICBpZiBNYXRoLmFicyh0YXNrLnZhbHVlKSA8IDAuMVxuICAgICAgICB0YXNrLnZhbHVlID0gMFxuICAgICAgZWxzZVxuICAgICAgICB0YXNrLnZhbHVlID0gdGFzay52YWx1ZSAvIDJcbiAgICAgIHBhdGhzW1widGFza3MuI3t0YXNrLmlkfS52YWx1ZVwiXSA9IHRydWVcblxuXG4gICMgRmluaXNoZWQgdGFsbHlpbmdcbiAgKCh1c2VyLmhpc3RvcnkgPz0ge30pLnRvZG9zID89IFtdKS5wdXNoIHsgZGF0ZTogbm93LCB2YWx1ZTogdG9kb1RhbGx5IH1cbiAgIyB0YWxseSBleHBlcmllbmNlXG4gIGV4cFRhbGx5ID0gdXNlci5zdGF0cy5leHBcbiAgbHZsID0gMCAjaXRlcmF0b3JcbiAgd2hpbGUgbHZsIDwgKHVzZXIuc3RhdHMubHZsIC0gMSlcbiAgICBsdmwrK1xuICAgIGV4cFRhbGx5ICs9IG9iai50bmwobHZsKVxuICAodXNlci5oaXN0b3J5LmV4cCA/PSBbXSkucHVzaCB7IGRhdGU6IG5vdywgdmFsdWU6IGV4cFRhbGx5IH1cbiAgcGF0aHNbXCJoaXN0b3J5XCJdID0gdHJ1ZVxuICB1c2VyXG4iLCJtb21lbnQgPSByZXF1aXJlICdtb21lbnQnXG5fID0gcmVxdWlyZSAnbG9kYXNoJ1xuaXRlbXMgPSByZXF1aXJlKCcuL2l0ZW1zLmNvZmZlZScpXG5cbiMjI1xuICBFYWNoIHRpbWUgd2UncmUgcGVyZm9ybWluZyBkYXRlIG1hdGggKGNyb24sIHRhc2stZHVlLWRheXMsIGV0YyksIHdlIG5lZWQgdG8gdGFrZSB1c2VyIHByZWZlcmVuY2VzIGludG8gY29uc2lkZXJhdGlvbi5cbiAgU3BlY2lmaWNhbGx5IHtkYXlTdGFydH0gKGN1c3RvbSBkYXkgc3RhcnQpIGFuZCB7dGltZXpvbmVPZmZzZXR9LiBUaGlzIGZ1bmN0aW9uIHNhbml0aXplcyAvIGRlZmF1bHRzIHRob3NlIHZhbHVlcy5cbiAge25vd30gaXMgYWxzbyBwYXNzZWQgaW4gZm9yIHZhcmlvdXMgcHVycG9zZXMsIG9uZSBleGFtcGxlIGJlaW5nIHRoZSB0ZXN0IHNjcmlwdHMgc2NyaXB0cyB0ZXN0aW5nIGRpZmZlcmVudCBcIm5vd1wiIHRpbWVzXG4jIyNcbnNhbml0aXplT3B0aW9ucyA9IChvKSAtPlxuICBkYXlTdGFydCA9IGlmIChvLmRheVN0YXJ0IGFuZCAwIDw9ICtvLmRheVN0YXJ0IDw9IDI0KSB0aGVuICtvLmRheVN0YXJ0IGVsc2UgMFxuICB0aW1lem9uZU9mZnNldCA9IGlmIG8udGltZXpvbmVPZmZzZXQgdGhlbiArKG8udGltZXpvbmVPZmZzZXQpIGVsc2UgK21vbWVudCgpLnpvbmUoKVxuICBub3cgPSBpZiBvLm5vdyB0aGVuIG1vbWVudChvLm5vdykuem9uZSh0aW1lem9uZU9mZnNldCkgZWxzZSBtb21lbnQoK25ldyBEYXRlKS56b25lKHRpbWV6b25lT2Zmc2V0KVxuICAjIHJldHVybiBhIG5ldyBvYmplY3QsIHdlIGRvbid0IHdhbnQgdG8gYWRkIFwibm93XCIgdG8gdXNlciBvYmplY3RcbiAge2RheVN0YXJ0LCB0aW1lem9uZU9mZnNldCwgbm93fVxuXG5zdGFydE9mV2VlayA9IChvcHRpb25zPXt9KSAtPlxuICBvID0gc2FuaXRpemVPcHRpb25zKG9wdGlvbnMpXG4gIG1vbWVudChvLm5vdykuc3RhcnRPZignd2VlaycpXG5cbnN0YXJ0T2ZEYXkgPSAob3B0aW9ucz17fSkgLT5cbiAgbyA9IHNhbml0aXplT3B0aW9ucyhvcHRpb25zKVxuICBtb21lbnQoby5ub3cpLnN0YXJ0T2YoJ2RheScpLmFkZCgnaCcsIG9wdGlvbnMuZGF5U3RhcnQpXG5cbmRheU1hcHBpbmcgPSB7MDonc3UnLDE6J20nLDI6J3QnLDM6J3cnLDQ6J3RoJyw1OidmJyw2OidzJ31cblxuIyMjXG4gIEFic29sdXRlIGRpZmYgZnJvbSBcInllc3RlcmRheVwiIHRpbGwgbm93XG4jIyNcbmRheXNTaW5jZSA9ICh5ZXN0ZXJkYXksIG9wdGlvbnMgPSB7fSkgLT5cbiAgbyA9IHNhbml0aXplT3B0aW9ucyBvcHRpb25zXG4gIE1hdGguYWJzIHN0YXJ0T2ZEYXkoXy5kZWZhdWx0cyB7bm93Onllc3RlcmRheX0sIG8pLmRpZmYoby5ub3csICdkYXlzJylcblxuIyMjXG4gIFNob3VsZCB0aGUgdXNlciBkbyB0aGlzIHRha3Mgb24gdGhpcyBkYXRlLCBnaXZlbiB0aGUgdGFzaydzIHJlcGVhdCBvcHRpb25zIGFuZCB1c2VyLnByZWZlcmVuY2VzLmRheVN0YXJ0P1xuIyMjXG5zaG91bGREbyA9IChkYXksIHJlcGVhdCwgb3B0aW9ucz17fSkgLT5cbiAgcmV0dXJuIGZhbHNlIHVubGVzcyByZXBlYXRcbiAgbyA9IHNhbml0aXplT3B0aW9ucyBvcHRpb25zXG4gIHNlbGVjdGVkID0gcmVwZWF0W2RheU1hcHBpbmdbc3RhcnRPZkRheShfLmRlZmF1bHRzIHtub3c6ZGF5fSwgbykuZGF5KCldXVxuICByZXR1cm4gc2VsZWN0ZWQgdW5sZXNzIG1vbWVudChkYXkpLnpvbmUoby50aW1lem9uZU9mZnNldCkuaXNTYW1lKG8ubm93LCdkJylcbiAgaWYgb3B0aW9ucy5kYXlTdGFydCA8PSBvLm5vdy5ob3VyKCkgIyB3ZSdyZSBwYXN0IHRoZSBkYXlTdGFydCBtYXJrLCBpcyBpdCBkdWUgdG9kYXk/XG4gICAgcmV0dXJuIHNlbGVjdGVkXG4gIGVsc2UgIyB3ZSdyZSBub3QgcGFzdCBkYXlTdGFydCBtYXJrLCBjaGVjayBpZiBpdCB3YXMgZHVlIFwieWVzdGVyZGF5XCJcbiAgICB5ZXN0ZXJkYXkgPSBtb21lbnQoby5ub3cpLnN1YnRyYWN0KDEsJ2QnKS5kYXkoKSAjIGhhdmUgdG8gd3JhcCBvLm5vdyBzbyBhcyBub3QgdG8gbW9kaWZ5IG9yaWdpbmFsXG4gICAgcmV0dXJuIHJlcGVhdFtkYXlNYXBwaW5nW3llc3RlcmRheV1dICMgRklYTUUgaXMgdGhpcyBjb3JyZWN0Pz8gRG8gSSBuZWVkIHRvIGRvIGFueSB0aW1lem9uZSBjYWxjYXVsYXRpb24gaGVyZT9cblxudXVpZCA9IC0+XG4gIFwieHh4eHh4eHgteHh4eC00eHh4LXl4eHgteHh4eHh4eHh4eHh4XCIucmVwbGFjZSAvW3h5XS9nLCAoYykgLT5cbiAgICByID0gTWF0aC5yYW5kb20oKSAqIDE2IHwgMFxuICAgIHYgPSAoaWYgYyBpcyBcInhcIiB0aGVuIHIgZWxzZSAociAmIDB4MyB8IDB4OCkpXG4gICAgdi50b1N0cmluZyAxNlxuXG5tb2R1bGUuZXhwb3J0cyA9XG5cbiAgdXVpZDogdXVpZFxuXG4gIHRhc2tEZWZhdWx0czogKHRhc2ssIGZpbHRlcnM9e30pIC0+XG4gICAgc2VsZiA9IEBcbiAgICBkZWZhdWx0cyA9XG4gICAgICBpZDogc2VsZi51dWlkKClcbiAgICAgIHRleHQ6ICcnXG4gICAgICB1cDogdHJ1ZVxuICAgICAgZG93bjogdHJ1ZVxuICAgICAgdHlwZTogJ2hhYml0J1xuICAgICAgY29tcGxldGVkOiBmYWxzZVxuICAgICAgcmVwZWF0OiB7c3U6dHJ1ZSxtOnRydWUsdDp0cnVlLHc6dHJ1ZSx0aDp0cnVlLGY6dHJ1ZSxzOnRydWV9XG4gICAgICBub3RlczogJydcbiAgICAgIHRhZ3M6IF8udHJhbnNmb3JtKGZpbHRlcnMsIChtLHYsaykgLT4gbVtrXT12IGlmIHYpXG4gICAgXy5kZWZhdWx0cyB0YXNrLCBkZWZhdWx0c1xuICAgIHRhc2sudmFsdWUgPz0gaWYgdGFzay50eXBlIGlzICdyZXdhcmQnIHRoZW4gMTAgZWxzZSAwXG4gICAgdGFza1xuXG4gIG5ld1VzZXI6IChpc0RlcmJ5PWZhbHNlKSAtPlxuICAgIHVzZXJTY2hlbWEgPVxuICAgICMgX2lkIC8gaWQgaGFuZGxlZCBieSBSYWNlclxuICAgICAgc3RhdHM6IHsgZ3A6IDAsIGV4cDogMCwgbHZsOiAxLCBocDogNTAgfVxuICAgICAgaW52aXRhdGlvbnM6IHtwYXJ0eTpudWxsLCBndWlsZHM6IFtdfVxuICAgICAgaXRlbXM6IHsgd2VhcG9uOiAwLCBhcm1vcjogMCwgaGVhZDogMCwgc2hpZWxkOiAwIH1cbiAgICAgIHByZWZlcmVuY2VzOiB7IGdlbmRlcjogJ20nLCBza2luOiAnd2hpdGUnLCBoYWlyOiAnYmxvbmQnLCBhcm1vclNldDogJ3YxJywgZGF5U3RhcnQ6MCwgc2hvd0hlbG06IHRydWUgfVxuICAgICAgYXBpVG9rZW46IHV1aWQoKSAjIHNldCBpbiBuZXdVc2VyT2JqZWN0IGJlbG93XG4gICAgICBsYXN0Q3JvbjogK25ldyBEYXRlICN0aGlzIHdpbGwgYmUgcmVwbGFjZWQgd2l0aCBgK25ldyBEYXRlYCBvbiBmaXJzdCBydW5cbiAgICAgIGJhbGFuY2U6IDBcbiAgICAgIGZsYWdzOlxuICAgICAgICBwYXJ0eUVuYWJsZWQ6IGZhbHNlXG4gICAgICAgIGl0ZW1zRW5hYmxlZDogZmFsc2VcbiAgICAgICAgYWRzOiAnc2hvdydcbiAgICAgIHRhZ3M6IFtdXG5cbiAgICBpZiBpc0RlcmJ5XG4gICAgICB1c2VyU2NoZW1hLmhhYml0SWRzID0gW11cbiAgICAgIHVzZXJTY2hlbWEuZGFpbHlJZHMgPSBbXVxuICAgICAgdXNlclNjaGVtYS50b2RvSWRzID0gW11cbiAgICAgIHVzZXJTY2hlbWEucmV3YXJkSWRzID0gW11cbiAgICAgIHVzZXJTY2hlbWEudGFza3MgPSB7fVxuICAgIGVsc2VcbiAgICAgIHVzZXJTY2hlbWEuaGFiaXRzID0gW11cbiAgICAgIHVzZXJTY2hlbWEuZGFpbHlzID0gW11cbiAgICAgIHVzZXJTY2hlbWEudG9kb3MgPSBbXVxuICAgICAgdXNlclNjaGVtYS5yZXdhcmRzID0gW11cblxuICAgICMgZGVlcCBjbG9uZSwgZWxzZSBmdXJ0aGVyIG5ldyB1c2VycyBnZXQgZHVwbGljYXRlIG9iamVjdHNcbiAgICBuZXdVc2VyID0gXy5jbG9uZURlZXAgdXNlclNjaGVtYVxuXG4gICAgcmVwZWF0ID0ge206dHJ1ZSx0OnRydWUsdzp0cnVlLHRoOnRydWUsZjp0cnVlLHM6dHJ1ZSxzdTp0cnVlfVxuICAgIGRlZmF1bHRUYXNrcyA9IFtcbiAgICAgIHt0eXBlOiAnaGFiaXQnLCB0ZXh0OiAnMWggUHJvZHVjdGl2ZSBXb3JrJywgbm90ZXM6ICctLSBIYWJpdHM6IENvbnN0YW50bHkgVHJhY2sgLS1cXG5Gb3Igc29tZSBoYWJpdHMsIGl0IG9ubHkgbWFrZXMgc2Vuc2UgdG8gKmdhaW4qIHBvaW50cyAobGlrZSB0aGlzIG9uZSkuJywgdmFsdWU6IDAsIHVwOiB0cnVlLCBkb3duOiBmYWxzZSB9XG4gICAgICB7dHlwZTogJ2hhYml0JywgdGV4dDogJ0VhdCBKdW5rIEZvb2QnLCBub3RlczogJ0ZvciBvdGhlcnMsIGl0IG9ubHkgbWFrZXMgc2Vuc2UgdG8gKmxvc2UqIHBvaW50cycsIHZhbHVlOiAwLCB1cDogZmFsc2UsIGRvd246IHRydWV9XG4gICAgICB7dHlwZTogJ2hhYml0JywgdGV4dDogJ1Rha2UgVGhlIFN0YWlycycsIG5vdGVzOiAnRm9yIHRoZSByZXN0LCBib3RoICsgYW5kIC0gbWFrZSBzZW5zZSAoc3RhaXJzID0gZ2FpbiwgZWxldmF0b3IgPSBsb3NlKScsIHZhbHVlOiAwLCB1cDogdHJ1ZSwgZG93bjogdHJ1ZX1cblxuICAgICAge3R5cGU6ICdkYWlseScsIHRleHQ6ICcxaCBQZXJzb25hbCBQcm9qZWN0Jywgbm90ZXM6ICctLSBEYWlsaWVzOiBDb21wbGV0ZSBPbmNlIGEgRGF5IC0tXFxuQXQgdGhlIGVuZCBvZiBlYWNoIGRheSwgbm9uLWNvbXBsZXRlZCBEYWlsaWVzIGRvY2sgeW91IHBvaW50cy4nLCB2YWx1ZTogMCwgY29tcGxldGVkOiBmYWxzZSwgcmVwZWF0OiByZXBlYXQgfVxuICAgICAge3R5cGU6ICdkYWlseScsIHRleHQ6ICdFeGVyY2lzZScsIG5vdGVzOiBcIklmIHlvdSBhcmUgZG9pbmcgd2VsbCwgdGhleSB0dXJuIGdyZWVuIGFuZCBhcmUgbGVzcyB2YWx1YWJsZSAoZXhwZXJpZW5jZSwgZ29sZCkgYW5kIGxlc3MgZGFtYWdpbmcgKEhQKS4gVGhpcyBtZWFucyB5b3UgY2FuIGVhc2UgdXAgb24gdGhlbSBmb3IgYSBiaXQuXCIsIHZhbHVlOiAzLCBjb21wbGV0ZWQ6IGZhbHNlLCByZXBlYXQ6IHJlcGVhdCB9XG4gICAgICB7dHlwZTogJ2RhaWx5JywgdGV4dDogJzQ1bSBSZWFkaW5nJywgbm90ZXM6ICdCdXQgaWYgeW91IGFyZSBkb2luZyBwb29ybHksIHRoZXkgdHVybiByZWQuIFRoZSB3b3JzZSB5b3UgZG8sIHRoZSBtb3JlIHZhbHVhYmxlIChleHAsIGdvbGQpIGFuZCBtb3JlIGRhbWFnaW5nIChIUCkgdGhlc2UgZ29hbHMgYmVjb21lLiBUaGlzIGVuY291cmFnZXMgeW91IHRvIGZvY3VzIG9uIHlvdXIgc2hvcnRjb21pbmdzLCB0aGUgcmVkcy4nLCB2YWx1ZTogLTEwLCBjb21wbGV0ZWQ6IGZhbHNlLCByZXBlYXQ6IHJlcGVhdCB9XG5cbiAgICAgIHt0eXBlOiAndG9kbycsIHRleHQ6ICdDYWxsIE1vbScsIG5vdGVzOiBcIi0tIFRvZG9zOiBDb21wbGV0ZSBFdmVudHVhbGx5IC0tXFxuTm9uLWNvbXBsZXRlZCBUb2RvcyB3b24ndCBodXJ0IHlvdSwgYnV0IHRoZXkgd2lsbCBiZWNvbWUgbW9yZSB2YWx1YWJsZSBvdmVyIHRpbWUuIFRoaXMgd2lsbCBlbmNvdXJhZ2UgeW91IHRvIHdyYXAgdXAgc3RhbGUgVG9kb3MuXCIsIHZhbHVlOiAtMywgY29tcGxldGVkOiBmYWxzZSB9XG5cbiAgICAgIHt0eXBlOiAncmV3YXJkJywgdGV4dDogJzEgRXBpc29kZSBvZiBHYW1lIG9mIFRocm9uZXMnLCBub3RlczogJy0tIFJld2FyZHM6IFRyZWF0IFlvdXJzZWxmISAtLVxcbkFzIHlvdSBjb21wbGV0ZSBnb2FscywgeW91IGVhcm4gZ29sZCB0byBidXkgcmV3YXJkcy4gQnV5IHRoZW0gbGliZXJhbGx5IC0gcmV3YXJkcyBhcmUgaW50ZWdyYWwgaW4gZm9ybWluZyBnb29kIGhhYml0cy4nLCB2YWx1ZTogMjAgfVxuICAgICAge3R5cGU6ICdyZXdhcmQnLCB0ZXh0OiAnQ2FrZScsIG5vdGVzOiAnQnV0IG9ubHkgYnV5IGlmIHlvdSBoYXZlIGVub3VnaCBnb2xkIC0geW91IGxvc2UgSFAgb3RoZXJ3aXNlLicsIHZhbHVlOiAxMCB9XG4gICAgXVxuXG4gICAgZGVmYXVsdFRhZ3MgPSBbXG4gICAgICB7bmFtZTogJ21vcm5pbmcnfVxuICAgICAge25hbWU6ICdhZnRlcm5vb24nfVxuICAgICAge25hbWU6ICdldmVuaW5nJ31cbiAgICBdXG5cbiAgICBmb3IgdGFzayBpbiBkZWZhdWx0VGFza3NcbiAgICAgIGd1aWQgPSB0YXNrLmlkID0gdXVpZCgpXG4gICAgICBpZiBpc0RlcmJ5XG4gICAgICAgIG5ld1VzZXIudGFza3NbZ3VpZF0gPSB0YXNrXG4gICAgICAgIG5ld1VzZXJbXCIje3Rhc2sudHlwZX1JZHNcIl0ucHVzaCBndWlkXG4gICAgICBlbHNlXG4gICAgICAgIG5ld1VzZXJbXCIje3Rhc2sudHlwZX1zXCJdLnB1c2ggdGFza1xuXG4gICAgZm9yIHRhZyBpbiBkZWZhdWx0VGFnc1xuICAgICAgdGFnLmlkID0gdXVpZCgpXG4gICAgICBuZXdVc2VyLnRhZ3MucHVzaCB0YWdcblxuICAgIG5ld1VzZXJcblxuICBwZXJjZW50OiAoeCx5KSAtPlxuICAgIHg9MSBpZiB4PT0wXG4gICAgTWF0aC5yb3VuZCh4L3kqMTAwKVxuXG4gICMjI1xuICAgIFRoaXMgYWxsb3dzIHlvdSB0byBzZXQgb2JqZWN0IHByb3BlcnRpZXMgYnkgZG90LXBhdGguIEVnLCB5b3UgY2FuIHJ1biBwYXRoU2V0KCdzdGF0cy5ocCcsNTAsdXNlcikgd2hpY2ggaXMgdGhlIHNhbWUgYXNcbiAgICB1c2VyLnN0YXRzLmhwID0gNTAuIFRoaXMgaXMgdXNlZnVsIGJlY2F1c2UgaW4gb3VyIGhhYml0cnBnLXNoYXJlZCBmdW5jdGlvbnMgd2UncmUgcmV0dXJuaW5nIGNoYW5nZXNldHMgYXMge3BhdGg6dmFsdWV9LFxuICAgIHNvIHRoYXQgZGlmZmVyZW50IGNvbnN1bWVycyBjYW4gaW1wbGVtZW50IHNldHRlcnMgdGhlaXIgb3duIHdheS4gRGVyYnkgbmVlZHMgbW9kZWwuc2V0KHBhdGgsIHZhbHVlKSBmb3IgZXhhbXBsZSwgd2hlcmVcbiAgICBBbmd1bGFyIHNldHMgb2JqZWN0IHByb3BlcnRpZXMgZGlyZWN0bHkgLSBpbiB3aGljaCBjYXNlLCB0aGlzIGZ1bmN0aW9uIHdpbGwgYmUgdXNlZC5cbiAgIyMjXG4gIGRvdFNldDogKHBhdGgsIHZhbCwgb2JqKSAtPlxuICAgIHJldHVybiBpZiB+cGF0aC5pbmRleE9mKCd1bmRlZmluZWQnKVxuICAgIGFyciA9IHBhdGguc3BsaXQoJy4nKVxuICAgIF8ucmVkdWNlIGFyciwgKGN1cnIsIG5leHQsIGluZGV4KSAtPlxuICAgICAgaWYgKGFyci5sZW5ndGggLSAxKSA9PSBpbmRleFxuICAgICAgICBjdXJyW25leHRdID0gdmFsXG4gICAgICBjdXJyW25leHRdXG4gICAgLCBvYmpcblxuICBkb3RHZXQ6IChwYXRoLCBvYmopIC0+XG4gICAgcmV0dXJuIHVuZGVmaW5lZCBpZiB+cGF0aC5pbmRleE9mKCd1bmRlZmluZWQnKVxuICAgIF8ucmVkdWNlIHBhdGguc3BsaXQoJy4nKSwgKChjdXJyLCBuZXh0KSAtPiBjdXJyW25leHRdKSwgb2JqXG5cbiAgZGF5c1NpbmNlOiBkYXlzU2luY2VcbiAgc3RhcnRPZldlZWs6IHN0YXJ0T2ZXZWVrXG4gIHN0YXJ0T2ZEYXk6IHN0YXJ0T2ZEYXlcblxuICBzaG91bGREbzogc2hvdWxkRG9cblxuICAjIyNcbiAgICBHZXQgYSByYW5kb20gcHJvcGVydHkgZnJvbSBhbiBvYmplY3RcbiAgICBodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzI1MzIyMTgvcGljay1yYW5kb20tcHJvcGVydHktZnJvbS1hLWphdmFzY3JpcHQtb2JqZWN0XG4gICAgcmV0dXJucyByYW5kb20gcHJvcGVydHkgKHRoZSB2YWx1ZSlcbiAgIyMjXG4gIHJhbmRvbVZhbDogKG9iaikgLT5cbiAgICByZXN1bHQgPSB1bmRlZmluZWRcbiAgICBjb3VudCA9IDBcbiAgICBmb3Iga2V5LCB2YWwgb2Ygb2JqXG4gICAgICByZXN1bHQgPSB2YWwgaWYgTWF0aC5yYW5kb20oKSA8ICgxIC8gKytjb3VudClcbiAgICByZXN1bHRcblxuICAjIyNcbiAgICBSZW1vdmUgd2hpdGVzcGFjZSAjRklYTUUgYXJlIHdlIHVzaW5nIHRoaXMgYW55d3doZXJlPyBTaG91bGQgd2UgYmU/XG4gICMjI1xuICByZW1vdmVXaGl0ZXNwYWNlOiAoc3RyKSAtPlxuICAgIHJldHVybiAnJyB1bmxlc3Mgc3RyXG4gICAgc3RyLnJlcGxhY2UgL1xccy9nLCAnJ1xuXG4gICMjI1xuICAgIEdlbmVyYXRlIHRoZSB1c2VybmFtZSwgc2luY2UgaXQgY2FuIGJlIG9uZSBvZiBtYW55IHRoaW5nczogdGhlaXIgdXNlcm5hbWUsIHRoZWlyIGZhY2Vib29rIGZ1bGxuYW1lLCB0aGVpciBtYW51YWxseS1zZXQgcHJvZmlsZSBuYW1lXG4gICMjI1xuICB1c2VybmFtZTogKGF1dGgsIG92ZXJyaWRlKSAtPlxuICAgICNzb21lIHBlb3BsZSBkZWZpbmUgY3VzdG9tIHByb2ZpbGUgbmFtZSBpbiBBdmF0YXIgLT4gUHJvZmlsZVxuICAgIHJldHVybiBvdmVycmlkZSBpZiBvdmVycmlkZVxuXG4gICAgaWYgYXV0aD8uZmFjZWJvb2s/LmRpc3BsYXlOYW1lP1xuICAgICAgYXV0aC5mYWNlYm9vay5kaXNwbGF5TmFtZVxuICAgIGVsc2UgaWYgYXV0aD8uZmFjZWJvb2s/XG4gICAgICBmYiA9IGF1dGguZmFjZWJvb2tcbiAgICAgIGlmIGZiLl9yYXcgdGhlbiBcIiN7ZmIubmFtZS5naXZlbk5hbWV9ICN7ZmIubmFtZS5mYW1pbHlOYW1lfVwiIGVsc2UgZmIubmFtZVxuICAgIGVsc2UgaWYgYXV0aD8ubG9jYWw/XG4gICAgICBhdXRoLmxvY2FsLnVzZXJuYW1lXG4gICAgZWxzZVxuICAgICAgJ0Fub255bW91cydcblxuICAjIyNcbiAgICBFbmNvZGUgdGhlIGRvd25sb2FkIGxpbmsgZm9yIC5pY3MgaUNhbCBmaWxlXG4gICMjI1xuICBlbmNvZGVpQ2FsTGluazogKHVpZCwgYXBpVG9rZW4pIC0+XG4gICAgbG9jID0gd2luZG93Py5sb2NhdGlvbi5ob3N0IG9yIHByb2Nlc3M/LmVudj8uQkFTRV9VUkwgb3IgJydcbiAgICBlbmNvZGVVUklDb21wb25lbnQgXCJodHRwOi8vI3tsb2N9L3YxL3VzZXJzLyN7dWlkfS9jYWxlbmRhci5pY3M/YXBpVG9rZW49I3thcGlUb2tlbn1cIlxuXG4gICMjI1xuICAgIFVzZXIncyBjdXJyZW50bHkgZXF1aXBlZCBpdGVtXG4gICMjI1xuICBlcXVpcHBlZDogKHR5cGUsIGl0ZW09MCwgcHJlZmVyZW5jZXM9e2dlbmRlcjonbScsIGFybW9yU2V0Oid2MSd9LCBiYWNrZXJUaWVyPTApIC0+XG4gICAge2dlbmRlciwgYXJtb3JTZXR9ID0gcHJlZmVyZW5jZXNcbiAgICBpdGVtID0gfn5pdGVtXG4gICAgYmFja2VyVGllciA9IH5+YmFja2VyVGllclxuXG4gICAgc3dpdGNoIHR5cGVcbiAgICAgIHdoZW4nYXJtb3InXG4gICAgICAgIGlmIGl0ZW0gPiA1XG4gICAgICAgICAgcmV0dXJuICdhcm1vcl82JyBpZiBiYWNrZXJUaWVyID49IDQ1XG4gICAgICAgICAgaXRlbSA9IDUgIyBzZXQgdGhlbSBiYWNrIGlmIHRoZXkncmUgdHJ5aW5nIHRvIGNoZWF0XG4gICAgICAgIGlmIGdlbmRlciBpcyAnZidcbiAgICAgICAgICByZXR1cm4gaWYgKGl0ZW0gaXMgMCkgdGhlbiBcImZfYXJtb3JfI3tpdGVtfV8je2FybW9yU2V0fVwiIGVsc2UgXCJmX2FybW9yXyN7aXRlbX1cIlxuICAgICAgICBlbHNlXG4gICAgICAgICAgcmV0dXJuIFwibV9hcm1vcl8je2l0ZW19XCJcblxuICAgICAgd2hlbiAnaGVhZCdcbiAgICAgICAgaWYgaXRlbSA+IDVcbiAgICAgICAgICByZXR1cm4gJ2hlYWRfNicgaWYgYmFja2VyVGllciA+PSA0NVxuICAgICAgICAgIGl0ZW0gPSA1XG4gICAgICAgIGlmIGdlbmRlciBpcyAnZidcbiAgICAgICAgICByZXR1cm4gaWYgKGl0ZW0gPiAxKSB0aGVuIFwiZl9oZWFkXyN7aXRlbX1fI3thcm1vclNldH1cIiBlbHNlIFwiZl9oZWFkXyN7aXRlbX1cIlxuICAgICAgICBlbHNlXG4gICAgICAgICAgcmV0dXJuIFwibV9oZWFkXyN7aXRlbX1cIlxuXG4gICAgICB3aGVuICdzaGllbGQnXG4gICAgICAgIGlmIGl0ZW0gPiA1XG4gICAgICAgICAgcmV0dXJuICdzaGllbGRfNicgaWYgYmFja2VyVGllciA+PSA0NVxuICAgICAgICAgIGl0ZW0gPSA1XG4gICAgICAgIHJldHVybiBcIiN7cHJlZmVyZW5jZXMuZ2VuZGVyfV9zaGllbGRfI3tpdGVtfVwiXG5cbiAgICAgIHdoZW4gJ3dlYXBvbidcbiAgICAgICAgaWYgaXRlbSA+IDZcbiAgICAgICAgICByZXR1cm4gJ3dlYXBvbl83JyBpZiBiYWNrZXJUaWVyID49IDcwXG4gICAgICAgICAgaXRlbSA9IDZcbiAgICAgICAgcmV0dXJuIFwiI3twcmVmZXJlbmNlcy5nZW5kZXJ9X3dlYXBvbl8je2l0ZW19XCJcblxuICAjIyNcbiAgICBHb2xkIGFtb3VudCBmcm9tIHRoZWlyIG1vbmV5XG4gICMjI1xuICBnb2xkOiAobnVtKSAtPlxuICAgIGlmIG51bVxuICAgICAgcmV0dXJuIChudW0pLnRvRml4ZWQoMSkuc3BsaXQoJy4nKVswXVxuICAgIGVsc2VcbiAgICAgIHJldHVybiBcIjBcIlxuXG4gICMjI1xuICAgIFNpbHZlciBhbW91bnQgZnJvbSB0aGVpciBtb25leVxuICAjIyNcbiAgc2lsdmVyOiAobnVtKSAtPlxuICAgIGlmIG51bVxuICAgICAgKG51bSkudG9GaXhlZCgyKS5zcGxpdCgnLicpWzFdXG4gICAgZWxzZVxuICAgICAgcmV0dXJuIFwiMDBcIlxuXG4gICMjI1xuICAgIFRhc2sgY2xhc3NlcyBnaXZlbiBldmVyeXRoaW5nIGFib3V0IHRoZSBjbGFzc1xuICAjIyNcbiAgdGFza0NsYXNzZXM6ICh0YXNrLCBmaWx0ZXJzLCBkYXlTdGFydCwgbGFzdENyb24sIHNob3dDb21wbGV0ZWQ9ZmFsc2UsIG1haW4pIC0+XG4gICAgcmV0dXJuIHVubGVzcyB0YXNrXG4gICAge3R5cGUsIGNvbXBsZXRlZCwgdmFsdWUsIHJlcGVhdH0gPSB0YXNrXG5cbiAgICAjIGNvbXBsZXRlZCAvIHJlbWFpbmluZyB0b2dnbGVcbiAgICByZXR1cm4gJ2hpZGRlbicgaWYgKHR5cGUgaXMgJ3RvZG8nKSBhbmQgKGNvbXBsZXRlZCAhPSBzaG93Q29tcGxldGVkKVxuXG4gICAgIyBGaWx0ZXJzXG4gICAgaWYgbWFpbiAjIG9ubHkgc2hvdyB3aGVuIG9uIHlvdXIgb3duIGxpc3RcbiAgICAgIGZvciBmaWx0ZXIsIGVuYWJsZWQgb2YgZmlsdGVyc1xuICAgICAgICBpZiBlbmFibGVkIGFuZCBub3QgdGFzay50YWdzP1tmaWx0ZXJdXG4gICAgICAgICAgIyBBbGwgdGhlIG90aGVyIGNsYXNzZXMgZG9uJ3QgbWF0dGVyXG4gICAgICAgICAgcmV0dXJuICdoaWRkZW4nXG5cbiAgICBjbGFzc2VzID0gdHlwZVxuXG4gICAgIyBzaG93IGFzIGNvbXBsZXRlZCBpZiBjb21wbGV0ZWQgKG5hdHVyYWxseSkgb3Igbm90IHJlcXVpcmVkIGZvciB0b2RheVxuICAgIGlmIHR5cGUgaW4gWyd0b2RvJywgJ2RhaWx5J11cbiAgICAgIGlmIGNvbXBsZXRlZCBvciAodHlwZSBpcyAnZGFpbHknIGFuZCAhc2hvdWxkRG8oK25ldyBEYXRlLCB0YXNrLnJlcGVhdCwge2RheVN0YXJ0fSkpXG4gICAgICAgIGNsYXNzZXMgKz0gXCIgY29tcGxldGVkXCJcbiAgICAgIGVsc2VcbiAgICAgICAgY2xhc3NlcyArPSBcIiB1bmNvbXBsZXRlZFwiXG4gICAgZWxzZSBpZiB0eXBlIGlzICdoYWJpdCdcbiAgICAgIGNsYXNzZXMgKz0gJyBoYWJpdC13aWRlJyBpZiB0YXNrLmRvd24gYW5kIHRhc2sudXBcblxuICAgIGlmIHZhbHVlIDwgLTIwXG4gICAgICBjbGFzc2VzICs9ICcgY29sb3Itd29yc3QnXG4gICAgZWxzZSBpZiB2YWx1ZSA8IC0xMFxuICAgICAgY2xhc3NlcyArPSAnIGNvbG9yLXdvcnNlJ1xuICAgIGVsc2UgaWYgdmFsdWUgPCAtMVxuICAgICAgY2xhc3NlcyArPSAnIGNvbG9yLWJhZCdcbiAgICBlbHNlIGlmIHZhbHVlIDwgMVxuICAgICAgY2xhc3NlcyArPSAnIGNvbG9yLW5ldXRyYWwnXG4gICAgZWxzZSBpZiB2YWx1ZSA8IDVcbiAgICAgIGNsYXNzZXMgKz0gJyBjb2xvci1nb29kJ1xuICAgIGVsc2UgaWYgdmFsdWUgPCAxMFxuICAgICAgY2xhc3NlcyArPSAnIGNvbG9yLWJldHRlcidcbiAgICBlbHNlXG4gICAgICBjbGFzc2VzICs9ICcgY29sb3ItYmVzdCdcbiAgICByZXR1cm4gY2xhc3Nlc1xuXG4gICMjI1xuICAgIERvZXMgdGhlIHVzZXIgb3duIHRoaXMgcGV0P1xuICAjIyNcbiAgb3duc1BldDogKHBldCwgdXNlclBldHMpIC0+IF8uaXNBcnJheSh1c2VyUGV0cykgYW5kIHVzZXJQZXRzLmluZGV4T2YocGV0KSAhPSAtMVxuXG4gICMjI1xuICAgIEZyaWVuZGx5IHRpbWVzdGFtcFxuICAjIyNcbiAgZnJpZW5kbHlUaW1lc3RhbXA6ICh0aW1lc3RhbXApIC0+IG1vbWVudCh0aW1lc3RhbXApLmZvcm1hdCgnTU0vREQgaDptbTpzcyBhJylcblxuICAjIyNcbiAgICBEb2VzIHVzZXIgaGF2ZSBuZXcgY2hhdCBtZXNzYWdlcz9cbiAgIyMjXG4gIG5ld0NoYXRNZXNzYWdlczogKG1lc3NhZ2VzLCBsYXN0TWVzc2FnZVNlZW4pIC0+XG4gICAgcmV0dXJuIGZhbHNlIHVubGVzcyBtZXNzYWdlcz8ubGVuZ3RoID4gMFxuICAgIG1lc3NhZ2VzP1swXSBhbmQgKG1lc3NhZ2VzWzBdLmlkICE9IGxhc3RNZXNzYWdlU2VlbilcblxuICAjIyNcbiAgICBSZWxhdGl2ZSBEYXRlXG4gICMjI1xuICByZWxhdGl2ZURhdGU6IHJlcXVpcmUoJ3JlbGF0aXZlLWRhdGUnKVxuXG4gICMjI1xuICAgIGFyZSBhbnkgdGFncyBhY3RpdmU/XG4gICMjI1xuICBub1RhZ3M6ICh0YWdzKSAtPiBfLmlzRW1wdHkodGFncykgb3IgXy5pc0VtcHR5KF8uZmlsdGVyKCB0YWdzLCAodCkgLT4gdCApIClcblxuICAjIyNcbiAgICBBcmUgdGhlcmUgdGFncyBhcHBsaWVkP1xuICAjIyNcbiAgYXBwbGllZFRhZ3M6ICh1c2VyVGFncywgdGFza1RhZ3MpIC0+XG4gICAgYXJyID0gW11cbiAgICBfLmVhY2ggdXNlclRhZ3MsICh0KSAtPlxuICAgICAgcmV0dXJuIHVubGVzcyB0P1xuICAgICAgYXJyLnB1c2godC5uYW1lKSBpZiB0YXNrVGFncz9bdC5pZF1cbiAgICBhcnIuam9pbignLCAnKVxuXG4gICMjI1xuICAgIFVzZXIgc3RhdHNcbiAgIyMjXG5cbiAgdXNlclN0cjogKGxldmVsKSAtPlxuICAgIChsZXZlbC0xKSAvIDJcblxuICB0b3RhbFN0cjogKGxldmVsLCB3ZWFwb249MCkgLT5cbiAgICBzdHIgPSAobGV2ZWwtMSkgLyAyXG4gICAgKHN0ciArIGl0ZW1zLmdldEl0ZW0oJ3dlYXBvbicsIHdlYXBvbikuc3RyZW5ndGgpXG5cbiAgdXNlckRlZjogKGxldmVsKSAtPlxuICAgIChsZXZlbC0xKSAvIDJcblxuICB0b3RhbERlZjogKGxldmVsLCBhcm1vcj0wLCBoZWFkPTAsIHNoaWVsZD0wKSAtPlxuICAgIHRvdGFsRGVmID1cbiAgICAgIChsZXZlbCAtIDEpIC8gMiArICMgZGVmZW5zZVxuICAgICAgaXRlbXMuZ2V0SXRlbSgnYXJtb3InLCBhcm1vcikuZGVmZW5zZSArXG4gICAgICBpdGVtcy5nZXRJdGVtKCdoZWFkJywgaGVhZCkuZGVmZW5zZSArXG4gICAgICBpdGVtcy5nZXRJdGVtKCdzaGllbGQnLCBzaGllbGQpLmRlZmVuc2VcbiAgICByZXR1cm4gdG90YWxEZWZcblxuICBpdGVtVGV4dDogKHR5cGUsIGl0ZW09MCkgLT5cbiAgICBpdGVtcy5nZXRJdGVtKHR5cGUsIGl0ZW0pLnRleHRcblxuICBpdGVtU3RhdDogKHR5cGUsIGl0ZW09MCkgLT5cbiAgICBpID0gaXRlbXMuZ2V0SXRlbSh0eXBlLCBpdGVtKVxuICAgIGlmIHR5cGUgaXMgJ3dlYXBvbicgdGhlbiBpLnN0cmVuZ3RoIGVsc2UgaS5kZWZlbnNlXG5cblxuICAjIyNcbiAgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICBEZXJieS1zcGVjaWZpYyBoZWxwZXJzLiBXaWxsIHJlbW92ZSBhZnRlciB0aGUgcmV3cml0ZSwgbmVlZCB0aGVtIGhlcmUgZm9yIG5vd1xuICAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICMjI1xuXG4gICMjI1xuICBNYWtlIHN1cmUgbW9kZWwuZ2V0KCkgcmV0dXJucyBhbGwgcHJvcGVydGllcywgc2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9jb2RlcGFydHkvcmFjZXIvaXNzdWVzLzExNlxuICAjIyNcbiAgaHlkcmF0ZTogKHNwZWMpIC0+XG4gICAgaWYgXy5pc09iamVjdChzcGVjKSBhbmQgIV8uaXNBcnJheShzcGVjKVxuICAgICAgaHlkcmF0ZWQgPSB7fVxuICAgICAga2V5cyA9IF8ua2V5cyhzcGVjKS5jb25jYXQoXy5rZXlzKHNwZWMuX19wcm90b19fKSlcbiAgICAgIGtleXMuZm9yRWFjaCAoaykgPT4gaHlkcmF0ZWRba10gPSBAaHlkcmF0ZShzcGVjW2tdKVxuICAgICAgaHlkcmF0ZWRcbiAgICBlbHNlIHNwZWMiLCJleHBvcnRzLmFsZ29zID0gcmVxdWlyZSgnLi9hbGdvcy5jb2ZmZWUnKTtcbmV4cG9ydHMuaXRlbXMgPSByZXF1aXJlKCcuL2l0ZW1zLmNvZmZlZScpO1xuZXhwb3J0cy5oZWxwZXJzID0gcmVxdWlyZSgnLi9oZWxwZXJzLmNvZmZlZScpO1xuXG50cnkge1xuICAgIHdpbmRvdztcbiAgICB3aW5kb3cuaGFiaXRycGdTaGFyZWQgPSBleHBvcnRzO1xufSBjYXRjaChlKSB7fSIsIl8gPSByZXF1aXJlICdsb2Rhc2gnXG5cbml0ZW1zID0gbW9kdWxlLmV4cG9ydHMuaXRlbXMgPVxuICB3ZWFwb246IFtcbiAgICB7aW5kZXg6IDAsIHRleHQ6IFwiVHJhaW5pbmcgU3dvcmRcIiwgY2xhc3NlczogXCJ3ZWFwb25fMFwiLCBub3RlczonVHJhaW5pbmcgd2VhcG9uLicsIHN0cmVuZ3RoOiAwLCB2YWx1ZTowfVxuICAgIHtpbmRleDogMSwgdGV4dDogXCJTd29yZFwiLCBjbGFzc2VzOid3ZWFwb25fMScsIG5vdGVzOidJbmNyZWFzZXMgZXhwZXJpZW5jZSBnYWluIGJ5IDMlLicsIHN0cmVuZ3RoOiAzLCB2YWx1ZToyMH1cbiAgICB7aW5kZXg6IDIsIHRleHQ6IFwiQXhlXCIsIGNsYXNzZXM6J3dlYXBvbl8yJywgbm90ZXM6J0luY3JlYXNlcyBleHBlcmllbmNlIGdhaW4gYnkgNiUuJywgc3RyZW5ndGg6IDYsIHZhbHVlOjMwfVxuICAgIHtpbmRleDogMywgdGV4dDogXCJNb3JuaW5nc3RhclwiLCBjbGFzc2VzOid3ZWFwb25fMycsIG5vdGVzOidJbmNyZWFzZXMgZXhwZXJpZW5jZSBnYWluIGJ5IDklLicsIHN0cmVuZ3RoOiA5LCB2YWx1ZTo0NX1cbiAgICB7aW5kZXg6IDQsIHRleHQ6IFwiQmx1ZSBTd29yZFwiLCBjbGFzc2VzOid3ZWFwb25fNCcsIG5vdGVzOidJbmNyZWFzZXMgZXhwZXJpZW5jZSBnYWluIGJ5IDEyJS4nLCBzdHJlbmd0aDogMTIsIHZhbHVlOjY1fVxuICAgIHtpbmRleDogNSwgdGV4dDogXCJSZWQgU3dvcmRcIiwgY2xhc3Nlczond2VhcG9uXzUnLCBub3RlczonSW5jcmVhc2VzIGV4cGVyaWVuY2UgZ2FpbiBieSAxNSUuJywgc3RyZW5ndGg6IDE1LCB2YWx1ZTo5MH1cbiAgICB7aW5kZXg6IDYsIHRleHQ6IFwiR29sZGVuIFN3b3JkXCIsIGNsYXNzZXM6J3dlYXBvbl82Jywgbm90ZXM6J0luY3JlYXNlcyBleHBlcmllbmNlIGdhaW4gYnkgMTglLicsIHN0cmVuZ3RoOiAxOCwgdmFsdWU6MTIwfVxuICAgIHtpbmRleDogNywgdGV4dDogXCJEYXJrIFNvdWxzIEJsYWRlXCIsIGNsYXNzZXM6J3dlYXBvbl83Jywgbm90ZXM6J0luY3JlYXNlcyBleHBlcmllbmNlIGdhaW4gYnkgMjElLicsIHN0cmVuZ3RoOiAyMSwgdmFsdWU6MTUwfVxuICBdXG4gIGFybW9yOiBbXG4gICAge2luZGV4OiAwLCB0ZXh0OiBcIkNsb3RoIEFybW9yXCIsIGNsYXNzZXM6ICdhcm1vcl8wJywgbm90ZXM6J1RyYWluaW5nIGFybW9yLicsIGRlZmVuc2U6IDAsIHZhbHVlOjB9XG4gICAge2luZGV4OiAxLCB0ZXh0OiBcIkxlYXRoZXIgQXJtb3JcIiwgY2xhc3NlczogJ2FybW9yXzEnLCBub3RlczonRGVjcmVhc2VzIEhQIGxvc3MgYnkgNCUuJywgZGVmZW5zZTogNCwgdmFsdWU6MzB9XG4gICAge2luZGV4OiAyLCB0ZXh0OiBcIkNoYWluIE1haWxcIiwgY2xhc3NlczogJ2FybW9yXzInLCBub3RlczonRGVjcmVhc2VzIEhQIGxvc3MgYnkgNiUuJywgZGVmZW5zZTogNiwgdmFsdWU6NDV9XG4gICAge2luZGV4OiAzLCB0ZXh0OiBcIlBsYXRlIE1haWxcIiwgY2xhc3NlczogJ2FybW9yXzMnLCBub3RlczonRGVjcmVhc2VzIEhQIGxvc3MgYnkgNyUuJywgZGVmZW5zZTogNywgdmFsdWU6NjV9XG4gICAge2luZGV4OiA0LCB0ZXh0OiBcIlJlZCBBcm1vclwiLCBjbGFzc2VzOiAnYXJtb3JfNCcsIG5vdGVzOidEZWNyZWFzZXMgSFAgbG9zcyBieSA4JS4nLCBkZWZlbnNlOiA4LCB2YWx1ZTo5MH1cbiAgICB7aW5kZXg6IDUsIHRleHQ6IFwiR29sZGVuIEFybW9yXCIsIGNsYXNzZXM6ICdhcm1vcl81Jywgbm90ZXM6J0RlY3JlYXNlcyBIUCBsb3NzIGJ5IDEwJS4nLCBkZWZlbnNlOiAxMCwgdmFsdWU6MTIwfVxuICAgIHtpbmRleDogNiwgdGV4dDogXCJTaGFkZSBBcm1vclwiLCBjbGFzc2VzOiAnYXJtb3JfNicsIG5vdGVzOidEZWNyZWFzZXMgSFAgbG9zcyBieSAxMiUuJywgZGVmZW5zZTogMTIsIHZhbHVlOjE1MH1cbiAgXVxuICBoZWFkOiBbXG4gICAge2luZGV4OiAwLCB0ZXh0OiBcIk5vIEhlbG1cIiwgY2xhc3NlczogJ2hlYWRfMCcsIG5vdGVzOidUcmFpbmluZyBoZWxtLicsIGRlZmVuc2U6IDAsIHZhbHVlOjB9XG4gICAge2luZGV4OiAxLCB0ZXh0OiBcIkxlYXRoZXIgSGVsbVwiLCBjbGFzc2VzOiAnaGVhZF8xJywgbm90ZXM6J0RlY3JlYXNlcyBIUCBsb3NzIGJ5IDIlLicsIGRlZmVuc2U6IDIsIHZhbHVlOjE1fVxuICAgIHtpbmRleDogMiwgdGV4dDogXCJDaGFpbiBDb2lmXCIsIGNsYXNzZXM6ICdoZWFkXzInLCBub3RlczonRGVjcmVhc2VzIEhQIGxvc3MgYnkgMyUuJywgZGVmZW5zZTogMywgdmFsdWU6MjV9XG4gICAge2luZGV4OiAzLCB0ZXh0OiBcIlBsYXRlIEhlbG1cIiwgY2xhc3NlczogJ2hlYWRfMycsIG5vdGVzOidEZWNyZWFzZXMgSFAgbG9zcyBieSA0JS4nLCBkZWZlbnNlOiA0LCB2YWx1ZTo0NX1cbiAgICB7aW5kZXg6IDQsIHRleHQ6IFwiUmVkIEhlbG1cIiwgY2xhc3NlczogJ2hlYWRfNCcsIG5vdGVzOidEZWNyZWFzZXMgSFAgbG9zcyBieSA1JS4nLCBkZWZlbnNlOiA1LCB2YWx1ZTo2MH1cbiAgICB7aW5kZXg6IDUsIHRleHQ6IFwiR29sZGVuIEhlbG1cIiwgY2xhc3NlczogJ2hlYWRfNScsIG5vdGVzOidEZWNyZWFzZXMgSFAgbG9zcyBieSA2JS4nLCBkZWZlbnNlOiA2LCB2YWx1ZTo4MH1cbiAgICB7aW5kZXg6IDYsIHRleHQ6IFwiU2hhZGUgSGVsbVwiLCBjbGFzc2VzOiAnaGVhZF82Jywgbm90ZXM6J0RlY3JlYXNlcyBIUCBsb3NzIGJ5IDclLicsIGRlZmVuc2U6IDcsIHZhbHVlOjEwMH1cbiAgXVxuICBzaGllbGQ6IFtcbiAgICB7aW5kZXg6IDAsIHRleHQ6IFwiTm8gU2hpZWxkXCIsIGNsYXNzZXM6ICdzaGllbGRfMCcsIG5vdGVzOidObyBTaGllbGQuJywgZGVmZW5zZTogMCwgdmFsdWU6MH1cbiAgICB7aW5kZXg6IDEsIHRleHQ6IFwiV29vZGVuIFNoaWVsZFwiLCBjbGFzc2VzOiAnc2hpZWxkXzEnLCBub3RlczonRGVjcmVhc2VzIEhQIGxvc3MgYnkgMyUnLCBkZWZlbnNlOiAzLCB2YWx1ZToyMH1cbiAgICB7aW5kZXg6IDIsIHRleHQ6IFwiQnVja2xlclwiLCBjbGFzc2VzOiAnc2hpZWxkXzInLCBub3RlczonRGVjcmVhc2VzIEhQIGxvc3MgYnkgNCUuJywgZGVmZW5zZTogNCwgdmFsdWU6MzV9XG4gICAge2luZGV4OiAzLCB0ZXh0OiBcIlJlaW5mb3JjZWQgU2hpZWxkXCIsIGNsYXNzZXM6ICdzaGllbGRfMycsIG5vdGVzOidEZWNyZWFzZXMgSFAgbG9zcyBieSA1JS4nLCBkZWZlbnNlOiA1LCB2YWx1ZTo1NX1cbiAgICB7aW5kZXg6IDQsIHRleHQ6IFwiUmVkIFNoaWVsZFwiLCBjbGFzc2VzOiAnc2hpZWxkXzQnLCBub3RlczonRGVjcmVhc2VzIEhQIGxvc3MgYnkgNyUuJywgZGVmZW5zZTogNywgdmFsdWU6NzB9XG4gICAge2luZGV4OiA1LCB0ZXh0OiBcIkdvbGRlbiBTaGllbGRcIiwgY2xhc3NlczogJ3NoaWVsZF81Jywgbm90ZXM6J0RlY3JlYXNlcyBIUCBsb3NzIGJ5IDglLicsIGRlZmVuc2U6IDgsIHZhbHVlOjkwfVxuICAgIHtpbmRleDogNiwgdGV4dDogXCJUb3JtZW50ZWQgU2t1bGxcIiwgY2xhc3NlczogJ3NoaWVsZF82Jywgbm90ZXM6J0RlY3JlYXNlcyBIUCBsb3NzIGJ5IDklLicsIGRlZmVuc2U6IDksIHZhbHVlOjEyMH1cbiAgXVxuICBwb3Rpb246IHt0eXBlOiAncG90aW9uJywgdGV4dDogXCJQb3Rpb25cIiwgbm90ZXM6IFwiUmVjb3ZlciAxNSBIUCAoSW5zdGFudCBVc2UpXCIsIHZhbHVlOiAyNSwgY2xhc3NlczogJ3BvdGlvbid9XG4gIHJlcm9sbDoge3R5cGU6ICdyZXJvbGwnLCB0ZXh0OiBcIlJlLVJvbGxcIiwgY2xhc3NlczogJ3Jlcm9sbCcsIG5vdGVzOiBcIlJlc2V0cyB5b3VyIHRhc2sgdmFsdWVzIGJhY2sgdG8gMCAoeWVsbG93KS4gVXNlZnVsIHdoZW4gZXZlcnl0aGluZydzIHJlZCBhbmQgaXQncyBoYXJkIHRvIHN0YXkgYWxpdmUuXCIsIHZhbHVlOjAgfVxuXG4gIHBldHM6IFtcbiAgICB7dGV4dDogJ1dvbGYnLCBuYW1lOiAnV29sZicsIHZhbHVlOiAzfVxuICAgIHt0ZXh0OiAnVGlnZXIgQ3ViJywgbmFtZTogJ1RpZ2VyQ3ViJywgdmFsdWU6IDN9XG4gICAgI3t0ZXh0OiAnUG9sYXIgQmVhciBDdWInLCBuYW1lOiAnUG9sYXJCZWFyQ3ViJywgdmFsdWU6IDN9ICNjb21tZW50ZWQgb3V0IGJlY2F1c2UgdGhlcmUgYXJlIG5vIHBvbGFyYmVhciBtb2RpZmllcnMgeWV0LCBzcGVjaWFsIGRyb3A/XG4gICAge3RleHQ6ICdQYW5kYSBDdWInLCBuYW1lOiAnUGFuZGFDdWInLCB2YWx1ZTogM31cbiAgICB7dGV4dDogJ0xpb24gQ3ViJywgbmFtZTogJ0xpb25DdWInLCB2YWx1ZTogM31cbiAgICB7dGV4dDogJ0ZveCcsIG5hbWU6ICdGb3gnLCB2YWx1ZTogM31cbiAgICB7dGV4dDogJ0ZseWluZyBQaWcnLCBuYW1lOiAnRmx5aW5nUGlnJywgdmFsdWU6IDN9XG4gICAge3RleHQ6ICdEcmFnb24nLCBuYW1lOiAnRHJhZ29uJywgdmFsdWU6IDN9XG4gICAge3RleHQ6ICdDYWN0dXMnLCBuYW1lOiAnQ2FjdHVzJywgdmFsdWU6IDN9XG4gICAge3RleHQ6ICdCZWFyIEN1YicsIG5hbWU6ICdCZWFyQ3ViJywgdmFsdWU6IDN9XG4gIF1cblxuICBoYXRjaGluZ1BvdGlvbnM6IFtcbiAgICB7dGV4dDogJ0Jhc2UnLCBuYW1lOiAnQmFzZScsIG5vdGVzOiBcIkhhdGNoZXMgeW91ciBwZXQgaW4gaXQncyBiYXNlIGZvcm0uXCIsIHZhbHVlOiAxfVxuICAgIHt0ZXh0OiAnV2hpdGUnLCBuYW1lOiAnV2hpdGUnLCBub3RlczogJ1R1cm5zIHlvdXIgYW5pbWFsIGludG8gYSBXaGl0ZSBwZXQuJywgdmFsdWU6IDJ9XG4gICAge3RleHQ6ICdEZXNlcnQnLCBuYW1lOiAnRGVzZXJ0Jywgbm90ZXM6ICdUdXJucyB5b3VyIGFuaW1hbCBpbnRvIGEgRGVzZXJ0IHBldC4nLCB2YWx1ZTogMn1cbiAgICB7dGV4dDogJ1JlZCcsIG5hbWU6ICdSZWQnLCBub3RlczogJ1R1cm5zIHlvdXIgYW5pbWFsIGludG8gYSBSZWQgcGV0LicsIHZhbHVlOiAzfVxuICAgIHt0ZXh0OiAnU2hhZGUnLCBuYW1lOiAnU2hhZGUnLCBub3RlczogJ1R1cm5zIHlvdXIgYW5pbWFsIGludG8gYSBTaGFkZSBwZXQuJywgdmFsdWU6IDN9XG4gICAge3RleHQ6ICdTa2VsZXRvbicsIG5hbWU6ICdTa2VsZXRvbicsIG5vdGVzOiAnVHVybnMgeW91ciBhbmltYWwgaW50byBhIFNrZWxldG9uLicsIHZhbHVlOiAzfVxuICAgIHt0ZXh0OiAnWm9tYmllJywgbmFtZTogJ1pvbWJpZScsIG5vdGVzOiAnVHVybnMgeW91ciBhbmltYWwgaW50byBhIFpvbWJpZS4nLCB2YWx1ZTogNH1cbiAgICB7dGV4dDogJ0NvdHRvbiBDYW5keSBQaW5rJywgbmFtZTogJ0NvdHRvbkNhbmR5UGluaycsIG5vdGVzOiAnVHVybnMgeW91ciBhbmltYWwgaW50byBhIENvdHRvbiBDYW5keSBQaW5rIHBldC4nLCB2YWx1ZTogNH1cbiAgICB7dGV4dDogJ0NvdHRvbiBDYW5keSBCbHVlJywgbmFtZTogJ0NvdHRvbkNhbmR5Qmx1ZScsIG5vdGVzOiAnVHVybnMgeW91ciBhbmltYWwgaW50byBhIENvdHRvbiBDYW5keSBCbHVlIHBldC4nLCB2YWx1ZTogNH1cbiAgICB7dGV4dDogJ0dvbGRlbicsIG5hbWU6ICdHb2xkZW4nLCBub3RlczogJ1R1cm5zIHlvdXIgYW5pbWFsIGludG8gYSBHb2xkZW4gcGV0LicsIHZhbHVlOiA1fVxuICBdXG5cbiMgYWRkIFwidHlwZVwiIHRvIGVhY2ggaXRlbSwgc28gd2UgY2FuIHJlZmVyZW5jZSB0aGF0IGFzIFwid2VhcG9uXCIgb3IgXCJhcm1vclwiIGluIHRoZSBodG1sXG5fLmVhY2ggWyd3ZWFwb24nLCAnYXJtb3InLCAnaGVhZCcsICdzaGllbGQnXSwgKGtleSkgLT5cbiAgXy5lYWNoIGl0ZW1zW2tleV0sIChpdGVtKSAtPiBpdGVtLnR5cGUgPSBrZXlcblxuXy5lYWNoIGl0ZW1zLnBldHMsIChwZXQpIC0+IHBldC5ub3RlcyA9ICdGaW5kIGEgaGF0Y2hpbmcgcG90aW9uIHRvIHBvdXIgb24gdGhpcyBlZ2csIGFuZCBpdCB3aWxsIGhhdGNoIGludG8gYSBsb3lhbCBwZXQuJ1xuXy5lYWNoIGl0ZW1zLmhhdGNoaW5nUG90aW9ucywgKGhhdGNoaW5nUG90aW9uKSAtPiBoYXRjaGluZ1BvdGlvbi5ub3RlcyA9IFwiUG91ciB0aGlzIG9uIGFuIGVnZywgYW5kIGl0IHdpbGwgaGF0Y2ggYXMgYSAje2hhdGNoaW5nUG90aW9uLnRleHR9IHBldC5cIlxuXG5tb2R1bGUuZXhwb3J0cy5idXlJdGVtID0gKHVzZXIsIHR5cGUsIG9wdGlvbnM9e30pIC0+XG4gIF8uZGVmYXVsdHMgb3B0aW9ucywge3BhdGhzOiB7fX1cblxuICBuZXh0SXRlbSA9XG4gICAgICBpZiB0eXBlIGlzICdwb3Rpb24nIHRoZW4gaXRlbXMucG90aW9uXG4gICAgICBlbHNlIG1vZHVsZS5leHBvcnRzLmdldEl0ZW0gdHlwZSwgKCh+fnVzZXIuaXRlbXNbdHlwZV0gb3IgMCkgKyAxKVxuXG4gIHJldHVybiBmYWxzZSBpZiArdXNlci5zdGF0cy5ncCA8ICtuZXh0SXRlbS52YWx1ZVxuICBpZiBuZXh0SXRlbS50eXBlIGlzICdwb3Rpb24nXG4gICAgdXNlci5zdGF0cy5ocCArPSAxNTtcbiAgICB1c2VyLnN0YXRzLmhwID0gNTAgaWYgdXNlci5zdGF0cy5ocCA+IDUwXG4gICAgb3B0aW9ucy5wYXRoc1snc3RhdHMuaHAnXSA9IHRydWVcbiAgZWxzZVxuICAgIHVzZXIuaXRlbXNbdHlwZV0gPSB+fm5leHRJdGVtLmluZGV4XG4gICAgb3B0aW9ucy5wYXRoc1tcIml0ZW1zLiN7dHlwZX1cIl0gPSB0cnVlXG4gIHVzZXIuc3RhdHMuZ3AgLT0gK25leHRJdGVtLnZhbHVlXG4gIG9wdGlvbnMucGF0aHNbJ3N0YXRzLmdwJ10gPSB0cnVlXG4gIHRydWVcblxuIyMjXG4gIHVwZGF0ZSBzdG9yZVxuIyMjXG5tb2R1bGUuZXhwb3J0cy51cGRhdGVTdG9yZSA9ICh1c2VyKSAtPlxuICBjaGFuZ2VzID0ge31cbiAgXy5lYWNoIFsnd2VhcG9uJywgJ2FybW9yJywgJ3NoaWVsZCcsICdoZWFkJ10sICh0eXBlKSAtPlxuICAgIGkgPSB+fih1c2VyLml0ZW1zP1t0eXBlXSBvciAwKSArIDFcbiAgICBzaG93TmV4dCA9IHRydWVcbiAgICBpZiBpIGlzIGl0ZW1zW3R5cGVdLmxlbmd0aCAtIDFcbiAgICAgIGlmICh0eXBlIGluIFsnYXJtb3InLCAnc2hpZWxkJywgJ2hlYWQnXSlcbiAgICAgICAgc2hvd05leHQgPSB1c2VyLmJhY2tlcj8udGllciBhbmQgdXNlci5iYWNrZXIudGllciA+PSA0NSAjIGJhY2tlciBhcm1vclxuICAgICAgZWxzZVxuICAgICAgICBzaG93TmV4dCA9IHVzZXIuYmFja2VyPy50aWVyIGFuZCB1c2VyLmJhY2tlci50aWVyID49IDcwICMgYmFja2VyIHdlYXBvblxuICAgIGVsc2UgaWYgaSBpcyBpdGVtc1t0eXBlXS5sZW5ndGhcbiAgICAgIHNob3dOZXh0ID0gZmFsc2VcbiAgICBjaGFuZ2VzW3R5cGVdID0gaWYgc2hvd05leHQgdGhlbiBpdGVtc1t0eXBlXVtpXSBlbHNlIHtoaWRlOnRydWV9XG4gIGNoYW5nZXMucG90aW9uID0gaXRlbXMucG90aW9uXG4gIGNoYW5nZXMucmVyb2xsID0gIGl0ZW1zLnJlcm9sbFxuICBjaGFuZ2VzXG5cbiMjI1xuICBHZXRzIGFuIGl0bWUsIGFuZCBjYXBzIG1heCB0byB0aGUgbGFzdCBpdGVtIGluIGl0cyBhcnJheVxuIyMjXG5tb2R1bGUuZXhwb3J0cy5nZXRJdGVtID0gKHR5cGUsIGluZGV4PTApIC0+XG4gIGkgPSBpZiAofn5pbmRleCA+IGl0ZW1zW3R5cGVdLmxlbmd0aCAtIDEpIHRoZW4gaXRlbXNbdHlwZV0ubGVuZ3RoIC0gMSBlbHNlIH5+aW5kZXhcbiAgaXRlbXNbdHlwZV1baV1cbiJdfQ==
|
|
; |