Created
September 1, 2020 12:22
-
-
Save ceremcem/f378161ac6a3c9a224567b6e06c7080c to your computer and use it in GitHub Desktop.
template.ls bundled with Rollup (has a problem)
This file has been truncated, but you can view the full file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
var util = require('util'); | |
var os = require('os'); | |
var buffer = require('buffer'); | |
var crypto = require('crypto'); | |
var tty = require('tty'); | |
var fs$1 = require('fs'); | |
var net = require('net'); | |
var ractive = require('ractive'); | |
var path = require('path'); | |
var preludeLs = require('prelude-ls'); | |
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } | |
var util__default = /*#__PURE__*/_interopDefaultLegacy(util); | |
var os__default = /*#__PURE__*/_interopDefaultLegacy(os); | |
var buffer__default = /*#__PURE__*/_interopDefaultLegacy(buffer); | |
var crypto__default = /*#__PURE__*/_interopDefaultLegacy(crypto); | |
var tty__default = /*#__PURE__*/_interopDefaultLegacy(tty); | |
var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs$1); | |
var net__default = /*#__PURE__*/_interopDefaultLegacy(net); | |
var ractive__default = /*#__PURE__*/_interopDefaultLegacy(ractive); | |
var path__default = /*#__PURE__*/_interopDefaultLegacy(path); | |
var preludeLs__default = /*#__PURE__*/_interopDefaultLegacy(preludeLs); | |
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; | |
function createCommonjsModule(fn, basedir, module) { | |
return module = { | |
path: basedir, | |
exports: {}, | |
require: function (path, base) { | |
return commonjsRequire(path, (base === undefined || base === null) ? module.path : base); | |
} | |
}, fn(module, module.exports), module.exports; | |
} | |
function getCjsExportFromNamespace (n) { | |
return n && n['default'] || n; | |
} | |
function commonjsRequire () { | |
throw new Error('Dynamic requires are not currently supported by @rollup/plugin-commonjs'); | |
} | |
var styles_1 = createCommonjsModule(function (module) { | |
/* | |
The MIT License (MIT) | |
Copyright (c) Sindre Sorhus <[email protected]> (sindresorhus.com) | |
Permission is hereby granted, free of charge, to any person obtaining a copy | |
of this software and associated documentation files (the "Software"), to deal | |
in the Software without restriction, including without limitation the rights | |
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
copies of the Software, and to permit persons to whom the Software is | |
furnished to do so, subject to the following conditions: | |
The above copyright notice and this permission notice shall be included in | |
all copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
THE SOFTWARE. | |
*/ | |
var styles = {}; | |
module['exports'] = styles; | |
var codes = { | |
reset: [0, 0], | |
bold: [1, 22], | |
dim: [2, 22], | |
italic: [3, 23], | |
underline: [4, 24], | |
inverse: [7, 27], | |
hidden: [8, 28], | |
strikethrough: [9, 29], | |
black: [30, 39], | |
red: [31, 39], | |
green: [32, 39], | |
yellow: [33, 39], | |
blue: [34, 39], | |
magenta: [35, 39], | |
cyan: [36, 39], | |
white: [37, 39], | |
gray: [90, 39], | |
grey: [90, 39], | |
brightRed: [91, 39], | |
brightGreen: [92, 39], | |
brightYellow: [93, 39], | |
brightBlue: [94, 39], | |
brightMagenta: [95, 39], | |
brightCyan: [96, 39], | |
brightWhite: [97, 39], | |
bgBlack: [40, 49], | |
bgRed: [41, 49], | |
bgGreen: [42, 49], | |
bgYellow: [43, 49], | |
bgBlue: [44, 49], | |
bgMagenta: [45, 49], | |
bgCyan: [46, 49], | |
bgWhite: [47, 49], | |
bgGray: [100, 49], | |
bgGrey: [100, 49], | |
bgBrightRed: [101, 49], | |
bgBrightGreen: [102, 49], | |
bgBrightYellow: [103, 49], | |
bgBrightBlue: [104, 49], | |
bgBrightMagenta: [105, 49], | |
bgBrightCyan: [106, 49], | |
bgBrightWhite: [107, 49], | |
// legacy styles for colors pre v1.0.0 | |
blackBG: [40, 49], | |
redBG: [41, 49], | |
greenBG: [42, 49], | |
yellowBG: [43, 49], | |
blueBG: [44, 49], | |
magentaBG: [45, 49], | |
cyanBG: [46, 49], | |
whiteBG: [47, 49], | |
}; | |
Object.keys(codes).forEach(function(key) { | |
var val = codes[key]; | |
var style = styles[key] = []; | |
style.open = '\u001b[' + val[0] + 'm'; | |
style.close = '\u001b[' + val[1] + 'm'; | |
}); | |
}); | |
/* | |
MIT License | |
Copyright (c) Sindre Sorhus <[email protected]> (sindresorhus.com) | |
Permission is hereby granted, free of charge, to any person obtaining a copy of | |
this software and associated documentation files (the "Software"), to deal in | |
the Software without restriction, including without limitation the rights to | |
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | |
of the Software, and to permit persons to whom the Software is furnished to do | |
so, subject to the following conditions: | |
The above copyright notice and this permission notice shall be included in all | |
copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
SOFTWARE. | |
*/ | |
var hasFlag = function(flag, argv) { | |
argv = argv || process.argv; | |
var terminatorPos = argv.indexOf('--'); | |
var prefix = /^-{1,2}/.test(flag) ? '' : '--'; | |
var pos = argv.indexOf(prefix + flag); | |
return pos !== -1 && (terminatorPos === -1 ? true : pos < terminatorPos); | |
}; | |
var env = process.env; | |
var forceColor = void 0; | |
if (hasFlag('no-color') || hasFlag('no-colors') || hasFlag('color=false')) { | |
forceColor = false; | |
} else if (hasFlag('color') || hasFlag('colors') || hasFlag('color=true') | |
|| hasFlag('color=always')) { | |
forceColor = true; | |
} | |
if ('FORCE_COLOR' in env) { | |
forceColor = env.FORCE_COLOR.length === 0 | |
|| parseInt(env.FORCE_COLOR, 10) !== 0; | |
} | |
function translateLevel(level) { | |
if (level === 0) { | |
return false; | |
} | |
return { | |
level: level, | |
hasBasic: true, | |
has256: level >= 2, | |
has16m: level >= 3, | |
}; | |
} | |
function supportsColor(stream) { | |
if (forceColor === false) { | |
return 0; | |
} | |
if (hasFlag('color=16m') || hasFlag('color=full') | |
|| hasFlag('color=truecolor')) { | |
return 3; | |
} | |
if (hasFlag('color=256')) { | |
return 2; | |
} | |
if (stream && !stream.isTTY && forceColor !== true) { | |
return 0; | |
} | |
var min = forceColor ? 1 : 0; | |
if (process.platform === 'win32') { | |
// Node.js 7.5.0 is the first version of Node.js to include a patch to | |
// libuv that enables 256 color output on Windows. Anything earlier and it | |
// won't work. However, here we target Node.js 8 at minimum as it is an LTS | |
// release, and Node.js 7 is not. Windows 10 build 10586 is the first | |
// Windows release that supports 256 colors. Windows 10 build 14931 is the | |
// first release that supports 16m/TrueColor. | |
var osRelease = os__default['default'].release().split('.'); | |
if (Number(process.versions.node.split('.')[0]) >= 8 | |
&& Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) { | |
return Number(osRelease[2]) >= 14931 ? 3 : 2; | |
} | |
return 1; | |
} | |
if ('CI' in env) { | |
if (['TRAVIS', 'CIRCLECI', 'APPVEYOR', 'GITLAB_CI'].some(function(sign) { | |
return sign in env; | |
}) || env.CI_NAME === 'codeship') { | |
return 1; | |
} | |
return min; | |
} | |
if ('TEAMCITY_VERSION' in env) { | |
return (/^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0 | |
); | |
} | |
if ('TERM_PROGRAM' in env) { | |
var version = parseInt((env.TERM_PROGRAM_VERSION || '').split('.')[0], 10); | |
switch (env.TERM_PROGRAM) { | |
case 'iTerm.app': | |
return version >= 3 ? 3 : 2; | |
case 'Hyper': | |
return 3; | |
case 'Apple_Terminal': | |
return 2; | |
// No default | |
} | |
} | |
if (/-256(color)?$/i.test(env.TERM)) { | |
return 2; | |
} | |
if (/^screen|^xterm|^vt100|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) { | |
return 1; | |
} | |
if ('COLORTERM' in env) { | |
return 1; | |
} | |
if (env.TERM === 'dumb') { | |
return min; | |
} | |
return min; | |
} | |
function getSupportLevel(stream) { | |
var level = supportsColor(stream); | |
return translateLevel(level); | |
} | |
var supportsColors = { | |
supportsColor: getSupportLevel, | |
stdout: getSupportLevel(process.stdout), | |
stderr: getSupportLevel(process.stderr), | |
}; | |
var trap = createCommonjsModule(function (module) { | |
module['exports'] = function runTheTrap(text, options) { | |
var result = ''; | |
text = text || 'Run the trap, drop the bass'; | |
text = text.split(''); | |
var trap = { | |
a: ['\u0040', '\u0104', '\u023a', '\u0245', '\u0394', '\u039b', '\u0414'], | |
b: ['\u00df', '\u0181', '\u0243', '\u026e', '\u03b2', '\u0e3f'], | |
c: ['\u00a9', '\u023b', '\u03fe'], | |
d: ['\u00d0', '\u018a', '\u0500', '\u0501', '\u0502', '\u0503'], | |
e: ['\u00cb', '\u0115', '\u018e', '\u0258', '\u03a3', '\u03be', '\u04bc', | |
'\u0a6c'], | |
f: ['\u04fa'], | |
g: ['\u0262'], | |
h: ['\u0126', '\u0195', '\u04a2', '\u04ba', '\u04c7', '\u050a'], | |
i: ['\u0f0f'], | |
j: ['\u0134'], | |
k: ['\u0138', '\u04a0', '\u04c3', '\u051e'], | |
l: ['\u0139'], | |
m: ['\u028d', '\u04cd', '\u04ce', '\u0520', '\u0521', '\u0d69'], | |
n: ['\u00d1', '\u014b', '\u019d', '\u0376', '\u03a0', '\u048a'], | |
o: ['\u00d8', '\u00f5', '\u00f8', '\u01fe', '\u0298', '\u047a', '\u05dd', | |
'\u06dd', '\u0e4f'], | |
p: ['\u01f7', '\u048e'], | |
q: ['\u09cd'], | |
r: ['\u00ae', '\u01a6', '\u0210', '\u024c', '\u0280', '\u042f'], | |
s: ['\u00a7', '\u03de', '\u03df', '\u03e8'], | |
t: ['\u0141', '\u0166', '\u0373'], | |
u: ['\u01b1', '\u054d'], | |
v: ['\u05d8'], | |
w: ['\u0428', '\u0460', '\u047c', '\u0d70'], | |
x: ['\u04b2', '\u04fe', '\u04fc', '\u04fd'], | |
y: ['\u00a5', '\u04b0', '\u04cb'], | |
z: ['\u01b5', '\u0240'], | |
}; | |
text.forEach(function(c) { | |
c = c.toLowerCase(); | |
var chars = trap[c] || [' ']; | |
var rand = Math.floor(Math.random() * chars.length); | |
if (typeof trap[c] !== 'undefined') { | |
result += trap[c][rand]; | |
} else { | |
result += c; | |
} | |
}); | |
return result; | |
}; | |
}); | |
var zalgo = createCommonjsModule(function (module) { | |
// please no | |
module['exports'] = function zalgo(text, options) { | |
text = text || ' he is here '; | |
var soul = { | |
'up': [ | |
'̍', '̎', '̄', '̅', | |
'̿', '̑', '̆', '̐', | |
'͒', '͗', '͑', '̇', | |
'̈', '̊', '͂', '̓', | |
'̈', '͊', '͋', '͌', | |
'̃', '̂', '̌', '͐', | |
'̀', '́', '̋', '̏', | |
'̒', '̓', '̔', '̽', | |
'̉', 'ͣ', 'ͤ', 'ͥ', | |
'ͦ', 'ͧ', 'ͨ', 'ͩ', | |
'ͪ', 'ͫ', 'ͬ', 'ͭ', | |
'ͮ', 'ͯ', '̾', '͛', | |
'͆', '̚', | |
], | |
'down': [ | |
'̖', '̗', '̘', '̙', | |
'̜', '̝', '̞', '̟', | |
'̠', '̤', '̥', '̦', | |
'̩', '̪', '̫', '̬', | |
'̭', '̮', '̯', '̰', | |
'̱', '̲', '̳', '̹', | |
'̺', '̻', '̼', 'ͅ', | |
'͇', '͈', '͉', '͍', | |
'͎', '͓', '͔', '͕', | |
'͖', '͙', '͚', '̣', | |
], | |
'mid': [ | |
'̕', '̛', '̀', '́', | |
'͘', '̡', '̢', '̧', | |
'̨', '̴', '̵', '̶', | |
'͜', '͝', '͞', | |
'͟', '͠', '͢', '̸', | |
'̷', '͡', ' ҉', | |
], | |
}; | |
var all = [].concat(soul.up, soul.down, soul.mid); | |
function randomNumber(range) { | |
var r = Math.floor(Math.random() * range); | |
return r; | |
} | |
function isChar(character) { | |
var bool = false; | |
all.filter(function(i) { | |
bool = (i === character); | |
}); | |
return bool; | |
} | |
function heComes(text, options) { | |
var result = ''; | |
var counts; | |
var l; | |
options = options || {}; | |
options['up'] = | |
typeof options['up'] !== 'undefined' ? options['up'] : true; | |
options['mid'] = | |
typeof options['mid'] !== 'undefined' ? options['mid'] : true; | |
options['down'] = | |
typeof options['down'] !== 'undefined' ? options['down'] : true; | |
options['size'] = | |
typeof options['size'] !== 'undefined' ? options['size'] : 'maxi'; | |
text = text.split(''); | |
for (l in text) { | |
if (isChar(l)) { | |
continue; | |
} | |
result = result + text[l]; | |
counts = {'up': 0, 'down': 0, 'mid': 0}; | |
switch (options.size) { | |
case 'mini': | |
counts.up = randomNumber(8); | |
counts.mid = randomNumber(2); | |
counts.down = randomNumber(8); | |
break; | |
case 'maxi': | |
counts.up = randomNumber(16) + 3; | |
counts.mid = randomNumber(4) + 1; | |
counts.down = randomNumber(64) + 3; | |
break; | |
default: | |
counts.up = randomNumber(8) + 1; | |
counts.mid = randomNumber(6) / 2; | |
counts.down = randomNumber(8) + 1; | |
break; | |
} | |
var arr = ['up', 'mid', 'down']; | |
for (var d in arr) { | |
var index = arr[d]; | |
for (var i = 0; i <= counts[index]; i++) { | |
if (options[index]) { | |
result = result + soul[index][randomNumber(soul[index].length)]; | |
} | |
} | |
} | |
} | |
return result; | |
} | |
// don't summon him | |
return heComes(text, options); | |
}; | |
}); | |
var america = createCommonjsModule(function (module) { | |
module['exports'] = function(colors) { | |
return function(letter, i, exploded) { | |
if (letter === ' ') return letter; | |
switch (i%3) { | |
case 0: return colors.red(letter); | |
case 1: return colors.white(letter); | |
case 2: return colors.blue(letter); | |
} | |
}; | |
}; | |
}); | |
var zebra = createCommonjsModule(function (module) { | |
module['exports'] = function(colors) { | |
return function(letter, i, exploded) { | |
return i % 2 === 0 ? letter : colors.inverse(letter); | |
}; | |
}; | |
}); | |
var rainbow = createCommonjsModule(function (module) { | |
module['exports'] = function(colors) { | |
// RoY G BiV | |
var rainbowColors = ['red', 'yellow', 'green', 'blue', 'magenta']; | |
return function(letter, i, exploded) { | |
if (letter === ' ') { | |
return letter; | |
} else { | |
return colors[rainbowColors[i++ % rainbowColors.length]](letter); | |
} | |
}; | |
}; | |
}); | |
var random = createCommonjsModule(function (module) { | |
module['exports'] = function(colors) { | |
var available = ['underline', 'inverse', 'grey', 'yellow', 'red', 'green', | |
'blue', 'white', 'cyan', 'magenta', 'brightYellow', 'brightRed', | |
'brightGreen', 'brightBlue', 'brightWhite', 'brightCyan', 'brightMagenta']; | |
return function(letter, i, exploded) { | |
return letter === ' ' ? letter : | |
colors[ | |
available[Math.round(Math.random() * (available.length - 2))] | |
](letter); | |
}; | |
}; | |
}); | |
var colors_1 = createCommonjsModule(function (module) { | |
/* | |
The MIT License (MIT) | |
Original Library | |
- Copyright (c) Marak Squires | |
Additional functionality | |
- Copyright (c) Sindre Sorhus <[email protected]> (sindresorhus.com) | |
Permission is hereby granted, free of charge, to any person obtaining a copy | |
of this software and associated documentation files (the "Software"), to deal | |
in the Software without restriction, including without limitation the rights | |
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
copies of the Software, and to permit persons to whom the Software is | |
furnished to do so, subject to the following conditions: | |
The above copyright notice and this permission notice shall be included in | |
all copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
THE SOFTWARE. | |
*/ | |
var colors = {}; | |
module['exports'] = colors; | |
colors.themes = {}; | |
var ansiStyles = colors.styles = styles_1; | |
var defineProps = Object.defineProperties; | |
var newLineRegex = new RegExp(/[\r\n]+/g); | |
colors.supportsColor = supportsColors.supportsColor; | |
if (typeof colors.enabled === 'undefined') { | |
colors.enabled = colors.supportsColor() !== false; | |
} | |
colors.enable = function() { | |
colors.enabled = true; | |
}; | |
colors.disable = function() { | |
colors.enabled = false; | |
}; | |
colors.stripColors = colors.strip = function(str) { | |
return ('' + str).replace(/\x1B\[\d+m/g, ''); | |
}; | |
// eslint-disable-next-line no-unused-vars | |
var stylize = colors.stylize = function stylize(str, style) { | |
if (!colors.enabled) { | |
return str+''; | |
} | |
var styleMap = ansiStyles[style]; | |
// Stylize should work for non-ANSI styles, too | |
if(!styleMap && style in colors){ | |
// Style maps like trap operate as functions on strings; | |
// they don't have properties like open or close. | |
return colors[style](str); | |
} | |
return styleMap.open + str + styleMap.close; | |
}; | |
var matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g; | |
var escapeStringRegexp = function(str) { | |
if (typeof str !== 'string') { | |
throw new TypeError('Expected a string'); | |
} | |
return str.replace(matchOperatorsRe, '\\$&'); | |
}; | |
function build(_styles) { | |
var builder = function builder() { | |
return applyStyle.apply(builder, arguments); | |
}; | |
builder._styles = _styles; | |
// __proto__ is used because we must return a function, but there is | |
// no way to create a function with a different prototype. | |
builder.__proto__ = proto; | |
return builder; | |
} | |
var styles = (function() { | |
var ret = {}; | |
ansiStyles.grey = ansiStyles.gray; | |
Object.keys(ansiStyles).forEach(function(key) { | |
ansiStyles[key].closeRe = | |
new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g'); | |
ret[key] = { | |
get: function() { | |
return build(this._styles.concat(key)); | |
}, | |
}; | |
}); | |
return ret; | |
})(); | |
var proto = defineProps(function colors() {}, styles); | |
function applyStyle() { | |
var args = Array.prototype.slice.call(arguments); | |
var str = args.map(function(arg) { | |
// Use weak equality check so we can colorize null/undefined in safe mode | |
if (arg != null && arg.constructor === String) { | |
return arg; | |
} else { | |
return util__default['default'].inspect(arg); | |
} | |
}).join(' '); | |
if (!colors.enabled || !str) { | |
return str; | |
} | |
var newLinesPresent = str.indexOf('\n') != -1; | |
var nestedStyles = this._styles; | |
var i = nestedStyles.length; | |
while (i--) { | |
var code = ansiStyles[nestedStyles[i]]; | |
str = code.open + str.replace(code.closeRe, code.open) + code.close; | |
if (newLinesPresent) { | |
str = str.replace(newLineRegex, function(match) { | |
return code.close + match + code.open; | |
}); | |
} | |
} | |
return str; | |
} | |
colors.setTheme = function(theme) { | |
if (typeof theme === 'string') { | |
console.log('colors.setTheme now only accepts an object, not a string. ' + | |
'If you are trying to set a theme from a file, it is now your (the ' + | |
'caller\'s) responsibility to require the file. The old syntax ' + | |
'looked like colors.setTheme(__dirname + ' + | |
'\'/../themes/generic-logging.js\'); The new syntax looks like '+ | |
'colors.setTheme(require(__dirname + ' + | |
'\'/../themes/generic-logging.js\'));'); | |
return; | |
} | |
for (var style in theme) { | |
(function(style) { | |
colors[style] = function(str) { | |
if (typeof theme[style] === 'object') { | |
var out = str; | |
for (var i in theme[style]) { | |
out = colors[theme[style][i]](out); | |
} | |
return out; | |
} | |
return colors[theme[style]](str); | |
}; | |
})(style); | |
} | |
}; | |
function init() { | |
var ret = {}; | |
Object.keys(styles).forEach(function(name) { | |
ret[name] = { | |
get: function() { | |
return build([name]); | |
}, | |
}; | |
}); | |
return ret; | |
} | |
var sequencer = function sequencer(map, str) { | |
var exploded = str.split(''); | |
exploded = exploded.map(map); | |
return exploded.join(''); | |
}; | |
// custom formatter methods | |
colors.trap = trap; | |
colors.zalgo = zalgo; | |
// maps | |
colors.maps = {}; | |
colors.maps.america = america(colors); | |
colors.maps.zebra = zebra(colors); | |
colors.maps.rainbow = rainbow(colors); | |
colors.maps.random = random(colors); | |
for (var map in colors.maps) { | |
(function(map) { | |
colors[map] = function(str) { | |
return sequencer(colors.maps[map], str); | |
}; | |
})(map); | |
} | |
defineProps(colors, init()); | |
}); | |
var extendStringPrototype = createCommonjsModule(function (module) { | |
module['exports'] = function() { | |
// | |
// Extends prototype of native string object to allow for "foo".red syntax | |
// | |
var addProperty = function(color, func) { | |
String.prototype.__defineGetter__(color, func); | |
}; | |
addProperty('strip', function() { | |
return colors_1.strip(this); | |
}); | |
addProperty('stripColors', function() { | |
return colors_1.strip(this); | |
}); | |
addProperty('trap', function() { | |
return colors_1.trap(this); | |
}); | |
addProperty('zalgo', function() { | |
return colors_1.zalgo(this); | |
}); | |
addProperty('zebra', function() { | |
return colors_1.zebra(this); | |
}); | |
addProperty('rainbow', function() { | |
return colors_1.rainbow(this); | |
}); | |
addProperty('random', function() { | |
return colors_1.random(this); | |
}); | |
addProperty('america', function() { | |
return colors_1.america(this); | |
}); | |
// | |
// Iterate through all default styles and colors | |
// | |
var x = Object.keys(colors_1.styles); | |
x.forEach(function(style) { | |
addProperty(style, function() { | |
return colors_1.stylize(this, style); | |
}); | |
}); | |
function applyTheme(theme) { | |
// | |
// Remark: This is a list of methods that exist | |
// on String that you should not overwrite. | |
// | |
var stringPrototypeBlacklist = [ | |
'__defineGetter__', '__defineSetter__', '__lookupGetter__', | |
'__lookupSetter__', 'charAt', 'constructor', 'hasOwnProperty', | |
'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', | |
'valueOf', 'charCodeAt', 'indexOf', 'lastIndexOf', 'length', | |
'localeCompare', 'match', 'repeat', 'replace', 'search', 'slice', | |
'split', 'substring', 'toLocaleLowerCase', 'toLocaleUpperCase', | |
'toLowerCase', 'toUpperCase', 'trim', 'trimLeft', 'trimRight', | |
]; | |
Object.keys(theme).forEach(function(prop) { | |
if (stringPrototypeBlacklist.indexOf(prop) !== -1) { | |
console.log('warn: '.red + ('String.prototype' + prop).magenta + | |
' is probably something you don\'t want to override. ' + | |
'Ignoring style name'); | |
} else { | |
if (typeof(theme[prop]) === 'string') { | |
colors_1[prop] = colors_1[theme[prop]]; | |
addProperty(prop, function() { | |
return colors_1[prop](this); | |
}); | |
} else { | |
var themePropApplicator = function(str) { | |
var ret = str || this; | |
for (var t = 0; t < theme[prop].length; t++) { | |
ret = colors_1[theme[prop][t]](ret); | |
} | |
return ret; | |
}; | |
addProperty(prop, themePropApplicator); | |
colors_1[prop] = function(str) { | |
return themePropApplicator(str); | |
}; | |
} | |
} | |
}); | |
} | |
colors_1.setTheme = function(theme) { | |
if (typeof theme === 'string') { | |
console.log('colors.setTheme now only accepts an object, not a string. ' + | |
'If you are trying to set a theme from a file, it is now your (the ' + | |
'caller\'s) responsibility to require the file. The old syntax ' + | |
'looked like colors.setTheme(__dirname + ' + | |
'\'/../themes/generic-logging.js\'); The new syntax looks like '+ | |
'colors.setTheme(require(__dirname + ' + | |
'\'/../themes/generic-logging.js\'));'); | |
return; | |
} else { | |
applyTheme(theme); | |
} | |
}; | |
}; | |
}); | |
var lib = createCommonjsModule(function (module) { | |
module['exports'] = colors_1; | |
// Remark: By default, colors will add style properties to String.prototype. | |
// | |
// If you don't wish to extend String.prototype, you can do this instead and | |
// native String will not be touched: | |
// | |
// var colors = require('colors/safe); | |
// colors.red("foo") | |
// | |
// | |
extendStringPrototype(); | |
}); | |
var moment = createCommonjsModule(function (module, exports) { | |
(function (global, factory) { | |
module.exports = factory() ; | |
}(commonjsGlobal, (function () { | |
var hookCallback; | |
function hooks() { | |
return hookCallback.apply(null, arguments); | |
} | |
// This is done to register the method called with moment() | |
// without creating circular dependencies. | |
function setHookCallback(callback) { | |
hookCallback = callback; | |
} | |
function isArray(input) { | |
return ( | |
input instanceof Array || | |
Object.prototype.toString.call(input) === '[object Array]' | |
); | |
} | |
function isObject(input) { | |
// IE8 will treat undefined and null as object if it wasn't for | |
// input != null | |
return ( | |
input != null && | |
Object.prototype.toString.call(input) === '[object Object]' | |
); | |
} | |
function hasOwnProp(a, b) { | |
return Object.prototype.hasOwnProperty.call(a, b); | |
} | |
function isObjectEmpty(obj) { | |
if (Object.getOwnPropertyNames) { | |
return Object.getOwnPropertyNames(obj).length === 0; | |
} else { | |
var k; | |
for (k in obj) { | |
if (hasOwnProp(obj, k)) { | |
return false; | |
} | |
} | |
return true; | |
} | |
} | |
function isUndefined(input) { | |
return input === void 0; | |
} | |
function isNumber(input) { | |
return ( | |
typeof input === 'number' || | |
Object.prototype.toString.call(input) === '[object Number]' | |
); | |
} | |
function isDate(input) { | |
return ( | |
input instanceof Date || | |
Object.prototype.toString.call(input) === '[object Date]' | |
); | |
} | |
function map(arr, fn) { | |
var res = [], | |
i; | |
for (i = 0; i < arr.length; ++i) { | |
res.push(fn(arr[i], i)); | |
} | |
return res; | |
} | |
function extend(a, b) { | |
for (var i in b) { | |
if (hasOwnProp(b, i)) { | |
a[i] = b[i]; | |
} | |
} | |
if (hasOwnProp(b, 'toString')) { | |
a.toString = b.toString; | |
} | |
if (hasOwnProp(b, 'valueOf')) { | |
a.valueOf = b.valueOf; | |
} | |
return a; | |
} | |
function createUTC(input, format, locale, strict) { | |
return createLocalOrUTC(input, format, locale, strict, true).utc(); | |
} | |
function defaultParsingFlags() { | |
// We need to deep clone this object. | |
return { | |
empty: false, | |
unusedTokens: [], | |
unusedInput: [], | |
overflow: -2, | |
charsLeftOver: 0, | |
nullInput: false, | |
invalidEra: null, | |
invalidMonth: null, | |
invalidFormat: false, | |
userInvalidated: false, | |
iso: false, | |
parsedDateParts: [], | |
era: null, | |
meridiem: null, | |
rfc2822: false, | |
weekdayMismatch: false, | |
}; | |
} | |
function getParsingFlags(m) { | |
if (m._pf == null) { | |
m._pf = defaultParsingFlags(); | |
} | |
return m._pf; | |
} | |
var some; | |
if (Array.prototype.some) { | |
some = Array.prototype.some; | |
} else { | |
some = function (fun) { | |
var t = Object(this), | |
len = t.length >>> 0, | |
i; | |
for (i = 0; i < len; i++) { | |
if (i in t && fun.call(this, t[i], i, t)) { | |
return true; | |
} | |
} | |
return false; | |
}; | |
} | |
function isValid(m) { | |
if (m._isValid == null) { | |
var flags = getParsingFlags(m), | |
parsedParts = some.call(flags.parsedDateParts, function (i) { | |
return i != null; | |
}), | |
isNowValid = | |
!isNaN(m._d.getTime()) && | |
flags.overflow < 0 && | |
!flags.empty && | |
!flags.invalidEra && | |
!flags.invalidMonth && | |
!flags.invalidWeekday && | |
!flags.weekdayMismatch && | |
!flags.nullInput && | |
!flags.invalidFormat && | |
!flags.userInvalidated && | |
(!flags.meridiem || (flags.meridiem && parsedParts)); | |
if (m._strict) { | |
isNowValid = | |
isNowValid && | |
flags.charsLeftOver === 0 && | |
flags.unusedTokens.length === 0 && | |
flags.bigHour === undefined; | |
} | |
if (Object.isFrozen == null || !Object.isFrozen(m)) { | |
m._isValid = isNowValid; | |
} else { | |
return isNowValid; | |
} | |
} | |
return m._isValid; | |
} | |
function createInvalid(flags) { | |
var m = createUTC(NaN); | |
if (flags != null) { | |
extend(getParsingFlags(m), flags); | |
} else { | |
getParsingFlags(m).userInvalidated = true; | |
} | |
return m; | |
} | |
// Plugins that add properties should also add the key here (null value), | |
// so we can properly clone ourselves. | |
var momentProperties = (hooks.momentProperties = []), | |
updateInProgress = false; | |
function copyConfig(to, from) { | |
var i, prop, val; | |
if (!isUndefined(from._isAMomentObject)) { | |
to._isAMomentObject = from._isAMomentObject; | |
} | |
if (!isUndefined(from._i)) { | |
to._i = from._i; | |
} | |
if (!isUndefined(from._f)) { | |
to._f = from._f; | |
} | |
if (!isUndefined(from._l)) { | |
to._l = from._l; | |
} | |
if (!isUndefined(from._strict)) { | |
to._strict = from._strict; | |
} | |
if (!isUndefined(from._tzm)) { | |
to._tzm = from._tzm; | |
} | |
if (!isUndefined(from._isUTC)) { | |
to._isUTC = from._isUTC; | |
} | |
if (!isUndefined(from._offset)) { | |
to._offset = from._offset; | |
} | |
if (!isUndefined(from._pf)) { | |
to._pf = getParsingFlags(from); | |
} | |
if (!isUndefined(from._locale)) { | |
to._locale = from._locale; | |
} | |
if (momentProperties.length > 0) { | |
for (i = 0; i < momentProperties.length; i++) { | |
prop = momentProperties[i]; | |
val = from[prop]; | |
if (!isUndefined(val)) { | |
to[prop] = val; | |
} | |
} | |
} | |
return to; | |
} | |
// Moment prototype object | |
function Moment(config) { | |
copyConfig(this, config); | |
this._d = new Date(config._d != null ? config._d.getTime() : NaN); | |
if (!this.isValid()) { | |
this._d = new Date(NaN); | |
} | |
// Prevent infinite loop in case updateOffset creates new moment | |
// objects. | |
if (updateInProgress === false) { | |
updateInProgress = true; | |
hooks.updateOffset(this); | |
updateInProgress = false; | |
} | |
} | |
function isMoment(obj) { | |
return ( | |
obj instanceof Moment || (obj != null && obj._isAMomentObject != null) | |
); | |
} | |
function warn(msg) { | |
if ( | |
hooks.suppressDeprecationWarnings === false && | |
typeof console !== 'undefined' && | |
console.warn | |
) { | |
console.warn('Deprecation warning: ' + msg); | |
} | |
} | |
function deprecate(msg, fn) { | |
var firstTime = true; | |
return extend(function () { | |
if (hooks.deprecationHandler != null) { | |
hooks.deprecationHandler(null, msg); | |
} | |
if (firstTime) { | |
var args = [], | |
arg, | |
i, | |
key; | |
for (i = 0; i < arguments.length; i++) { | |
arg = ''; | |
if (typeof arguments[i] === 'object') { | |
arg += '\n[' + i + '] '; | |
for (key in arguments[0]) { | |
if (hasOwnProp(arguments[0], key)) { | |
arg += key + ': ' + arguments[0][key] + ', '; | |
} | |
} | |
arg = arg.slice(0, -2); // Remove trailing comma and space | |
} else { | |
arg = arguments[i]; | |
} | |
args.push(arg); | |
} | |
warn( | |
msg + | |
'\nArguments: ' + | |
Array.prototype.slice.call(args).join('') + | |
'\n' + | |
new Error().stack | |
); | |
firstTime = false; | |
} | |
return fn.apply(this, arguments); | |
}, fn); | |
} | |
var deprecations = {}; | |
function deprecateSimple(name, msg) { | |
if (hooks.deprecationHandler != null) { | |
hooks.deprecationHandler(name, msg); | |
} | |
if (!deprecations[name]) { | |
warn(msg); | |
deprecations[name] = true; | |
} | |
} | |
hooks.suppressDeprecationWarnings = false; | |
hooks.deprecationHandler = null; | |
function isFunction(input) { | |
return ( | |
(typeof Function !== 'undefined' && input instanceof Function) || | |
Object.prototype.toString.call(input) === '[object Function]' | |
); | |
} | |
function set(config) { | |
var prop, i; | |
for (i in config) { | |
if (hasOwnProp(config, i)) { | |
prop = config[i]; | |
if (isFunction(prop)) { | |
this[i] = prop; | |
} else { | |
this['_' + i] = prop; | |
} | |
} | |
} | |
this._config = config; | |
// Lenient ordinal parsing accepts just a number in addition to | |
// number + (possibly) stuff coming from _dayOfMonthOrdinalParse. | |
// TODO: Remove "ordinalParse" fallback in next major release. | |
this._dayOfMonthOrdinalParseLenient = new RegExp( | |
(this._dayOfMonthOrdinalParse.source || this._ordinalParse.source) + | |
'|' + | |
/\d{1,2}/.source | |
); | |
} | |
function mergeConfigs(parentConfig, childConfig) { | |
var res = extend({}, parentConfig), | |
prop; | |
for (prop in childConfig) { | |
if (hasOwnProp(childConfig, prop)) { | |
if (isObject(parentConfig[prop]) && isObject(childConfig[prop])) { | |
res[prop] = {}; | |
extend(res[prop], parentConfig[prop]); | |
extend(res[prop], childConfig[prop]); | |
} else if (childConfig[prop] != null) { | |
res[prop] = childConfig[prop]; | |
} else { | |
delete res[prop]; | |
} | |
} | |
} | |
for (prop in parentConfig) { | |
if ( | |
hasOwnProp(parentConfig, prop) && | |
!hasOwnProp(childConfig, prop) && | |
isObject(parentConfig[prop]) | |
) { | |
// make sure changes to properties don't modify parent config | |
res[prop] = extend({}, res[prop]); | |
} | |
} | |
return res; | |
} | |
function Locale(config) { | |
if (config != null) { | |
this.set(config); | |
} | |
} | |
var keys; | |
if (Object.keys) { | |
keys = Object.keys; | |
} else { | |
keys = function (obj) { | |
var i, | |
res = []; | |
for (i in obj) { | |
if (hasOwnProp(obj, i)) { | |
res.push(i); | |
} | |
} | |
return res; | |
}; | |
} | |
var defaultCalendar = { | |
sameDay: '[Today at] LT', | |
nextDay: '[Tomorrow at] LT', | |
nextWeek: 'dddd [at] LT', | |
lastDay: '[Yesterday at] LT', | |
lastWeek: '[Last] dddd [at] LT', | |
sameElse: 'L', | |
}; | |
function calendar(key, mom, now) { | |
var output = this._calendar[key] || this._calendar['sameElse']; | |
return isFunction(output) ? output.call(mom, now) : output; | |
} | |
function zeroFill(number, targetLength, forceSign) { | |
var absNumber = '' + Math.abs(number), | |
zerosToFill = targetLength - absNumber.length, | |
sign = number >= 0; | |
return ( | |
(sign ? (forceSign ? '+' : '') : '-') + | |
Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + | |
absNumber | |
); | |
} | |
var formattingTokens = /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|N{1,5}|YYYYYY|YYYYY|YYYY|YY|y{2,4}|yo?|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g, | |
localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, | |
formatFunctions = {}, | |
formatTokenFunctions = {}; | |
// token: 'M' | |
// padded: ['MM', 2] | |
// ordinal: 'Mo' | |
// callback: function () { this.month() + 1 } | |
function addFormatToken(token, padded, ordinal, callback) { | |
var func = callback; | |
if (typeof callback === 'string') { | |
func = function () { | |
return this[callback](); | |
}; | |
} | |
if (token) { | |
formatTokenFunctions[token] = func; | |
} | |
if (padded) { | |
formatTokenFunctions[padded[0]] = function () { | |
return zeroFill(func.apply(this, arguments), padded[1], padded[2]); | |
}; | |
} | |
if (ordinal) { | |
formatTokenFunctions[ordinal] = function () { | |
return this.localeData().ordinal( | |
func.apply(this, arguments), | |
token | |
); | |
}; | |
} | |
} | |
function removeFormattingTokens(input) { | |
if (input.match(/\[[\s\S]/)) { | |
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 = '', | |
i; | |
for (i = 0; i < length; i++) { | |
output += isFunction(array[i]) | |
? array[i].call(mom, format) | |
: array[i]; | |
} | |
return output; | |
}; | |
} | |
// format date using native date object | |
function formatMoment(m, format) { | |
if (!m.isValid()) { | |
return m.localeData().invalidDate(); | |
} | |
format = expandFormat(format, m.localeData()); | |
formatFunctions[format] = | |
formatFunctions[format] || makeFormatFunction(format); | |
return formatFunctions[format](m); | |
} | |
function expandFormat(format, locale) { | |
var i = 5; | |
function replaceLongDateFormatTokens(input) { | |
return locale.longDateFormat(input) || input; | |
} | |
localFormattingTokens.lastIndex = 0; | |
while (i >= 0 && localFormattingTokens.test(format)) { | |
format = format.replace( | |
localFormattingTokens, | |
replaceLongDateFormatTokens | |
); | |
localFormattingTokens.lastIndex = 0; | |
i -= 1; | |
} | |
return format; | |
} | |
var defaultLongDateFormat = { | |
LTS: 'h:mm:ss A', | |
LT: 'h:mm A', | |
L: 'MM/DD/YYYY', | |
LL: 'MMMM D, YYYY', | |
LLL: 'MMMM D, YYYY h:mm A', | |
LLLL: 'dddd, MMMM D, YYYY h:mm A', | |
}; | |
function longDateFormat(key) { | |
var format = this._longDateFormat[key], | |
formatUpper = this._longDateFormat[key.toUpperCase()]; | |
if (format || !formatUpper) { | |
return format; | |
} | |
this._longDateFormat[key] = formatUpper | |
.match(formattingTokens) | |
.map(function (tok) { | |
if ( | |
tok === 'MMMM' || | |
tok === 'MM' || | |
tok === 'DD' || | |
tok === 'dddd' | |
) { | |
return tok.slice(1); | |
} | |
return tok; | |
}) | |
.join(''); | |
return this._longDateFormat[key]; | |
} | |
var defaultInvalidDate = 'Invalid date'; | |
function invalidDate() { | |
return this._invalidDate; | |
} | |
var defaultOrdinal = '%d', | |
defaultDayOfMonthOrdinalParse = /\d{1,2}/; | |
function ordinal(number) { | |
return this._ordinal.replace('%d', number); | |
} | |
var defaultRelativeTime = { | |
future: 'in %s', | |
past: '%s ago', | |
s: 'a few seconds', | |
ss: '%d seconds', | |
m: 'a minute', | |
mm: '%d minutes', | |
h: 'an hour', | |
hh: '%d hours', | |
d: 'a day', | |
dd: '%d days', | |
w: 'a week', | |
ww: '%d weeks', | |
M: 'a month', | |
MM: '%d months', | |
y: 'a year', | |
yy: '%d years', | |
}; | |
function relativeTime(number, withoutSuffix, string, isFuture) { | |
var output = this._relativeTime[string]; | |
return isFunction(output) | |
? output(number, withoutSuffix, string, isFuture) | |
: output.replace(/%d/i, number); | |
} | |
function pastFuture(diff, output) { | |
var format = this._relativeTime[diff > 0 ? 'future' : 'past']; | |
return isFunction(format) ? format(output) : format.replace(/%s/i, output); | |
} | |
var aliases = {}; | |
function addUnitAlias(unit, shorthand) { | |
var lowerCase = unit.toLowerCase(); | |
aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit; | |
} | |
function normalizeUnits(units) { | |
return typeof units === 'string' | |
? aliases[units] || aliases[units.toLowerCase()] | |
: undefined; | |
} | |
function normalizeObjectUnits(inputObject) { | |
var normalizedInput = {}, | |
normalizedProp, | |
prop; | |
for (prop in inputObject) { | |
if (hasOwnProp(inputObject, prop)) { | |
normalizedProp = normalizeUnits(prop); | |
if (normalizedProp) { | |
normalizedInput[normalizedProp] = inputObject[prop]; | |
} | |
} | |
} | |
return normalizedInput; | |
} | |
var priorities = {}; | |
function addUnitPriority(unit, priority) { | |
priorities[unit] = priority; | |
} | |
function getPrioritizedUnits(unitsObj) { | |
var units = [], | |
u; | |
for (u in unitsObj) { | |
if (hasOwnProp(unitsObj, u)) { | |
units.push({ unit: u, priority: priorities[u] }); | |
} | |
} | |
units.sort(function (a, b) { | |
return a.priority - b.priority; | |
}); | |
return units; | |
} | |
function isLeapYear(year) { | |
return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; | |
} | |
function absFloor(number) { | |
if (number < 0) { | |
// -0 -> 0 | |
return Math.ceil(number) || 0; | |
} else { | |
return Math.floor(number); | |
} | |
} | |
function toInt(argumentForCoercion) { | |
var coercedNumber = +argumentForCoercion, | |
value = 0; | |
if (coercedNumber !== 0 && isFinite(coercedNumber)) { | |
value = absFloor(coercedNumber); | |
} | |
return value; | |
} | |
function makeGetSet(unit, keepTime) { | |
return function (value) { | |
if (value != null) { | |
set$1(this, unit, value); | |
hooks.updateOffset(this, keepTime); | |
return this; | |
} else { | |
return get(this, unit); | |
} | |
}; | |
} | |
function get(mom, unit) { | |
return mom.isValid() | |
? mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]() | |
: NaN; | |
} | |
function set$1(mom, unit, value) { | |
if (mom.isValid() && !isNaN(value)) { | |
if ( | |
unit === 'FullYear' && | |
isLeapYear(mom.year()) && | |
mom.month() === 1 && | |
mom.date() === 29 | |
) { | |
value = toInt(value); | |
mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit]( | |
value, | |
mom.month(), | |
daysInMonth(value, mom.month()) | |
); | |
} else { | |
mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value); | |
} | |
} | |
} | |
// MOMENTS | |
function stringGet(units) { | |
units = normalizeUnits(units); | |
if (isFunction(this[units])) { | |
return this[units](); | |
} | |
return this; | |
} | |
function stringSet(units, value) { | |
if (typeof units === 'object') { | |
units = normalizeObjectUnits(units); | |
var prioritized = getPrioritizedUnits(units), | |
i; | |
for (i = 0; i < prioritized.length; i++) { | |
this[prioritized[i].unit](units[prioritized[i].unit]); | |
} | |
} else { | |
units = normalizeUnits(units); | |
if (isFunction(this[units])) { | |
return this[units](value); | |
} | |
} | |
return this; | |
} | |
var match1 = /\d/, // 0 - 9 | |
match2 = /\d\d/, // 00 - 99 | |
match3 = /\d{3}/, // 000 - 999 | |
match4 = /\d{4}/, // 0000 - 9999 | |
match6 = /[+-]?\d{6}/, // -999999 - 999999 | |
match1to2 = /\d\d?/, // 0 - 99 | |
match3to4 = /\d\d\d\d?/, // 999 - 9999 | |
match5to6 = /\d\d\d\d\d\d?/, // 99999 - 999999 | |
match1to3 = /\d{1,3}/, // 0 - 999 | |
match1to4 = /\d{1,4}/, // 0 - 9999 | |
match1to6 = /[+-]?\d{1,6}/, // -999999 - 999999 | |
matchUnsigned = /\d+/, // 0 - inf | |
matchSigned = /[+-]?\d+/, // -inf - inf | |
matchOffset = /Z|[+-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z | |
matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi, // +00 -00 +00:00 -00:00 +0000 -0000 or Z | |
matchTimestamp = /[+-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123 | |
// any word (or two) characters or numbers including two/three word month in arabic. | |
// includes scottish gaelic two word and hyphenated months | |
matchWord = /[0-9]{0,256}['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFF07\uFF10-\uFFEF]{1,256}|[\u0600-\u06FF\/]{1,256}(\s*?[\u0600-\u06FF]{1,256}){1,2}/i, | |
regexes; | |
regexes = {}; | |
function addRegexToken(token, regex, strictRegex) { | |
regexes[token] = isFunction(regex) | |
? regex | |
: function (isStrict, localeData) { | |
return isStrict && strictRegex ? strictRegex : regex; | |
}; | |
} | |
function getParseRegexForToken(token, config) { | |
if (!hasOwnProp(regexes, token)) { | |
return new RegExp(unescapeFormat(token)); | |
} | |
return regexes[token](config._strict, config._locale); | |
} | |
// Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript | |
function unescapeFormat(s) { | |
return regexEscape( | |
s | |
.replace('\\', '') | |
.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function ( | |
matched, | |
p1, | |
p2, | |
p3, | |
p4 | |
) { | |
return p1 || p2 || p3 || p4; | |
}) | |
); | |
} | |
function regexEscape(s) { | |
return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); | |
} | |
var tokens = {}; | |
function addParseToken(token, callback) { | |
var i, | |
func = callback; | |
if (typeof token === 'string') { | |
token = [token]; | |
} | |
if (isNumber(callback)) { | |
func = function (input, array) { | |
array[callback] = toInt(input); | |
}; | |
} | |
for (i = 0; i < token.length; i++) { | |
tokens[token[i]] = func; | |
} | |
} | |
function addWeekParseToken(token, callback) { | |
addParseToken(token, function (input, array, config, token) { | |
config._w = config._w || {}; | |
callback(input, config._w, config, token); | |
}); | |
} | |
function addTimeToArrayFromToken(token, input, config) { | |
if (input != null && hasOwnProp(tokens, token)) { | |
tokens[token](input, config._a, config, token); | |
} | |
} | |
var YEAR = 0, | |
MONTH = 1, | |
DATE = 2, | |
HOUR = 3, | |
MINUTE = 4, | |
SECOND = 5, | |
MILLISECOND = 6, | |
WEEK = 7, | |
WEEKDAY = 8; | |
function mod(n, x) { | |
return ((n % x) + x) % x; | |
} | |
var indexOf; | |
if (Array.prototype.indexOf) { | |
indexOf = Array.prototype.indexOf; | |
} else { | |
indexOf = function (o) { | |
// I know | |
var i; | |
for (i = 0; i < this.length; ++i) { | |
if (this[i] === o) { | |
return i; | |
} | |
} | |
return -1; | |
}; | |
} | |
function daysInMonth(year, month) { | |
if (isNaN(year) || isNaN(month)) { | |
return NaN; | |
} | |
var modMonth = mod(month, 12); | |
year += (month - modMonth) / 12; | |
return modMonth === 1 | |
? isLeapYear(year) | |
? 29 | |
: 28 | |
: 31 - ((modMonth % 7) % 2); | |
} | |
// FORMATTING | |
addFormatToken('M', ['MM', 2], 'Mo', function () { | |
return this.month() + 1; | |
}); | |
addFormatToken('MMM', 0, 0, function (format) { | |
return this.localeData().monthsShort(this, format); | |
}); | |
addFormatToken('MMMM', 0, 0, function (format) { | |
return this.localeData().months(this, format); | |
}); | |
// ALIASES | |
addUnitAlias('month', 'M'); | |
// PRIORITY | |
addUnitPriority('month', 8); | |
// PARSING | |
addRegexToken('M', match1to2); | |
addRegexToken('MM', match1to2, match2); | |
addRegexToken('MMM', function (isStrict, locale) { | |
return locale.monthsShortRegex(isStrict); | |
}); | |
addRegexToken('MMMM', function (isStrict, locale) { | |
return locale.monthsRegex(isStrict); | |
}); | |
addParseToken(['M', 'MM'], function (input, array) { | |
array[MONTH] = toInt(input) - 1; | |
}); | |
addParseToken(['MMM', 'MMMM'], function (input, array, config, token) { | |
var month = config._locale.monthsParse(input, token, config._strict); | |
// if we didn't find a month name, mark the date as invalid. | |
if (month != null) { | |
array[MONTH] = month; | |
} else { | |
getParsingFlags(config).invalidMonth = input; | |
} | |
}); | |
// LOCALES | |
var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split( | |
'_' | |
), | |
defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split( | |
'_' | |
), | |
MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/, | |
defaultMonthsShortRegex = matchWord, | |
defaultMonthsRegex = matchWord; | |
function localeMonths(m, format) { | |
if (!m) { | |
return isArray(this._months) | |
? this._months | |
: this._months['standalone']; | |
} | |
return isArray(this._months) | |
? this._months[m.month()] | |
: this._months[ | |
(this._months.isFormat || MONTHS_IN_FORMAT).test(format) | |
? 'format' | |
: 'standalone' | |
][m.month()]; | |
} | |
function localeMonthsShort(m, format) { | |
if (!m) { | |
return isArray(this._monthsShort) | |
? this._monthsShort | |
: this._monthsShort['standalone']; | |
} | |
return isArray(this._monthsShort) | |
? this._monthsShort[m.month()] | |
: this._monthsShort[ | |
MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone' | |
][m.month()]; | |
} | |
function handleStrictParse(monthName, format, strict) { | |
var i, | |
ii, | |
mom, | |
llc = monthName.toLocaleLowerCase(); | |
if (!this._monthsParse) { | |
// this is not used | |
this._monthsParse = []; | |
this._longMonthsParse = []; | |
this._shortMonthsParse = []; | |
for (i = 0; i < 12; ++i) { | |
mom = createUTC([2000, i]); | |
this._shortMonthsParse[i] = this.monthsShort( | |
mom, | |
'' | |
).toLocaleLowerCase(); | |
this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase(); | |
} | |
} | |
if (strict) { | |
if (format === 'MMM') { | |
ii = indexOf.call(this._shortMonthsParse, llc); | |
return ii !== -1 ? ii : null; | |
} else { | |
ii = indexOf.call(this._longMonthsParse, llc); | |
return ii !== -1 ? ii : null; | |
} | |
} else { | |
if (format === 'MMM') { | |
ii = indexOf.call(this._shortMonthsParse, llc); | |
if (ii !== -1) { | |
return ii; | |
} | |
ii = indexOf.call(this._longMonthsParse, llc); | |
return ii !== -1 ? ii : null; | |
} else { | |
ii = indexOf.call(this._longMonthsParse, llc); | |
if (ii !== -1) { | |
return ii; | |
} | |
ii = indexOf.call(this._shortMonthsParse, llc); | |
return ii !== -1 ? ii : null; | |
} | |
} | |
} | |
function localeMonthsParse(monthName, format, strict) { | |
var i, mom, regex; | |
if (this._monthsParseExact) { | |
return handleStrictParse.call(this, monthName, format, strict); | |
} | |
if (!this._monthsParse) { | |
this._monthsParse = []; | |
this._longMonthsParse = []; | |
this._shortMonthsParse = []; | |
} | |
// TODO: add sorting | |
// Sorting makes sure if one month (or abbr) is a prefix of another | |
// see sorting in computeMonthsParse | |
for (i = 0; i < 12; i++) { | |
// make the regex if we don't have it already | |
mom = createUTC([2000, i]); | |
if (strict && !this._longMonthsParse[i]) { | |
this._longMonthsParse[i] = new RegExp( | |
'^' + this.months(mom, '').replace('.', '') + '$', | |
'i' | |
); | |
this._shortMonthsParse[i] = new RegExp( | |
'^' + this.monthsShort(mom, '').replace('.', '') + '$', | |
'i' | |
); | |
} | |
if (!strict && !this._monthsParse[i]) { | |
regex = | |
'^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); | |
this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); | |
} | |
// test the regex | |
if ( | |
strict && | |
format === 'MMMM' && | |
this._longMonthsParse[i].test(monthName) | |
) { | |
return i; | |
} else if ( | |
strict && | |
format === 'MMM' && | |
this._shortMonthsParse[i].test(monthName) | |
) { | |
return i; | |
} else if (!strict && this._monthsParse[i].test(monthName)) { | |
return i; | |
} | |
} | |
} | |
// MOMENTS | |
function setMonth(mom, value) { | |
var dayOfMonth; | |
if (!mom.isValid()) { | |
// No op | |
return mom; | |
} | |
if (typeof value === 'string') { | |
if (/^\d+$/.test(value)) { | |
value = toInt(value); | |
} else { | |
value = mom.localeData().monthsParse(value); | |
// TODO: Another silent failure? | |
if (!isNumber(value)) { | |
return mom; | |
} | |
} | |
} | |
dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value)); | |
mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth); | |
return mom; | |
} | |
function getSetMonth(value) { | |
if (value != null) { | |
setMonth(this, value); | |
hooks.updateOffset(this, true); | |
return this; | |
} else { | |
return get(this, 'Month'); | |
} | |
} | |
function getDaysInMonth() { | |
return daysInMonth(this.year(), this.month()); | |
} | |
function monthsShortRegex(isStrict) { | |
if (this._monthsParseExact) { | |
if (!hasOwnProp(this, '_monthsRegex')) { | |
computeMonthsParse.call(this); | |
} | |
if (isStrict) { | |
return this._monthsShortStrictRegex; | |
} else { | |
return this._monthsShortRegex; | |
} | |
} else { | |
if (!hasOwnProp(this, '_monthsShortRegex')) { | |
this._monthsShortRegex = defaultMonthsShortRegex; | |
} | |
return this._monthsShortStrictRegex && isStrict | |
? this._monthsShortStrictRegex | |
: this._monthsShortRegex; | |
} | |
} | |
function monthsRegex(isStrict) { | |
if (this._monthsParseExact) { | |
if (!hasOwnProp(this, '_monthsRegex')) { | |
computeMonthsParse.call(this); | |
} | |
if (isStrict) { | |
return this._monthsStrictRegex; | |
} else { | |
return this._monthsRegex; | |
} | |
} else { | |
if (!hasOwnProp(this, '_monthsRegex')) { | |
this._monthsRegex = defaultMonthsRegex; | |
} | |
return this._monthsStrictRegex && isStrict | |
? this._monthsStrictRegex | |
: this._monthsRegex; | |
} | |
} | |
function computeMonthsParse() { | |
function cmpLenRev(a, b) { | |
return b.length - a.length; | |
} | |
var shortPieces = [], | |
longPieces = [], | |
mixedPieces = [], | |
i, | |
mom; | |
for (i = 0; i < 12; i++) { | |
// make the regex if we don't have it already | |
mom = createUTC([2000, i]); | |
shortPieces.push(this.monthsShort(mom, '')); | |
longPieces.push(this.months(mom, '')); | |
mixedPieces.push(this.months(mom, '')); | |
mixedPieces.push(this.monthsShort(mom, '')); | |
} | |
// Sorting makes sure if one month (or abbr) is a prefix of another it | |
// will match the longer piece. | |
shortPieces.sort(cmpLenRev); | |
longPieces.sort(cmpLenRev); | |
mixedPieces.sort(cmpLenRev); | |
for (i = 0; i < 12; i++) { | |
shortPieces[i] = regexEscape(shortPieces[i]); | |
longPieces[i] = regexEscape(longPieces[i]); | |
} | |
for (i = 0; i < 24; i++) { | |
mixedPieces[i] = regexEscape(mixedPieces[i]); | |
} | |
this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i'); | |
this._monthsShortRegex = this._monthsRegex; | |
this._monthsStrictRegex = new RegExp( | |
'^(' + longPieces.join('|') + ')', | |
'i' | |
); | |
this._monthsShortStrictRegex = new RegExp( | |
'^(' + shortPieces.join('|') + ')', | |
'i' | |
); | |
} | |
// FORMATTING | |
addFormatToken('Y', 0, 0, function () { | |
var y = this.year(); | |
return y <= 9999 ? zeroFill(y, 4) : '+' + y; | |
}); | |
addFormatToken(0, ['YY', 2], 0, function () { | |
return this.year() % 100; | |
}); | |
addFormatToken(0, ['YYYY', 4], 0, 'year'); | |
addFormatToken(0, ['YYYYY', 5], 0, 'year'); | |
addFormatToken(0, ['YYYYYY', 6, true], 0, 'year'); | |
// ALIASES | |
addUnitAlias('year', 'y'); | |
// PRIORITIES | |
addUnitPriority('year', 1); | |
// PARSING | |
addRegexToken('Y', matchSigned); | |
addRegexToken('YY', match1to2, match2); | |
addRegexToken('YYYY', match1to4, match4); | |
addRegexToken('YYYYY', match1to6, match6); | |
addRegexToken('YYYYYY', match1to6, match6); | |
addParseToken(['YYYYY', 'YYYYYY'], YEAR); | |
addParseToken('YYYY', function (input, array) { | |
array[YEAR] = | |
input.length === 2 ? hooks.parseTwoDigitYear(input) : toInt(input); | |
}); | |
addParseToken('YY', function (input, array) { | |
array[YEAR] = hooks.parseTwoDigitYear(input); | |
}); | |
addParseToken('Y', function (input, array) { | |
array[YEAR] = parseInt(input, 10); | |
}); | |
// HELPERS | |
function daysInYear(year) { | |
return isLeapYear(year) ? 366 : 365; | |
} | |
// HOOKS | |
hooks.parseTwoDigitYear = function (input) { | |
return toInt(input) + (toInt(input) > 68 ? 1900 : 2000); | |
}; | |
// MOMENTS | |
var getSetYear = makeGetSet('FullYear', true); | |
function getIsLeapYear() { | |
return isLeapYear(this.year()); | |
} | |
function createDate(y, m, d, h, M, s, ms) { | |
// can't just apply() to create a date: | |
// https://stackoverflow.com/q/181348 | |
var date; | |
// the date constructor remaps years 0-99 to 1900-1999 | |
if (y < 100 && y >= 0) { | |
// preserve leap years using a full 400 year cycle, then reset | |
date = new Date(y + 400, m, d, h, M, s, ms); | |
if (isFinite(date.getFullYear())) { | |
date.setFullYear(y); | |
} | |
} else { | |
date = new Date(y, m, d, h, M, s, ms); | |
} | |
return date; | |
} | |
function createUTCDate(y) { | |
var date, args; | |
// the Date.UTC function remaps years 0-99 to 1900-1999 | |
if (y < 100 && y >= 0) { | |
args = Array.prototype.slice.call(arguments); | |
// preserve leap years using a full 400 year cycle, then reset | |
args[0] = y + 400; | |
date = new Date(Date.UTC.apply(null, args)); | |
if (isFinite(date.getUTCFullYear())) { | |
date.setUTCFullYear(y); | |
} | |
} else { | |
date = new Date(Date.UTC.apply(null, arguments)); | |
} | |
return date; | |
} | |
// start-of-first-week - start-of-year | |
function firstWeekOffset(year, dow, doy) { | |
var // first-week day -- which january is always in the first week (4 for iso, 1 for other) | |
fwd = 7 + dow - doy, | |
// first-week day local weekday -- which local weekday is fwd | |
fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7; | |
return -fwdlw + fwd - 1; | |
} | |
// https://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday | |
function dayOfYearFromWeeks(year, week, weekday, dow, doy) { | |
var localWeekday = (7 + weekday - dow) % 7, | |
weekOffset = firstWeekOffset(year, dow, doy), | |
dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset, | |
resYear, | |
resDayOfYear; | |
if (dayOfYear <= 0) { | |
resYear = year - 1; | |
resDayOfYear = daysInYear(resYear) + dayOfYear; | |
} else if (dayOfYear > daysInYear(year)) { | |
resYear = year + 1; | |
resDayOfYear = dayOfYear - daysInYear(year); | |
} else { | |
resYear = year; | |
resDayOfYear = dayOfYear; | |
} | |
return { | |
year: resYear, | |
dayOfYear: resDayOfYear, | |
}; | |
} | |
function weekOfYear(mom, dow, doy) { | |
var weekOffset = firstWeekOffset(mom.year(), dow, doy), | |
week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1, | |
resWeek, | |
resYear; | |
if (week < 1) { | |
resYear = mom.year() - 1; | |
resWeek = week + weeksInYear(resYear, dow, doy); | |
} else if (week > weeksInYear(mom.year(), dow, doy)) { | |
resWeek = week - weeksInYear(mom.year(), dow, doy); | |
resYear = mom.year() + 1; | |
} else { | |
resYear = mom.year(); | |
resWeek = week; | |
} | |
return { | |
week: resWeek, | |
year: resYear, | |
}; | |
} | |
function weeksInYear(year, dow, doy) { | |
var weekOffset = firstWeekOffset(year, dow, doy), | |
weekOffsetNext = firstWeekOffset(year + 1, dow, doy); | |
return (daysInYear(year) - weekOffset + weekOffsetNext) / 7; | |
} | |
// FORMATTING | |
addFormatToken('w', ['ww', 2], 'wo', 'week'); | |
addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek'); | |
// ALIASES | |
addUnitAlias('week', 'w'); | |
addUnitAlias('isoWeek', 'W'); | |
// PRIORITIES | |
addUnitPriority('week', 5); | |
addUnitPriority('isoWeek', 5); | |
// PARSING | |
addRegexToken('w', match1to2); | |
addRegexToken('ww', match1to2, match2); | |
addRegexToken('W', match1to2); | |
addRegexToken('WW', match1to2, match2); | |
addWeekParseToken(['w', 'ww', 'W', 'WW'], function ( | |
input, | |
week, | |
config, | |
token | |
) { | |
week[token.substr(0, 1)] = toInt(input); | |
}); | |
// HELPERS | |
// LOCALES | |
function localeWeek(mom) { | |
return weekOfYear(mom, this._week.dow, this._week.doy).week; | |
} | |
var defaultLocaleWeek = { | |
dow: 0, // Sunday is the first day of the week. | |
doy: 6, // The week that contains Jan 6th is the first week of the year. | |
}; | |
function localeFirstDayOfWeek() { | |
return this._week.dow; | |
} | |
function localeFirstDayOfYear() { | |
return this._week.doy; | |
} | |
// MOMENTS | |
function getSetWeek(input) { | |
var week = this.localeData().week(this); | |
return input == null ? week : this.add((input - week) * 7, 'd'); | |
} | |
function getSetISOWeek(input) { | |
var week = weekOfYear(this, 1, 4).week; | |
return input == null ? week : this.add((input - week) * 7, 'd'); | |
} | |
// FORMATTING | |
addFormatToken('d', 0, 'do', 'day'); | |
addFormatToken('dd', 0, 0, function (format) { | |
return this.localeData().weekdaysMin(this, format); | |
}); | |
addFormatToken('ddd', 0, 0, function (format) { | |
return this.localeData().weekdaysShort(this, format); | |
}); | |
addFormatToken('dddd', 0, 0, function (format) { | |
return this.localeData().weekdays(this, format); | |
}); | |
addFormatToken('e', 0, 0, 'weekday'); | |
addFormatToken('E', 0, 0, 'isoWeekday'); | |
// ALIASES | |
addUnitAlias('day', 'd'); | |
addUnitAlias('weekday', 'e'); | |
addUnitAlias('isoWeekday', 'E'); | |
// PRIORITY | |
addUnitPriority('day', 11); | |
addUnitPriority('weekday', 11); | |
addUnitPriority('isoWeekday', 11); | |
// PARSING | |
addRegexToken('d', match1to2); | |
addRegexToken('e', match1to2); | |
addRegexToken('E', match1to2); | |
addRegexToken('dd', function (isStrict, locale) { | |
return locale.weekdaysMinRegex(isStrict); | |
}); | |
addRegexToken('ddd', function (isStrict, locale) { | |
return locale.weekdaysShortRegex(isStrict); | |
}); | |
addRegexToken('dddd', function (isStrict, locale) { | |
return locale.weekdaysRegex(isStrict); | |
}); | |
addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) { | |
var weekday = config._locale.weekdaysParse(input, token, config._strict); | |
// if we didn't get a weekday name, mark the date as invalid | |
if (weekday != null) { | |
week.d = weekday; | |
} else { | |
getParsingFlags(config).invalidWeekday = input; | |
} | |
}); | |
addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) { | |
week[token] = toInt(input); | |
}); | |
// HELPERS | |
function parseWeekday(input, locale) { | |
if (typeof input !== 'string') { | |
return input; | |
} | |
if (!isNaN(input)) { | |
return parseInt(input, 10); | |
} | |
input = locale.weekdaysParse(input); | |
if (typeof input === 'number') { | |
return input; | |
} | |
return null; | |
} | |
function parseIsoWeekday(input, locale) { | |
if (typeof input === 'string') { | |
return locale.weekdaysParse(input) % 7 || 7; | |
} | |
return isNaN(input) ? null : input; | |
} | |
// LOCALES | |
function shiftWeekdays(ws, n) { | |
return ws.slice(n, 7).concat(ws.slice(0, n)); | |
} | |
var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split( | |
'_' | |
), | |
defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), | |
defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), | |
defaultWeekdaysRegex = matchWord, | |
defaultWeekdaysShortRegex = matchWord, | |
defaultWeekdaysMinRegex = matchWord; | |
function localeWeekdays(m, format) { | |
var weekdays = isArray(this._weekdays) | |
? this._weekdays | |
: this._weekdays[ | |
m && m !== true && this._weekdays.isFormat.test(format) | |
? 'format' | |
: 'standalone' | |
]; | |
return m === true | |
? shiftWeekdays(weekdays, this._week.dow) | |
: m | |
? weekdays[m.day()] | |
: weekdays; | |
} | |
function localeWeekdaysShort(m) { | |
return m === true | |
? shiftWeekdays(this._weekdaysShort, this._week.dow) | |
: m | |
? this._weekdaysShort[m.day()] | |
: this._weekdaysShort; | |
} | |
function localeWeekdaysMin(m) { | |
return m === true | |
? shiftWeekdays(this._weekdaysMin, this._week.dow) | |
: m | |
? this._weekdaysMin[m.day()] | |
: this._weekdaysMin; | |
} | |
function handleStrictParse$1(weekdayName, format, strict) { | |
var i, | |
ii, | |
mom, | |
llc = weekdayName.toLocaleLowerCase(); | |
if (!this._weekdaysParse) { | |
this._weekdaysParse = []; | |
this._shortWeekdaysParse = []; | |
this._minWeekdaysParse = []; | |
for (i = 0; i < 7; ++i) { | |
mom = createUTC([2000, 1]).day(i); | |
this._minWeekdaysParse[i] = this.weekdaysMin( | |
mom, | |
'' | |
).toLocaleLowerCase(); | |
this._shortWeekdaysParse[i] = this.weekdaysShort( | |
mom, | |
'' | |
).toLocaleLowerCase(); | |
this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase(); | |
} | |
} | |
if (strict) { | |
if (format === 'dddd') { | |
ii = indexOf.call(this._weekdaysParse, llc); | |
return ii !== -1 ? ii : null; | |
} else if (format === 'ddd') { | |
ii = indexOf.call(this._shortWeekdaysParse, llc); | |
return ii !== -1 ? ii : null; | |
} else { | |
ii = indexOf.call(this._minWeekdaysParse, llc); | |
return ii !== -1 ? ii : null; | |
} | |
} else { | |
if (format === 'dddd') { | |
ii = indexOf.call(this._weekdaysParse, llc); | |
if (ii !== -1) { | |
return ii; | |
} | |
ii = indexOf.call(this._shortWeekdaysParse, llc); | |
if (ii !== -1) { | |
return ii; | |
} | |
ii = indexOf.call(this._minWeekdaysParse, llc); | |
return ii !== -1 ? ii : null; | |
} else if (format === 'ddd') { | |
ii = indexOf.call(this._shortWeekdaysParse, llc); | |
if (ii !== -1) { | |
return ii; | |
} | |
ii = indexOf.call(this._weekdaysParse, llc); | |
if (ii !== -1) { | |
return ii; | |
} | |
ii = indexOf.call(this._minWeekdaysParse, llc); | |
return ii !== -1 ? ii : null; | |
} else { | |
ii = indexOf.call(this._minWeekdaysParse, llc); | |
if (ii !== -1) { | |
return ii; | |
} | |
ii = indexOf.call(this._weekdaysParse, llc); | |
if (ii !== -1) { | |
return ii; | |
} | |
ii = indexOf.call(this._shortWeekdaysParse, llc); | |
return ii !== -1 ? ii : null; | |
} | |
} | |
} | |
function localeWeekdaysParse(weekdayName, format, strict) { | |
var i, mom, regex; | |
if (this._weekdaysParseExact) { | |
return handleStrictParse$1.call(this, weekdayName, format, strict); | |
} | |
if (!this._weekdaysParse) { | |
this._weekdaysParse = []; | |
this._minWeekdaysParse = []; | |
this._shortWeekdaysParse = []; | |
this._fullWeekdaysParse = []; | |
} | |
for (i = 0; i < 7; i++) { | |
// make the regex if we don't have it already | |
mom = createUTC([2000, 1]).day(i); | |
if (strict && !this._fullWeekdaysParse[i]) { | |
this._fullWeekdaysParse[i] = new RegExp( | |
'^' + this.weekdays(mom, '').replace('.', '\\.?') + '$', | |
'i' | |
); | |
this._shortWeekdaysParse[i] = new RegExp( | |
'^' + this.weekdaysShort(mom, '').replace('.', '\\.?') + '$', | |
'i' | |
); | |
this._minWeekdaysParse[i] = new RegExp( | |
'^' + this.weekdaysMin(mom, '').replace('.', '\\.?') + '$', | |
'i' | |
); | |
} | |
if (!this._weekdaysParse[i]) { | |
regex = | |
'^' + | |
this.weekdays(mom, '') + | |
'|^' + | |
this.weekdaysShort(mom, '') + | |
'|^' + | |
this.weekdaysMin(mom, ''); | |
this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i'); | |
} | |
// test the regex | |
if ( | |
strict && | |
format === 'dddd' && | |
this._fullWeekdaysParse[i].test(weekdayName) | |
) { | |
return i; | |
} else if ( | |
strict && | |
format === 'ddd' && | |
this._shortWeekdaysParse[i].test(weekdayName) | |
) { | |
return i; | |
} else if ( | |
strict && | |
format === 'dd' && | |
this._minWeekdaysParse[i].test(weekdayName) | |
) { | |
return i; | |
} else if (!strict && this._weekdaysParse[i].test(weekdayName)) { | |
return i; | |
} | |
} | |
} | |
// MOMENTS | |
function getSetDayOfWeek(input) { | |
if (!this.isValid()) { | |
return input != null ? this : NaN; | |
} | |
var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); | |
if (input != null) { | |
input = parseWeekday(input, this.localeData()); | |
return this.add(input - day, 'd'); | |
} else { | |
return day; | |
} | |
} | |
function getSetLocaleDayOfWeek(input) { | |
if (!this.isValid()) { | |
return input != null ? this : NaN; | |
} | |
var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7; | |
return input == null ? weekday : this.add(input - weekday, 'd'); | |
} | |
function getSetISODayOfWeek(input) { | |
if (!this.isValid()) { | |
return input != null ? this : NaN; | |
} | |
// 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. | |
if (input != null) { | |
var weekday = parseIsoWeekday(input, this.localeData()); | |
return this.day(this.day() % 7 ? weekday : weekday - 7); | |
} else { | |
return this.day() || 7; | |
} | |
} | |
function weekdaysRegex(isStrict) { | |
if (this._weekdaysParseExact) { | |
if (!hasOwnProp(this, '_weekdaysRegex')) { | |
computeWeekdaysParse.call(this); | |
} | |
if (isStrict) { | |
return this._weekdaysStrictRegex; | |
} else { | |
return this._weekdaysRegex; | |
} | |
} else { | |
if (!hasOwnProp(this, '_weekdaysRegex')) { | |
this._weekdaysRegex = defaultWeekdaysRegex; | |
} | |
return this._weekdaysStrictRegex && isStrict | |
? this._weekdaysStrictRegex | |
: this._weekdaysRegex; | |
} | |
} | |
function weekdaysShortRegex(isStrict) { | |
if (this._weekdaysParseExact) { | |
if (!hasOwnProp(this, '_weekdaysRegex')) { | |
computeWeekdaysParse.call(this); | |
} | |
if (isStrict) { | |
return this._weekdaysShortStrictRegex; | |
} else { | |
return this._weekdaysShortRegex; | |
} | |
} else { | |
if (!hasOwnProp(this, '_weekdaysShortRegex')) { | |
this._weekdaysShortRegex = defaultWeekdaysShortRegex; | |
} | |
return this._weekdaysShortStrictRegex && isStrict | |
? this._weekdaysShortStrictRegex | |
: this._weekdaysShortRegex; | |
} | |
} | |
function weekdaysMinRegex(isStrict) { | |
if (this._weekdaysParseExact) { | |
if (!hasOwnProp(this, '_weekdaysRegex')) { | |
computeWeekdaysParse.call(this); | |
} | |
if (isStrict) { | |
return this._weekdaysMinStrictRegex; | |
} else { | |
return this._weekdaysMinRegex; | |
} | |
} else { | |
if (!hasOwnProp(this, '_weekdaysMinRegex')) { | |
this._weekdaysMinRegex = defaultWeekdaysMinRegex; | |
} | |
return this._weekdaysMinStrictRegex && isStrict | |
? this._weekdaysMinStrictRegex | |
: this._weekdaysMinRegex; | |
} | |
} | |
function computeWeekdaysParse() { | |
function cmpLenRev(a, b) { | |
return b.length - a.length; | |
} | |
var minPieces = [], | |
shortPieces = [], | |
longPieces = [], | |
mixedPieces = [], | |
i, | |
mom, | |
minp, | |
shortp, | |
longp; | |
for (i = 0; i < 7; i++) { | |
// make the regex if we don't have it already | |
mom = createUTC([2000, 1]).day(i); | |
minp = regexEscape(this.weekdaysMin(mom, '')); | |
shortp = regexEscape(this.weekdaysShort(mom, '')); | |
longp = regexEscape(this.weekdays(mom, '')); | |
minPieces.push(minp); | |
shortPieces.push(shortp); | |
longPieces.push(longp); | |
mixedPieces.push(minp); | |
mixedPieces.push(shortp); | |
mixedPieces.push(longp); | |
} | |
// Sorting makes sure if one weekday (or abbr) is a prefix of another it | |
// will match the longer piece. | |
minPieces.sort(cmpLenRev); | |
shortPieces.sort(cmpLenRev); | |
longPieces.sort(cmpLenRev); | |
mixedPieces.sort(cmpLenRev); | |
this._weekdaysRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i'); | |
this._weekdaysShortRegex = this._weekdaysRegex; | |
this._weekdaysMinRegex = this._weekdaysRegex; | |
this._weekdaysStrictRegex = new RegExp( | |
'^(' + longPieces.join('|') + ')', | |
'i' | |
); | |
this._weekdaysShortStrictRegex = new RegExp( | |
'^(' + shortPieces.join('|') + ')', | |
'i' | |
); | |
this._weekdaysMinStrictRegex = new RegExp( | |
'^(' + minPieces.join('|') + ')', | |
'i' | |
); | |
} | |
// FORMATTING | |
function hFormat() { | |
return this.hours() % 12 || 12; | |
} | |
function kFormat() { | |
return this.hours() || 24; | |
} | |
addFormatToken('H', ['HH', 2], 0, 'hour'); | |
addFormatToken('h', ['hh', 2], 0, hFormat); | |
addFormatToken('k', ['kk', 2], 0, kFormat); | |
addFormatToken('hmm', 0, 0, function () { | |
return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2); | |
}); | |
addFormatToken('hmmss', 0, 0, function () { | |
return ( | |
'' + | |
hFormat.apply(this) + | |
zeroFill(this.minutes(), 2) + | |
zeroFill(this.seconds(), 2) | |
); | |
}); | |
addFormatToken('Hmm', 0, 0, function () { | |
return '' + this.hours() + zeroFill(this.minutes(), 2); | |
}); | |
addFormatToken('Hmmss', 0, 0, function () { | |
return ( | |
'' + | |
this.hours() + | |
zeroFill(this.minutes(), 2) + | |
zeroFill(this.seconds(), 2) | |
); | |
}); | |
function meridiem(token, lowercase) { | |
addFormatToken(token, 0, 0, function () { | |
return this.localeData().meridiem( | |
this.hours(), | |
this.minutes(), | |
lowercase | |
); | |
}); | |
} | |
meridiem('a', true); | |
meridiem('A', false); | |
// ALIASES | |
addUnitAlias('hour', 'h'); | |
// PRIORITY | |
addUnitPriority('hour', 13); | |
// PARSING | |
function matchMeridiem(isStrict, locale) { | |
return locale._meridiemParse; | |
} | |
addRegexToken('a', matchMeridiem); | |
addRegexToken('A', matchMeridiem); | |
addRegexToken('H', match1to2); | |
addRegexToken('h', match1to2); | |
addRegexToken('k', match1to2); | |
addRegexToken('HH', match1to2, match2); | |
addRegexToken('hh', match1to2, match2); | |
addRegexToken('kk', match1to2, match2); | |
addRegexToken('hmm', match3to4); | |
addRegexToken('hmmss', match5to6); | |
addRegexToken('Hmm', match3to4); | |
addRegexToken('Hmmss', match5to6); | |
addParseToken(['H', 'HH'], HOUR); | |
addParseToken(['k', 'kk'], function (input, array, config) { | |
var kInput = toInt(input); | |
array[HOUR] = kInput === 24 ? 0 : kInput; | |
}); | |
addParseToken(['a', 'A'], function (input, array, config) { | |
config._isPm = config._locale.isPM(input); | |
config._meridiem = input; | |
}); | |
addParseToken(['h', 'hh'], function (input, array, config) { | |
array[HOUR] = toInt(input); | |
getParsingFlags(config).bigHour = true; | |
}); | |
addParseToken('hmm', function (input, array, config) { | |
var pos = input.length - 2; | |
array[HOUR] = toInt(input.substr(0, pos)); | |
array[MINUTE] = toInt(input.substr(pos)); | |
getParsingFlags(config).bigHour = true; | |
}); | |
addParseToken('hmmss', function (input, array, config) { | |
var pos1 = input.length - 4, | |
pos2 = input.length - 2; | |
array[HOUR] = toInt(input.substr(0, pos1)); | |
array[MINUTE] = toInt(input.substr(pos1, 2)); | |
array[SECOND] = toInt(input.substr(pos2)); | |
getParsingFlags(config).bigHour = true; | |
}); | |
addParseToken('Hmm', function (input, array, config) { | |
var pos = input.length - 2; | |
array[HOUR] = toInt(input.substr(0, pos)); | |
array[MINUTE] = toInt(input.substr(pos)); | |
}); | |
addParseToken('Hmmss', function (input, array, config) { | |
var pos1 = input.length - 4, | |
pos2 = input.length - 2; | |
array[HOUR] = toInt(input.substr(0, pos1)); | |
array[MINUTE] = toInt(input.substr(pos1, 2)); | |
array[SECOND] = toInt(input.substr(pos2)); | |
}); | |
// LOCALES | |
function localeIsPM(input) { | |
// IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays | |
// Using charAt should be more compatible. | |
return (input + '').toLowerCase().charAt(0) === 'p'; | |
} | |
var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i, | |
// Setting the hour should keep the time, because the user explicitly | |
// specified which hour they want. So trying to maintain the same hour (in | |
// a new timezone) makes sense. Adding/subtracting hours does not follow | |
// this rule. | |
getSetHour = makeGetSet('Hours', true); | |
function localeMeridiem(hours, minutes, isLower) { | |
if (hours > 11) { | |
return isLower ? 'pm' : 'PM'; | |
} else { | |
return isLower ? 'am' : 'AM'; | |
} | |
} | |
var baseConfig = { | |
calendar: defaultCalendar, | |
longDateFormat: defaultLongDateFormat, | |
invalidDate: defaultInvalidDate, | |
ordinal: defaultOrdinal, | |
dayOfMonthOrdinalParse: defaultDayOfMonthOrdinalParse, | |
relativeTime: defaultRelativeTime, | |
months: defaultLocaleMonths, | |
monthsShort: defaultLocaleMonthsShort, | |
week: defaultLocaleWeek, | |
weekdays: defaultLocaleWeekdays, | |
weekdaysMin: defaultLocaleWeekdaysMin, | |
weekdaysShort: defaultLocaleWeekdaysShort, | |
meridiemParse: defaultLocaleMeridiemParse, | |
}; | |
// internal storage for locale config files | |
var locales = {}, | |
localeFamilies = {}, | |
globalLocale; | |
function commonPrefix(arr1, arr2) { | |
var i, | |
minl = Math.min(arr1.length, arr2.length); | |
for (i = 0; i < minl; i += 1) { | |
if (arr1[i] !== arr2[i]) { | |
return i; | |
} | |
} | |
return minl; | |
} | |
function normalizeLocale(key) { | |
return key ? key.toLowerCase().replace('_', '-') : key; | |
} | |
// pick the locale from the array | |
// try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each | |
// substring from most specific to least, but move to the next array item if it's a more specific variant than the current root | |
function chooseLocale(names) { | |
var i = 0, | |
j, | |
next, | |
locale, | |
split; | |
while (i < names.length) { | |
split = normalizeLocale(names[i]).split('-'); | |
j = split.length; | |
next = normalizeLocale(names[i + 1]); | |
next = next ? next.split('-') : null; | |
while (j > 0) { | |
locale = loadLocale(split.slice(0, j).join('-')); | |
if (locale) { | |
return locale; | |
} | |
if ( | |
next && | |
next.length >= j && | |
commonPrefix(split, next) >= j - 1 | |
) { | |
//the next array item is better than a shallower substring of this one | |
break; | |
} | |
j--; | |
} | |
i++; | |
} | |
return globalLocale; | |
} | |
function loadLocale(name) { | |
var oldLocale = null, | |
aliasedRequire; | |
// TODO: Find a better way to register and load all the locales in Node | |
if ( | |
locales[name] === undefined && | |
'object' !== 'undefined' && | |
module && | |
module.exports | |
) { | |
try { | |
oldLocale = globalLocale._abbr; | |
aliasedRequire = commonjsRequire; | |
aliasedRequire('./locale/' + name); | |
getSetGlobalLocale(oldLocale); | |
} catch (e) { | |
// mark as not found to avoid repeating expensive file require call causing high CPU | |
// when trying to find en-US, en_US, en-us for every format call | |
locales[name] = null; // null means not found | |
} | |
} | |
return locales[name]; | |
} | |
// This function will load locale and then set the global locale. If | |
// no arguments are passed in, it will simply return the current global | |
// locale key. | |
function getSetGlobalLocale(key, values) { | |
var data; | |
if (key) { | |
if (isUndefined(values)) { | |
data = getLocale(key); | |
} else { | |
data = defineLocale(key, values); | |
} | |
if (data) { | |
// moment.duration._locale = moment._locale = data; | |
globalLocale = data; | |
} else { | |
if (typeof console !== 'undefined' && console.warn) { | |
//warn user if arguments are passed but the locale could not be set | |
console.warn( | |
'Locale ' + key + ' not found. Did you forget to load it?' | |
); | |
} | |
} | |
} | |
return globalLocale._abbr; | |
} | |
function defineLocale(name, config) { | |
if (config !== null) { | |
var locale, | |
parentConfig = baseConfig; | |
config.abbr = name; | |
if (locales[name] != null) { | |
deprecateSimple( | |
'defineLocaleOverride', | |
'use moment.updateLocale(localeName, config) to change ' + | |
'an existing locale. moment.defineLocale(localeName, ' + | |
'config) should only be used for creating a new locale ' + | |
'See http://momentjs.com/guides/#/warnings/define-locale/ for more info.' | |
); | |
parentConfig = locales[name]._config; | |
} else if (config.parentLocale != null) { | |
if (locales[config.parentLocale] != null) { | |
parentConfig = locales[config.parentLocale]._config; | |
} else { | |
locale = loadLocale(config.parentLocale); | |
if (locale != null) { | |
parentConfig = locale._config; | |
} else { | |
if (!localeFamilies[config.parentLocale]) { | |
localeFamilies[config.parentLocale] = []; | |
} | |
localeFamilies[config.parentLocale].push({ | |
name: name, | |
config: config, | |
}); | |
return null; | |
} | |
} | |
} | |
locales[name] = new Locale(mergeConfigs(parentConfig, config)); | |
if (localeFamilies[name]) { | |
localeFamilies[name].forEach(function (x) { | |
defineLocale(x.name, x.config); | |
}); | |
} | |
// backwards compat for now: also set the locale | |
// make sure we set the locale AFTER all child locales have been | |
// created, so we won't end up with the child locale set. | |
getSetGlobalLocale(name); | |
return locales[name]; | |
} else { | |
// useful for testing | |
delete locales[name]; | |
return null; | |
} | |
} | |
function updateLocale(name, config) { | |
if (config != null) { | |
var locale, | |
tmpLocale, | |
parentConfig = baseConfig; | |
if (locales[name] != null && locales[name].parentLocale != null) { | |
// Update existing child locale in-place to avoid memory-leaks | |
locales[name].set(mergeConfigs(locales[name]._config, config)); | |
} else { | |
// MERGE | |
tmpLocale = loadLocale(name); | |
if (tmpLocale != null) { | |
parentConfig = tmpLocale._config; | |
} | |
config = mergeConfigs(parentConfig, config); | |
if (tmpLocale == null) { | |
// updateLocale is called for creating a new locale | |
// Set abbr so it will have a name (getters return | |
// undefined otherwise). | |
config.abbr = name; | |
} | |
locale = new Locale(config); | |
locale.parentLocale = locales[name]; | |
locales[name] = locale; | |
} | |
// backwards compat for now: also set the locale | |
getSetGlobalLocale(name); | |
} else { | |
// pass null for config to unupdate, useful for tests | |
if (locales[name] != null) { | |
if (locales[name].parentLocale != null) { | |
locales[name] = locales[name].parentLocale; | |
if (name === getSetGlobalLocale()) { | |
getSetGlobalLocale(name); | |
} | |
} else if (locales[name] != null) { | |
delete locales[name]; | |
} | |
} | |
} | |
return locales[name]; | |
} | |
// returns locale data | |
function getLocale(key) { | |
var locale; | |
if (key && key._locale && key._locale._abbr) { | |
key = key._locale._abbr; | |
} | |
if (!key) { | |
return globalLocale; | |
} | |
if (!isArray(key)) { | |
//short-circuit everything else | |
locale = loadLocale(key); | |
if (locale) { | |
return locale; | |
} | |
key = [key]; | |
} | |
return chooseLocale(key); | |
} | |
function listLocales() { | |
return keys(locales); | |
} | |
function checkOverflow(m) { | |
var overflow, | |
a = m._a; | |
if (a && getParsingFlags(m).overflow === -2) { | |
overflow = | |
a[MONTH] < 0 || a[MONTH] > 11 | |
? MONTH | |
: a[DATE] < 1 || a[DATE] > daysInMonth(a[YEAR], a[MONTH]) | |
? DATE | |
: a[HOUR] < 0 || | |
a[HOUR] > 24 || | |
(a[HOUR] === 24 && | |
(a[MINUTE] !== 0 || | |
a[SECOND] !== 0 || | |
a[MILLISECOND] !== 0)) | |
? HOUR | |
: a[MINUTE] < 0 || a[MINUTE] > 59 | |
? MINUTE | |
: a[SECOND] < 0 || a[SECOND] > 59 | |
? SECOND | |
: a[MILLISECOND] < 0 || a[MILLISECOND] > 999 | |
? MILLISECOND | |
: -1; | |
if ( | |
getParsingFlags(m)._overflowDayOfYear && | |
(overflow < YEAR || overflow > DATE) | |
) { | |
overflow = DATE; | |
} | |
if (getParsingFlags(m)._overflowWeeks && overflow === -1) { | |
overflow = WEEK; | |
} | |
if (getParsingFlags(m)._overflowWeekday && overflow === -1) { | |
overflow = WEEKDAY; | |
} | |
getParsingFlags(m).overflow = overflow; | |
} | |
return m; | |
} | |
// iso 8601 regex | |
// 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00) | |
var extendedIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/, | |
basicIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d|))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/, | |
tzRegex = /Z|[+-]\d\d(?::?\d\d)?/, | |
isoDates = [ | |
['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/], | |
['YYYY-MM-DD', /\d{4}-\d\d-\d\d/], | |
['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/], | |
['GGGG-[W]WW', /\d{4}-W\d\d/, false], | |
['YYYY-DDD', /\d{4}-\d{3}/], | |
['YYYY-MM', /\d{4}-\d\d/, false], | |
['YYYYYYMMDD', /[+-]\d{10}/], | |
['YYYYMMDD', /\d{8}/], | |
['GGGG[W]WWE', /\d{4}W\d{3}/], | |
['GGGG[W]WW', /\d{4}W\d{2}/, false], | |
['YYYYDDD', /\d{7}/], | |
['YYYYMM', /\d{6}/, false], | |
['YYYY', /\d{4}/, false], | |
], | |
// iso time formats and regexes | |
isoTimes = [ | |
['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/], | |
['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/], | |
['HH:mm:ss', /\d\d:\d\d:\d\d/], | |
['HH:mm', /\d\d:\d\d/], | |
['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/], | |
['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/], | |
['HHmmss', /\d\d\d\d\d\d/], | |
['HHmm', /\d\d\d\d/], | |
['HH', /\d\d/], | |
], | |
aspNetJsonRegex = /^\/?Date\((-?\d+)/i, | |
// RFC 2822 regex: For details see https://tools.ietf.org/html/rfc2822#section-3.3 | |
rfc2822 = /^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/, | |
obsOffsets = { | |
UT: 0, | |
GMT: 0, | |
EDT: -4 * 60, | |
EST: -5 * 60, | |
CDT: -5 * 60, | |
CST: -6 * 60, | |
MDT: -6 * 60, | |
MST: -7 * 60, | |
PDT: -7 * 60, | |
PST: -8 * 60, | |
}; | |
// date from iso format | |
function configFromISO(config) { | |
var i, | |
l, | |
string = config._i, | |
match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string), | |
allowTime, | |
dateFormat, | |
timeFormat, | |
tzFormat; | |
if (match) { | |
getParsingFlags(config).iso = true; | |
for (i = 0, l = isoDates.length; i < l; i++) { | |
if (isoDates[i][1].exec(match[1])) { | |
dateFormat = isoDates[i][0]; | |
allowTime = isoDates[i][2] !== false; | |
break; | |
} | |
} | |
if (dateFormat == null) { | |
config._isValid = false; | |
return; | |
} | |
if (match[3]) { | |
for (i = 0, l = isoTimes.length; i < l; i++) { | |
if (isoTimes[i][1].exec(match[3])) { | |
// match[2] should be 'T' or space | |
timeFormat = (match[2] || ' ') + isoTimes[i][0]; | |
break; | |
} | |
} | |
if (timeFormat == null) { | |
config._isValid = false; | |
return; | |
} | |
} | |
if (!allowTime && timeFormat != null) { | |
config._isValid = false; | |
return; | |
} | |
if (match[4]) { | |
if (tzRegex.exec(match[4])) { | |
tzFormat = 'Z'; | |
} else { | |
config._isValid = false; | |
return; | |
} | |
} | |
config._f = dateFormat + (timeFormat || '') + (tzFormat || ''); | |
configFromStringAndFormat(config); | |
} else { | |
config._isValid = false; | |
} | |
} | |
function extractFromRFC2822Strings( | |
yearStr, | |
monthStr, | |
dayStr, | |
hourStr, | |
minuteStr, | |
secondStr | |
) { | |
var result = [ | |
untruncateYear(yearStr), | |
defaultLocaleMonthsShort.indexOf(monthStr), | |
parseInt(dayStr, 10), | |
parseInt(hourStr, 10), | |
parseInt(minuteStr, 10), | |
]; | |
if (secondStr) { | |
result.push(parseInt(secondStr, 10)); | |
} | |
return result; | |
} | |
function untruncateYear(yearStr) { | |
var year = parseInt(yearStr, 10); | |
if (year <= 49) { | |
return 2000 + year; | |
} else if (year <= 999) { | |
return 1900 + year; | |
} | |
return year; | |
} | |
function preprocessRFC2822(s) { | |
// Remove comments and folding whitespace and replace multiple-spaces with a single space | |
return s | |
.replace(/\([^)]*\)|[\n\t]/g, ' ') | |
.replace(/(\s\s+)/g, ' ') | |
.replace(/^\s\s*/, '') | |
.replace(/\s\s*$/, ''); | |
} | |
function checkWeekday(weekdayStr, parsedInput, config) { | |
if (weekdayStr) { | |
// TODO: Replace the vanilla JS Date object with an independent day-of-week check. | |
var weekdayProvided = defaultLocaleWeekdaysShort.indexOf(weekdayStr), | |
weekdayActual = new Date( | |
parsedInput[0], | |
parsedInput[1], | |
parsedInput[2] | |
).getDay(); | |
if (weekdayProvided !== weekdayActual) { | |
getParsingFlags(config).weekdayMismatch = true; | |
config._isValid = false; | |
return false; | |
} | |
} | |
return true; | |
} | |
function calculateOffset(obsOffset, militaryOffset, numOffset) { | |
if (obsOffset) { | |
return obsOffsets[obsOffset]; | |
} else if (militaryOffset) { | |
// the only allowed military tz is Z | |
return 0; | |
} else { | |
var hm = parseInt(numOffset, 10), | |
m = hm % 100, | |
h = (hm - m) / 100; | |
return h * 60 + m; | |
} | |
} | |
// date and time from ref 2822 format | |
function configFromRFC2822(config) { | |
var match = rfc2822.exec(preprocessRFC2822(config._i)), | |
parsedArray; | |
if (match) { | |
parsedArray = extractFromRFC2822Strings( | |
match[4], | |
match[3], | |
match[2], | |
match[5], | |
match[6], | |
match[7] | |
); | |
if (!checkWeekday(match[1], parsedArray, config)) { | |
return; | |
} | |
config._a = parsedArray; | |
config._tzm = calculateOffset(match[8], match[9], match[10]); | |
config._d = createUTCDate.apply(null, config._a); | |
config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm); | |
getParsingFlags(config).rfc2822 = true; | |
} else { | |
config._isValid = false; | |
} | |
} | |
// date from 1) ASP.NET, 2) ISO, 3) RFC 2822 formats, or 4) optional fallback if parsing isn't strict | |
function configFromString(config) { | |
var matched = aspNetJsonRegex.exec(config._i); | |
if (matched !== null) { | |
config._d = new Date(+matched[1]); | |
return; | |
} | |
configFromISO(config); | |
if (config._isValid === false) { | |
delete config._isValid; | |
} else { | |
return; | |
} | |
configFromRFC2822(config); | |
if (config._isValid === false) { | |
delete config._isValid; | |
} else { | |
return; | |
} | |
if (config._strict) { | |
config._isValid = false; | |
} else { | |
// Final attempt, use Input Fallback | |
hooks.createFromInputFallback(config); | |
} | |
} | |
hooks.createFromInputFallback = deprecate( | |
'value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), ' + | |
'which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are ' + | |
'discouraged and will be removed in an upcoming major release. Please refer to ' + | |
'http://momentjs.com/guides/#/warnings/js-date/ for more info.', | |
function (config) { | |
config._d = new Date(config._i + (config._useUTC ? ' UTC' : '')); | |
} | |
); | |
// Pick the first defined of two or three arguments. | |
function defaults(a, b, c) { | |
if (a != null) { | |
return a; | |
} | |
if (b != null) { | |
return b; | |
} | |
return c; | |
} | |
function currentDateArray(config) { | |
// hooks is actually the exported moment object | |
var nowValue = new Date(hooks.now()); | |
if (config._useUTC) { | |
return [ | |
nowValue.getUTCFullYear(), | |
nowValue.getUTCMonth(), | |
nowValue.getUTCDate(), | |
]; | |
} | |
return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()]; | |
} | |
// 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 configFromArray(config) { | |
var i, | |
date, | |
input = [], | |
currentDate, | |
expectedWeekday, | |
yearToUse; | |
if (config._d) { | |
return; | |
} | |
currentDate = currentDateArray(config); | |
//compute day of the year from weeks and weekdays | |
if (config._w && config._a[DATE] == null && config._a[MONTH] == null) { | |
dayOfYearFromWeekInfo(config); | |
} | |
//if the day of the year is set, figure out what it is | |
if (config._dayOfYear != null) { | |
yearToUse = defaults(config._a[YEAR], currentDate[YEAR]); | |
if ( | |
config._dayOfYear > daysInYear(yearToUse) || | |
config._dayOfYear === 0 | |
) { | |
getParsingFlags(config)._overflowDayOfYear = true; | |
} | |
date = createUTCDate(yearToUse, 0, config._dayOfYear); | |
config._a[MONTH] = date.getUTCMonth(); | |
config._a[DATE] = date.getUTCDate(); | |
} | |
// Default to current date. | |
// * if no year, month, day of month are given, default to today | |
// * if day of month is given, default month and year | |
// * if month is given, default only year | |
// * if year is given, don't default anything | |
for (i = 0; i < 3 && config._a[i] == null; ++i) { | |
config._a[i] = input[i] = currentDate[i]; | |
} | |
// Zero out whatever was not defaulted, including time | |
for (; i < 7; i++) { | |
config._a[i] = input[i] = | |
config._a[i] == null ? (i === 2 ? 1 : 0) : config._a[i]; | |
} | |
// Check for 24:00:00.000 | |
if ( | |
config._a[HOUR] === 24 && | |
config._a[MINUTE] === 0 && | |
config._a[SECOND] === 0 && | |
config._a[MILLISECOND] === 0 | |
) { | |
config._nextDay = true; | |
config._a[HOUR] = 0; | |
} | |
config._d = (config._useUTC ? createUTCDate : createDate).apply( | |
null, | |
input | |
); | |
expectedWeekday = config._useUTC | |
? config._d.getUTCDay() | |
: config._d.getDay(); | |
// Apply timezone offset from input. The actual utcOffset can be changed | |
// with parseZone. | |
if (config._tzm != null) { | |
config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm); | |
} | |
if (config._nextDay) { | |
config._a[HOUR] = 24; | |
} | |
// check for mismatching day of week | |
if ( | |
config._w && | |
typeof config._w.d !== 'undefined' && | |
config._w.d !== expectedWeekday | |
) { | |
getParsingFlags(config).weekdayMismatch = true; | |
} | |
} | |
function dayOfYearFromWeekInfo(config) { | |
var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow, curWeek; | |
w = config._w; | |
if (w.GG != null || w.W != null || w.E != null) { | |
dow = 1; | |
doy = 4; | |
// TODO: We need to take the current isoWeekYear, but that depends on | |
// how we interpret now (local, utc, fixed offset). So create | |
// a now version of current config (take local/utc/offset flags, and | |
// create now). | |
weekYear = defaults( | |
w.GG, | |
config._a[YEAR], | |
weekOfYear(createLocal(), 1, 4).year | |
); | |
week = defaults(w.W, 1); | |
weekday = defaults(w.E, 1); | |
if (weekday < 1 || weekday > 7) { | |
weekdayOverflow = true; | |
} | |
} else { | |
dow = config._locale._week.dow; | |
doy = config._locale._week.doy; | |
curWeek = weekOfYear(createLocal(), dow, doy); | |
weekYear = defaults(w.gg, config._a[YEAR], curWeek.year); | |
// Default to current week. | |
week = defaults(w.w, curWeek.week); | |
if (w.d != null) { | |
// weekday -- low day numbers are considered next week | |
weekday = w.d; | |
if (weekday < 0 || weekday > 6) { | |
weekdayOverflow = true; | |
} | |
} else if (w.e != null) { | |
// local weekday -- counting starts from beginning of week | |
weekday = w.e + dow; | |
if (w.e < 0 || w.e > 6) { | |
weekdayOverflow = true; | |
} | |
} else { | |
// default to beginning of week | |
weekday = dow; | |
} | |
} | |
if (week < 1 || week > weeksInYear(weekYear, dow, doy)) { | |
getParsingFlags(config)._overflowWeeks = true; | |
} else if (weekdayOverflow != null) { | |
getParsingFlags(config)._overflowWeekday = true; | |
} else { | |
temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy); | |
config._a[YEAR] = temp.year; | |
config._dayOfYear = temp.dayOfYear; | |
} | |
} | |
// constant that refers to the ISO standard | |
hooks.ISO_8601 = function () {}; | |
// constant that refers to the RFC 2822 form | |
hooks.RFC_2822 = function () {}; | |
// date from string and format string | |
function configFromStringAndFormat(config) { | |
// TODO: Move this to another part of the creation flow to prevent circular deps | |
if (config._f === hooks.ISO_8601) { | |
configFromISO(config); | |
return; | |
} | |
if (config._f === hooks.RFC_2822) { | |
configFromRFC2822(config); | |
return; | |
} | |
config._a = []; | |
getParsingFlags(config).empty = true; | |
// This array is used to make a Date, either with `new Date` or `Date.UTC` | |
var string = '' + config._i, | |
i, | |
parsedInput, | |
tokens, | |
token, | |
skipped, | |
stringLength = string.length, | |
totalParsedInputLength = 0, | |
era; | |
tokens = | |
expandFormat(config._f, config._locale).match(formattingTokens) || []; | |
for (i = 0; i < tokens.length; i++) { | |
token = tokens[i]; | |
parsedInput = (string.match(getParseRegexForToken(token, config)) || | |
[])[0]; | |
if (parsedInput) { | |
skipped = string.substr(0, string.indexOf(parsedInput)); | |
if (skipped.length > 0) { | |
getParsingFlags(config).unusedInput.push(skipped); | |
} | |
string = string.slice( | |
string.indexOf(parsedInput) + parsedInput.length | |
); | |
totalParsedInputLength += parsedInput.length; | |
} | |
// don't parse if it's not a known token | |
if (formatTokenFunctions[token]) { | |
if (parsedInput) { | |
getParsingFlags(config).empty = false; | |
} else { | |
getParsingFlags(config).unusedTokens.push(token); | |
} | |
addTimeToArrayFromToken(token, parsedInput, config); | |
} else if (config._strict && !parsedInput) { | |
getParsingFlags(config).unusedTokens.push(token); | |
} | |
} | |
// add remaining unparsed input length to the string | |
getParsingFlags(config).charsLeftOver = | |
stringLength - totalParsedInputLength; | |
if (string.length > 0) { | |
getParsingFlags(config).unusedInput.push(string); | |
} | |
// clear _12h flag if hour is <= 12 | |
if ( | |
config._a[HOUR] <= 12 && | |
getParsingFlags(config).bigHour === true && | |
config._a[HOUR] > 0 | |
) { | |
getParsingFlags(config).bigHour = undefined; | |
} | |
getParsingFlags(config).parsedDateParts = config._a.slice(0); | |
getParsingFlags(config).meridiem = config._meridiem; | |
// handle meridiem | |
config._a[HOUR] = meridiemFixWrap( | |
config._locale, | |
config._a[HOUR], | |
config._meridiem | |
); | |
// handle era | |
era = getParsingFlags(config).era; | |
if (era !== null) { | |
config._a[YEAR] = config._locale.erasConvertYear(era, config._a[YEAR]); | |
} | |
configFromArray(config); | |
checkOverflow(config); | |
} | |
function meridiemFixWrap(locale, hour, meridiem) { | |
var isPm; | |
if (meridiem == null) { | |
// nothing to do | |
return hour; | |
} | |
if (locale.meridiemHour != null) { | |
return locale.meridiemHour(hour, meridiem); | |
} else if (locale.isPM != null) { | |
// Fallback | |
isPm = locale.isPM(meridiem); | |
if (isPm && hour < 12) { | |
hour += 12; | |
} | |
if (!isPm && hour === 12) { | |
hour = 0; | |
} | |
return hour; | |
} else { | |
// this is not supposed to happen | |
return hour; | |
} | |
} | |
// date from string and array of format strings | |
function configFromStringAndArray(config) { | |
var tempConfig, | |
bestMoment, | |
scoreToBeat, | |
i, | |
currentScore, | |
validFormatFound, | |
bestFormatIsValid = false; | |
if (config._f.length === 0) { | |
getParsingFlags(config).invalidFormat = true; | |
config._d = new Date(NaN); | |
return; | |
} | |
for (i = 0; i < config._f.length; i++) { | |
currentScore = 0; | |
validFormatFound = false; | |
tempConfig = copyConfig({}, config); | |
if (config._useUTC != null) { | |
tempConfig._useUTC = config._useUTC; | |
} | |
tempConfig._f = config._f[i]; | |
configFromStringAndFormat(tempConfig); | |
if (isValid(tempConfig)) { | |
validFormatFound = true; | |
} | |
// if there is any input that was not parsed add a penalty for that format | |
currentScore += getParsingFlags(tempConfig).charsLeftOver; | |
//or tokens | |
currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10; | |
getParsingFlags(tempConfig).score = currentScore; | |
if (!bestFormatIsValid) { | |
if ( | |
scoreToBeat == null || | |
currentScore < scoreToBeat || | |
validFormatFound | |
) { | |
scoreToBeat = currentScore; | |
bestMoment = tempConfig; | |
if (validFormatFound) { | |
bestFormatIsValid = true; | |
} | |
} | |
} else { | |
if (currentScore < scoreToBeat) { | |
scoreToBeat = currentScore; | |
bestMoment = tempConfig; | |
} | |
} | |
} | |
extend(config, bestMoment || tempConfig); | |
} | |
function configFromObject(config) { | |
if (config._d) { | |
return; | |
} | |
var i = normalizeObjectUnits(config._i), | |
dayOrDate = i.day === undefined ? i.date : i.day; | |
config._a = map( | |
[i.year, i.month, dayOrDate, i.hour, i.minute, i.second, i.millisecond], | |
function (obj) { | |
return obj && parseInt(obj, 10); | |
} | |
); | |
configFromArray(config); | |
} | |
function createFromConfig(config) { | |
var res = new Moment(checkOverflow(prepareConfig(config))); | |
if (res._nextDay) { | |
// Adding is smart enough around DST | |
res.add(1, 'd'); | |
res._nextDay = undefined; | |
} | |
return res; | |
} | |
function prepareConfig(config) { | |
var input = config._i, | |
format = config._f; | |
config._locale = config._locale || getLocale(config._l); | |
if (input === null || (format === undefined && input === '')) { | |
return createInvalid({ nullInput: true }); | |
} | |
if (typeof input === 'string') { | |
config._i = input = config._locale.preparse(input); | |
} | |
if (isMoment(input)) { | |
return new Moment(checkOverflow(input)); | |
} else if (isDate(input)) { | |
config._d = input; | |
} else if (isArray(format)) { | |
configFromStringAndArray(config); | |
} else if (format) { | |
configFromStringAndFormat(config); | |
} else { | |
configFromInput(config); | |
} | |
if (!isValid(config)) { | |
config._d = null; | |
} | |
return config; | |
} | |
function configFromInput(config) { | |
var input = config._i; | |
if (isUndefined(input)) { | |
config._d = new Date(hooks.now()); | |
} else if (isDate(input)) { | |
config._d = new Date(input.valueOf()); | |
} else if (typeof input === 'string') { | |
configFromString(config); | |
} else if (isArray(input)) { | |
config._a = map(input.slice(0), function (obj) { | |
return parseInt(obj, 10); | |
}); | |
configFromArray(config); | |
} else if (isObject(input)) { | |
configFromObject(config); | |
} else if (isNumber(input)) { | |
// from milliseconds | |
config._d = new Date(input); | |
} else { | |
hooks.createFromInputFallback(config); | |
} | |
} | |
function createLocalOrUTC(input, format, locale, strict, isUTC) { | |
var c = {}; | |
if (format === true || format === false) { | |
strict = format; | |
format = undefined; | |
} | |
if (locale === true || locale === false) { | |
strict = locale; | |
locale = undefined; | |
} | |
if ( | |
(isObject(input) && isObjectEmpty(input)) || | |
(isArray(input) && input.length === 0) | |
) { | |
input = undefined; | |
} | |
// object construction must be done this way. | |
// https://github.com/moment/moment/issues/1423 | |
c._isAMomentObject = true; | |
c._useUTC = c._isUTC = isUTC; | |
c._l = locale; | |
c._i = input; | |
c._f = format; | |
c._strict = strict; | |
return createFromConfig(c); | |
} | |
function createLocal(input, format, locale, strict) { | |
return createLocalOrUTC(input, format, locale, strict, false); | |
} | |
var prototypeMin = deprecate( | |
'moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/', | |
function () { | |
var other = createLocal.apply(null, arguments); | |
if (this.isValid() && other.isValid()) { | |
return other < this ? this : other; | |
} else { | |
return createInvalid(); | |
} | |
} | |
), | |
prototypeMax = deprecate( | |
'moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/', | |
function () { | |
var other = createLocal.apply(null, arguments); | |
if (this.isValid() && other.isValid()) { | |
return other > this ? this : other; | |
} else { | |
return createInvalid(); | |
} | |
} | |
); | |
// Pick a moment m from moments so that m[fn](other) is true for all | |
// other. This relies on the function fn to be transitive. | |
// | |
// moments should either be an array of moment objects or an array, whose | |
// first element is an array of moment objects. | |
function pickBy(fn, moments) { | |
var res, i; | |
if (moments.length === 1 && isArray(moments[0])) { | |
moments = moments[0]; | |
} | |
if (!moments.length) { | |
return createLocal(); | |
} | |
res = moments[0]; | |
for (i = 1; i < moments.length; ++i) { | |
if (!moments[i].isValid() || moments[i][fn](res)) { | |
res = moments[i]; | |
} | |
} | |
return res; | |
} | |
// TODO: Use [].sort instead? | |
function min() { | |
var args = [].slice.call(arguments, 0); | |
return pickBy('isBefore', args); | |
} | |
function max() { | |
var args = [].slice.call(arguments, 0); | |
return pickBy('isAfter', args); | |
} | |
var now = function () { | |
return Date.now ? Date.now() : +new Date(); | |
}; | |
var ordering = [ | |
'year', | |
'quarter', | |
'month', | |
'week', | |
'day', | |
'hour', | |
'minute', | |
'second', | |
'millisecond', | |
]; | |
function isDurationValid(m) { | |
var key, | |
unitHasDecimal = false, | |
i; | |
for (key in m) { | |
if ( | |
hasOwnProp(m, key) && | |
!( | |
indexOf.call(ordering, key) !== -1 && | |
(m[key] == null || !isNaN(m[key])) | |
) | |
) { | |
return false; | |
} | |
} | |
for (i = 0; i < ordering.length; ++i) { | |
if (m[ordering[i]]) { | |
if (unitHasDecimal) { | |
return false; // only allow non-integers for smallest unit | |
} | |
if (parseFloat(m[ordering[i]]) !== toInt(m[ordering[i]])) { | |
unitHasDecimal = true; | |
} | |
} | |
} | |
return true; | |
} | |
function isValid$1() { | |
return this._isValid; | |
} | |
function createInvalid$1() { | |
return createDuration(NaN); | |
} | |
function Duration(duration) { | |
var normalizedInput = normalizeObjectUnits(duration), | |
years = normalizedInput.year || 0, | |
quarters = normalizedInput.quarter || 0, | |
months = normalizedInput.month || 0, | |
weeks = normalizedInput.week || normalizedInput.isoWeek || 0, | |
days = normalizedInput.day || 0, | |
hours = normalizedInput.hour || 0, | |
minutes = normalizedInput.minute || 0, | |
seconds = normalizedInput.second || 0, | |
milliseconds = normalizedInput.millisecond || 0; | |
this._isValid = isDurationValid(normalizedInput); | |
// representation for dateAddRemove | |
this._milliseconds = | |
+milliseconds + | |
seconds * 1e3 + // 1000 | |
minutes * 6e4 + // 1000 * 60 | |
hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978 | |
// 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 to translate months into days without knowing | |
// which months you are are talking about, so we have to store | |
// it separately. | |
this._months = +months + quarters * 3 + years * 12; | |
this._data = {}; | |
this._locale = getLocale(); | |
this._bubble(); | |
} | |
function isDuration(obj) { | |
return obj instanceof Duration; | |
} | |
function absRound(number) { | |
if (number < 0) { | |
return Math.round(-1 * number) * -1; | |
} else { | |
return Math.round(number); | |
} | |
} | |
// compare two arrays, return the number of differences | |
function compareArrays(array1, array2, dontConvert) { | |
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 ( | |
(dontConvert && array1[i] !== array2[i]) || | |
(!dontConvert && toInt(array1[i]) !== toInt(array2[i])) | |
) { | |
diffs++; | |
} | |
} | |
return diffs + lengthDiff; | |
} | |
// FORMATTING | |
function offset(token, separator) { | |
addFormatToken(token, 0, 0, function () { | |
var offset = this.utcOffset(), | |
sign = '+'; | |
if (offset < 0) { | |
offset = -offset; | |
sign = '-'; | |
} | |
return ( | |
sign + | |
zeroFill(~~(offset / 60), 2) + | |
separator + | |
zeroFill(~~offset % 60, 2) | |
); | |
}); | |
} | |
offset('Z', ':'); | |
offset('ZZ', ''); | |
// PARSING | |
addRegexToken('Z', matchShortOffset); | |
addRegexToken('ZZ', matchShortOffset); | |
addParseToken(['Z', 'ZZ'], function (input, array, config) { | |
config._useUTC = true; | |
config._tzm = offsetFromString(matchShortOffset, input); | |
}); | |
// HELPERS | |
// timezone chunker | |
// '+10:00' > ['10', '00'] | |
// '-1530' > ['-15', '30'] | |
var chunkOffset = /([\+\-]|\d\d)/gi; | |
function offsetFromString(matcher, string) { | |
var matches = (string || '').match(matcher), | |
chunk, | |
parts, | |
minutes; | |
if (matches === null) { | |
return null; | |
} | |
chunk = matches[matches.length - 1] || []; | |
parts = (chunk + '').match(chunkOffset) || ['-', 0, 0]; | |
minutes = +(parts[1] * 60) + toInt(parts[2]); | |
return minutes === 0 ? 0 : parts[0] === '+' ? minutes : -minutes; | |
} | |
// Return a moment from input, that is local/utc/zone equivalent to model. | |
function cloneWithOffset(input, model) { | |
var res, diff; | |
if (model._isUTC) { | |
res = model.clone(); | |
diff = | |
(isMoment(input) || isDate(input) | |
? input.valueOf() | |
: createLocal(input).valueOf()) - res.valueOf(); | |
// Use low-level api, because this fn is low-level api. | |
res._d.setTime(res._d.valueOf() + diff); | |
hooks.updateOffset(res, false); | |
return res; | |
} else { | |
return createLocal(input).local(); | |
} | |
} | |
function getDateOffset(m) { | |
// On Firefox.24 Date#getTimezoneOffset returns a floating point. | |
// https://github.com/moment/moment/pull/1871 | |
return -Math.round(m._d.getTimezoneOffset()); | |
} | |
// HOOKS | |
// This function will be called whenever a moment is mutated. | |
// It is intended to keep the offset in sync with the timezone. | |
hooks.updateOffset = function () {}; | |
// MOMENTS | |
// keepLocalTime = true means only change the timezone, without | |
// affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]--> | |
// 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset | |
// +0200, so we adjust the time as needed, to be valid. | |
// | |
// Keeping the time actually adds/subtracts (one hour) | |
// from the actual represented time. That is why we call updateOffset | |
// a second time. In case it wants us to change the offset again | |
// _changeInProgress == true case, then we have to adjust, because | |
// there is no such time in the given timezone. | |
function getSetOffset(input, keepLocalTime, keepMinutes) { | |
var offset = this._offset || 0, | |
localAdjust; | |
if (!this.isValid()) { | |
return input != null ? this : NaN; | |
} | |
if (input != null) { | |
if (typeof input === 'string') { | |
input = offsetFromString(matchShortOffset, input); | |
if (input === null) { | |
return this; | |
} | |
} else if (Math.abs(input) < 16 && !keepMinutes) { | |
input = input * 60; | |
} | |
if (!this._isUTC && keepLocalTime) { | |
localAdjust = getDateOffset(this); | |
} | |
this._offset = input; | |
this._isUTC = true; | |
if (localAdjust != null) { | |
this.add(localAdjust, 'm'); | |
} | |
if (offset !== input) { | |
if (!keepLocalTime || this._changeInProgress) { | |
addSubtract( | |
this, | |
createDuration(input - offset, 'm'), | |
1, | |
false | |
); | |
} else if (!this._changeInProgress) { | |
this._changeInProgress = true; | |
hooks.updateOffset(this, true); | |
this._changeInProgress = null; | |
} | |
} | |
return this; | |
} else { | |
return this._isUTC ? offset : getDateOffset(this); | |
} | |
} | |
function getSetZone(input, keepLocalTime) { | |
if (input != null) { | |
if (typeof input !== 'string') { | |
input = -input; | |
} | |
this.utcOffset(input, keepLocalTime); | |
return this; | |
} else { | |
return -this.utcOffset(); | |
} | |
} | |
function setOffsetToUTC(keepLocalTime) { | |
return this.utcOffset(0, keepLocalTime); | |
} | |
function setOffsetToLocal(keepLocalTime) { | |
if (this._isUTC) { | |
this.utcOffset(0, keepLocalTime); | |
this._isUTC = false; | |
if (keepLocalTime) { | |
this.subtract(getDateOffset(this), 'm'); | |
} | |
} | |
return this; | |
} | |
function setOffsetToParsedOffset() { | |
if (this._tzm != null) { | |
this.utcOffset(this._tzm, false, true); | |
} else if (typeof this._i === 'string') { | |
var tZone = offsetFromString(matchOffset, this._i); | |
if (tZone != null) { | |
this.utcOffset(tZone); | |
} else { | |
this.utcOffset(0, true); | |
} | |
} | |
return this; | |
} | |
function hasAlignedHourOffset(input) { | |
if (!this.isValid()) { | |
return false; | |
} | |
input = input ? createLocal(input).utcOffset() : 0; | |
return (this.utcOffset() - input) % 60 === 0; | |
} | |
function isDaylightSavingTime() { | |
return ( | |
this.utcOffset() > this.clone().month(0).utcOffset() || | |
this.utcOffset() > this.clone().month(5).utcOffset() | |
); | |
} | |
function isDaylightSavingTimeShifted() { | |
if (!isUndefined(this._isDSTShifted)) { | |
return this._isDSTShifted; | |
} | |
var c = {}, | |
other; | |
copyConfig(c, this); | |
c = prepareConfig(c); | |
if (c._a) { | |
other = c._isUTC ? createUTC(c._a) : createLocal(c._a); | |
this._isDSTShifted = | |
this.isValid() && compareArrays(c._a, other.toArray()) > 0; | |
} else { | |
this._isDSTShifted = false; | |
} | |
return this._isDSTShifted; | |
} | |
function isLocal() { | |
return this.isValid() ? !this._isUTC : false; | |
} | |
function isUtcOffset() { | |
return this.isValid() ? this._isUTC : false; | |
} | |
function isUtc() { | |
return this.isValid() ? this._isUTC && this._offset === 0 : false; | |
} | |
// ASP.NET json date format regex | |
var aspNetRegex = /^(-|\+)?(?:(\d*)[. ])?(\d+):(\d+)(?::(\d+)(\.\d*)?)?$/, | |
// from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html | |
// somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere | |
// and further modified to allow for strings containing both week and day | |
isoRegex = /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/; | |
function createDuration(input, key) { | |
var duration = input, | |
// matching against regexp is expensive, do it on demand | |
match = null, | |
sign, | |
ret, | |
diffRes; | |
if (isDuration(input)) { | |
duration = { | |
ms: input._milliseconds, | |
d: input._days, | |
M: input._months, | |
}; | |
} else if (isNumber(input) || !isNaN(+input)) { | |
duration = {}; | |
if (key) { | |
duration[key] = +input; | |
} else { | |
duration.milliseconds = +input; | |
} | |
} else if ((match = aspNetRegex.exec(input))) { | |
sign = match[1] === '-' ? -1 : 1; | |
duration = { | |
y: 0, | |
d: toInt(match[DATE]) * sign, | |
h: toInt(match[HOUR]) * sign, | |
m: toInt(match[MINUTE]) * sign, | |
s: toInt(match[SECOND]) * sign, | |
ms: toInt(absRound(match[MILLISECOND] * 1000)) * sign, // the millisecond decimal point is included in the match | |
}; | |
} else if ((match = isoRegex.exec(input))) { | |
sign = match[1] === '-' ? -1 : 1; | |
duration = { | |
y: parseIso(match[2], sign), | |
M: parseIso(match[3], sign), | |
w: parseIso(match[4], sign), | |
d: parseIso(match[5], sign), | |
h: parseIso(match[6], sign), | |
m: parseIso(match[7], sign), | |
s: parseIso(match[8], sign), | |
}; | |
} else if (duration == null) { | |
// checks for null or undefined | |
duration = {}; | |
} else if ( | |
typeof duration === 'object' && | |
('from' in duration || 'to' in duration) | |
) { | |
diffRes = momentsDifference( | |
createLocal(duration.from), | |
createLocal(duration.to) | |
); | |
duration = {}; | |
duration.ms = diffRes.milliseconds; | |
duration.M = diffRes.months; | |
} | |
ret = new Duration(duration); | |
if (isDuration(input) && hasOwnProp(input, '_locale')) { | |
ret._locale = input._locale; | |
} | |
if (isDuration(input) && hasOwnProp(input, '_isValid')) { | |
ret._isValid = input._isValid; | |
} | |
return ret; | |
} | |
createDuration.fn = Duration.prototype; | |
createDuration.invalid = createInvalid$1; | |
function parseIso(inp, sign) { | |
// We'd normally use ~~inp for this, but unfortunately it also | |
// converts floats to ints. | |
// inp may be undefined, so careful calling replace on it. | |
var res = inp && parseFloat(inp.replace(',', '.')); | |
// apply sign while we're at it | |
return (isNaN(res) ? 0 : res) * sign; | |
} | |
function positiveMomentsDifference(base, other) { | |
var res = {}; | |
res.months = | |
other.month() - base.month() + (other.year() - base.year()) * 12; | |
if (base.clone().add(res.months, 'M').isAfter(other)) { | |
--res.months; | |
} | |
res.milliseconds = +other - +base.clone().add(res.months, 'M'); | |
return res; | |
} | |
function momentsDifference(base, other) { | |
var res; | |
if (!(base.isValid() && other.isValid())) { | |
return { milliseconds: 0, months: 0 }; | |
} | |
other = cloneWithOffset(other, base); | |
if (base.isBefore(other)) { | |
res = positiveMomentsDifference(base, other); | |
} else { | |
res = positiveMomentsDifference(other, base); | |
res.milliseconds = -res.milliseconds; | |
res.months = -res.months; | |
} | |
return res; | |
} | |
// TODO: remove 'name' arg after deprecation is removed | |
function createAdder(direction, name) { | |
return function (val, period) { | |
var dur, tmp; | |
//invert the arguments, but complain about it | |
if (period !== null && !isNaN(+period)) { | |
deprecateSimple( | |
name, | |
'moment().' + | |
name + | |
'(period, number) is deprecated. Please use moment().' + | |
name + | |
'(number, period). ' + | |
'See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.' | |
); | |
tmp = val; | |
val = period; | |
period = tmp; | |
} | |
dur = createDuration(val, period); | |
addSubtract(this, dur, direction); | |
return this; | |
}; | |
} | |
function addSubtract(mom, duration, isAdding, updateOffset) { | |
var milliseconds = duration._milliseconds, | |
days = absRound(duration._days), | |
months = absRound(duration._months); | |
if (!mom.isValid()) { | |
// No op | |
return; | |
} | |
updateOffset = updateOffset == null ? true : updateOffset; | |
if (months) { | |
setMonth(mom, get(mom, 'Month') + months * isAdding); | |
} | |
if (days) { | |
set$1(mom, 'Date', get(mom, 'Date') + days * isAdding); | |
} | |
if (milliseconds) { | |
mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding); | |
} | |
if (updateOffset) { | |
hooks.updateOffset(mom, days || months); | |
} | |
} | |
var add = createAdder(1, 'add'), | |
subtract = createAdder(-1, 'subtract'); | |
function isString(input) { | |
return typeof input === 'string' || input instanceof String; | |
} | |
// type MomentInput = Moment | Date | string | number | (number | string)[] | MomentInputObject | void; // null | undefined | |
function isMomentInput(input) { | |
return ( | |
isMoment(input) || | |
isDate(input) || | |
isString(input) || | |
isNumber(input) || | |
isNumberOrStringArray(input) || | |
isMomentInputObject(input) || | |
input === null || | |
input === undefined | |
); | |
} | |
function isMomentInputObject(input) { | |
var objectTest = isObject(input) && !isObjectEmpty(input), | |
propertyTest = false, | |
properties = [ | |
'years', | |
'year', | |
'y', | |
'months', | |
'month', | |
'M', | |
'days', | |
'day', | |
'd', | |
'dates', | |
'date', | |
'D', | |
'hours', | |
'hour', | |
'h', | |
'minutes', | |
'minute', | |
'm', | |
'seconds', | |
'second', | |
's', | |
'milliseconds', | |
'millisecond', | |
'ms', | |
], | |
i, | |
property; | |
for (i = 0; i < properties.length; i += 1) { | |
property = properties[i]; | |
propertyTest = propertyTest || hasOwnProp(input, property); | |
} | |
return objectTest && propertyTest; | |
} | |
function isNumberOrStringArray(input) { | |
var arrayTest = isArray(input), | |
dataTypeTest = false; | |
if (arrayTest) { | |
dataTypeTest = | |
input.filter(function (item) { | |
return !isNumber(item) && isString(input); | |
}).length === 0; | |
} | |
return arrayTest && dataTypeTest; | |
} | |
function isCalendarSpec(input) { | |
var objectTest = isObject(input) && !isObjectEmpty(input), | |
propertyTest = false, | |
properties = [ | |
'sameDay', | |
'nextDay', | |
'lastDay', | |
'nextWeek', | |
'lastWeek', | |
'sameElse', | |
], | |
i, | |
property; | |
for (i = 0; i < properties.length; i += 1) { | |
property = properties[i]; | |
propertyTest = propertyTest || hasOwnProp(input, property); | |
} | |
return objectTest && propertyTest; | |
} | |
function getCalendarFormat(myMoment, now) { | |
var diff = myMoment.diff(now, 'days', true); | |
return diff < -6 | |
? 'sameElse' | |
: diff < -1 | |
? 'lastWeek' | |
: diff < 0 | |
? 'lastDay' | |
: diff < 1 | |
? 'sameDay' | |
: diff < 2 | |
? 'nextDay' | |
: diff < 7 | |
? 'nextWeek' | |
: 'sameElse'; | |
} | |
function calendar$1(time, formats) { | |
// Support for single parameter, formats only overload to the calendar function | |
if (arguments.length === 1) { | |
if (isMomentInput(arguments[0])) { | |
time = arguments[0]; | |
formats = undefined; | |
} else if (isCalendarSpec(arguments[0])) { | |
formats = arguments[0]; | |
time = undefined; | |
} | |
} | |
// We want to compare the start of today, vs this. | |
// Getting start-of-today depends on whether we're local/utc/offset or not. | |
var now = time || createLocal(), | |
sod = cloneWithOffset(now, this).startOf('day'), | |
format = hooks.calendarFormat(this, sod) || 'sameElse', | |
output = | |
formats && | |
(isFunction(formats[format]) | |
? formats[format].call(this, now) | |
: formats[format]); | |
return this.format( | |
output || this.localeData().calendar(format, this, createLocal(now)) | |
); | |
} | |
function clone() { | |
return new Moment(this); | |
} | |
function isAfter(input, units) { | |
var localInput = isMoment(input) ? input : createLocal(input); | |
if (!(this.isValid() && localInput.isValid())) { | |
return false; | |
} | |
units = normalizeUnits(units) || 'millisecond'; | |
if (units === 'millisecond') { | |
return this.valueOf() > localInput.valueOf(); | |
} else { | |
return localInput.valueOf() < this.clone().startOf(units).valueOf(); | |
} | |
} | |
function isBefore(input, units) { | |
var localInput = isMoment(input) ? input : createLocal(input); | |
if (!(this.isValid() && localInput.isValid())) { | |
return false; | |
} | |
units = normalizeUnits(units) || 'millisecond'; | |
if (units === 'millisecond') { | |
return this.valueOf() < localInput.valueOf(); | |
} else { | |
return this.clone().endOf(units).valueOf() < localInput.valueOf(); | |
} | |
} | |
function isBetween(from, to, units, inclusivity) { | |
var localFrom = isMoment(from) ? from : createLocal(from), | |
localTo = isMoment(to) ? to : createLocal(to); | |
if (!(this.isValid() && localFrom.isValid() && localTo.isValid())) { | |
return false; | |
} | |
inclusivity = inclusivity || '()'; | |
return ( | |
(inclusivity[0] === '(' | |
? this.isAfter(localFrom, units) | |
: !this.isBefore(localFrom, units)) && | |
(inclusivity[1] === ')' | |
? this.isBefore(localTo, units) | |
: !this.isAfter(localTo, units)) | |
); | |
} | |
function isSame(input, units) { | |
var localInput = isMoment(input) ? input : createLocal(input), | |
inputMs; | |
if (!(this.isValid() && localInput.isValid())) { | |
return false; | |
} | |
units = normalizeUnits(units) || 'millisecond'; | |
if (units === 'millisecond') { | |
return this.valueOf() === localInput.valueOf(); | |
} else { | |
inputMs = localInput.valueOf(); | |
return ( | |
this.clone().startOf(units).valueOf() <= inputMs && | |
inputMs <= this.clone().endOf(units).valueOf() | |
); | |
} | |
} | |
function isSameOrAfter(input, units) { | |
return this.isSame(input, units) || this.isAfter(input, units); | |
} | |
function isSameOrBefore(input, units) { | |
return this.isSame(input, units) || this.isBefore(input, units); | |
} | |
function diff(input, units, asFloat) { | |
var that, zoneDelta, output; | |
if (!this.isValid()) { | |
return NaN; | |
} | |
that = cloneWithOffset(input, this); | |
if (!that.isValid()) { | |
return NaN; | |
} | |
zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4; | |
units = normalizeUnits(units); | |
switch (units) { | |
case 'year': | |
output = monthDiff(this, that) / 12; | |
break; | |
case 'month': | |
output = monthDiff(this, that); | |
break; | |
case 'quarter': | |
output = monthDiff(this, that) / 3; | |
break; | |
case 'second': | |
output = (this - that) / 1e3; | |
break; // 1000 | |
case 'minute': | |
output = (this - that) / 6e4; | |
break; // 1000 * 60 | |
case 'hour': | |
output = (this - that) / 36e5; | |
break; // 1000 * 60 * 60 | |
case 'day': | |
output = (this - that - zoneDelta) / 864e5; | |
break; // 1000 * 60 * 60 * 24, negate dst | |
case 'week': | |
output = (this - that - zoneDelta) / 6048e5; | |
break; // 1000 * 60 * 60 * 24 * 7, negate dst | |
default: | |
output = this - that; | |
} | |
return asFloat ? output : absFloor(output); | |
} | |
function monthDiff(a, b) { | |
if (a.date() < b.date()) { | |
// end-of-month calculations work correct when the start month has more | |
// days than the end month. | |
return -monthDiff(b, a); | |
} | |
// difference in months | |
var wholeMonthDiff = (b.year() - a.year()) * 12 + (b.month() - a.month()), | |
// b is in (anchor - 1 month, anchor + 1 month) | |
anchor = a.clone().add(wholeMonthDiff, 'months'), | |
anchor2, | |
adjust; | |
if (b - anchor < 0) { | |
anchor2 = a.clone().add(wholeMonthDiff - 1, 'months'); | |
// linear across the month | |
adjust = (b - anchor) / (anchor - anchor2); | |
} else { | |
anchor2 = a.clone().add(wholeMonthDiff + 1, 'months'); | |
// linear across the month | |
adjust = (b - anchor) / (anchor2 - anchor); | |
} | |
//check for negative zero, return zero if negative zero | |
return -(wholeMonthDiff + adjust) || 0; | |
} | |
hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ'; | |
hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]'; | |
function toString() { | |
return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ'); | |
} | |
function toISOString(keepOffset) { | |
if (!this.isValid()) { | |
return null; | |
} | |
var utc = keepOffset !== true, | |
m = utc ? this.clone().utc() : this; | |
if (m.year() < 0 || m.year() > 9999) { | |
return formatMoment( | |
m, | |
utc | |
? 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]' | |
: 'YYYYYY-MM-DD[T]HH:mm:ss.SSSZ' | |
); | |
} | |
if (isFunction(Date.prototype.toISOString)) { | |
// native implementation is ~50x faster, use it when we can | |
if (utc) { | |
return this.toDate().toISOString(); | |
} else { | |
return new Date(this.valueOf() + this.utcOffset() * 60 * 1000) | |
.toISOString() | |
.replace('Z', formatMoment(m, 'Z')); | |
} | |
} | |
return formatMoment( | |
m, | |
utc ? 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYY-MM-DD[T]HH:mm:ss.SSSZ' | |
); | |
} | |
/** | |
* Return a human readable representation of a moment that can | |
* also be evaluated to get a new moment which is the same | |
* | |
* @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects | |
*/ | |
function inspect() { | |
if (!this.isValid()) { | |
return 'moment.invalid(/* ' + this._i + ' */)'; | |
} | |
var func = 'moment', | |
zone = '', | |
prefix, | |
year, | |
datetime, | |
suffix; | |
if (!this.isLocal()) { | |
func = this.utcOffset() === 0 ? 'moment.utc' : 'moment.parseZone'; | |
zone = 'Z'; | |
} | |
prefix = '[' + func + '("]'; | |
year = 0 <= this.year() && this.year() <= 9999 ? 'YYYY' : 'YYYYYY'; | |
datetime = '-MM-DD[T]HH:mm:ss.SSS'; | |
suffix = zone + '[")]'; | |
return this.format(prefix + year + datetime + suffix); | |
} | |
function format(inputString) { | |
if (!inputString) { | |
inputString = this.isUtc() | |
? hooks.defaultFormatUtc | |
: hooks.defaultFormat; | |
} | |
var output = formatMoment(this, inputString); | |
return this.localeData().postformat(output); | |
} | |
function from(time, withoutSuffix) { | |
if ( | |
this.isValid() && | |
((isMoment(time) && time.isValid()) || createLocal(time).isValid()) | |
) { | |
return createDuration({ to: this, from: time }) | |
.locale(this.locale()) | |
.humanize(!withoutSuffix); | |
} else { | |
return this.localeData().invalidDate(); | |
} | |
} | |
function fromNow(withoutSuffix) { | |
return this.from(createLocal(), withoutSuffix); | |
} | |
function to(time, withoutSuffix) { | |
if ( | |
this.isValid() && | |
((isMoment(time) && time.isValid()) || createLocal(time).isValid()) | |
) { | |
return createDuration({ from: this, to: time }) | |
.locale(this.locale()) | |
.humanize(!withoutSuffix); | |
} else { | |
return this.localeData().invalidDate(); | |
} | |
} | |
function toNow(withoutSuffix) { | |
return this.to(createLocal(), withoutSuffix); | |
} | |
// If passed a locale key, it will set the locale for this | |
// instance. Otherwise, it will return the locale configuration | |
// variables for this instance. | |
function locale(key) { | |
var newLocaleData; | |
if (key === undefined) { | |
return this._locale._abbr; | |
} else { | |
newLocaleData = getLocale(key); | |
if (newLocaleData != null) { | |
this._locale = newLocaleData; | |
} | |
return this; | |
} | |
} | |
var lang = deprecate( | |
'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.', | |
function (key) { | |
if (key === undefined) { | |
return this.localeData(); | |
} else { | |
return this.locale(key); | |
} | |
} | |
); | |
function localeData() { | |
return this._locale; | |
} | |
var MS_PER_SECOND = 1000, | |
MS_PER_MINUTE = 60 * MS_PER_SECOND, | |
MS_PER_HOUR = 60 * MS_PER_MINUTE, | |
MS_PER_400_YEARS = (365 * 400 + 97) * 24 * MS_PER_HOUR; | |
// actual modulo - handles negative numbers (for dates before 1970): | |
function mod$1(dividend, divisor) { | |
return ((dividend % divisor) + divisor) % divisor; | |
} | |
function localStartOfDate(y, m, d) { | |
// the date constructor remaps years 0-99 to 1900-1999 | |
if (y < 100 && y >= 0) { | |
// preserve leap years using a full 400 year cycle, then reset | |
return new Date(y + 400, m, d) - MS_PER_400_YEARS; | |
} else { | |
return new Date(y, m, d).valueOf(); | |
} | |
} | |
function utcStartOfDate(y, m, d) { | |
// Date.UTC remaps years 0-99 to 1900-1999 | |
if (y < 100 && y >= 0) { | |
// preserve leap years using a full 400 year cycle, then reset | |
return Date.UTC(y + 400, m, d) - MS_PER_400_YEARS; | |
} else { | |
return Date.UTC(y, m, d); | |
} | |
} | |
function startOf(units) { | |
var time, startOfDate; | |
units = normalizeUnits(units); | |
if (units === undefined || units === 'millisecond' || !this.isValid()) { | |
return this; | |
} | |
startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate; | |
switch (units) { | |
case 'year': | |
time = startOfDate(this.year(), 0, 1); | |
break; | |
case 'quarter': | |
time = startOfDate( | |
this.year(), | |
this.month() - (this.month() % 3), | |
1 | |
); | |
break; | |
case 'month': | |
time = startOfDate(this.year(), this.month(), 1); | |
break; | |
case 'week': | |
time = startOfDate( | |
this.year(), | |
this.month(), | |
this.date() - this.weekday() | |
); | |
break; | |
case 'isoWeek': | |
time = startOfDate( | |
this.year(), | |
this.month(), | |
this.date() - (this.isoWeekday() - 1) | |
); | |
break; | |
case 'day': | |
case 'date': | |
time = startOfDate(this.year(), this.month(), this.date()); | |
break; | |
case 'hour': | |
time = this._d.valueOf(); | |
time -= mod$1( | |
time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE), | |
MS_PER_HOUR | |
); | |
break; | |
case 'minute': | |
time = this._d.valueOf(); | |
time -= mod$1(time, MS_PER_MINUTE); | |
break; | |
case 'second': | |
time = this._d.valueOf(); | |
time -= mod$1(time, MS_PER_SECOND); | |
break; | |
} | |
this._d.setTime(time); | |
hooks.updateOffset(this, true); | |
return this; | |
} | |
function endOf(units) { | |
var time, startOfDate; | |
units = normalizeUnits(units); | |
if (units === undefined || units === 'millisecond' || !this.isValid()) { | |
return this; | |
} | |
startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate; | |
switch (units) { | |
case 'year': | |
time = startOfDate(this.year() + 1, 0, 1) - 1; | |
break; | |
case 'quarter': | |
time = | |
startOfDate( | |
this.year(), | |
this.month() - (this.month() % 3) + 3, | |
1 | |
) - 1; | |
break; | |
case 'month': | |
time = startOfDate(this.year(), this.month() + 1, 1) - 1; | |
break; | |
case 'week': | |
time = | |
startOfDate( | |
this.year(), | |
this.month(), | |
this.date() - this.weekday() + 7 | |
) - 1; | |
break; | |
case 'isoWeek': | |
time = | |
startOfDate( | |
this.year(), | |
this.month(), | |
this.date() - (this.isoWeekday() - 1) + 7 | |
) - 1; | |
break; | |
case 'day': | |
case 'date': | |
time = startOfDate(this.year(), this.month(), this.date() + 1) - 1; | |
break; | |
case 'hour': | |
time = this._d.valueOf(); | |
time += | |
MS_PER_HOUR - | |
mod$1( | |
time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE), | |
MS_PER_HOUR | |
) - | |
1; | |
break; | |
case 'minute': | |
time = this._d.valueOf(); | |
time += MS_PER_MINUTE - mod$1(time, MS_PER_MINUTE) - 1; | |
break; | |
case 'second': | |
time = this._d.valueOf(); | |
time += MS_PER_SECOND - mod$1(time, MS_PER_SECOND) - 1; | |
break; | |
} | |
this._d.setTime(time); | |
hooks.updateOffset(this, true); | |
return this; | |
} | |
function valueOf() { | |
return this._d.valueOf() - (this._offset || 0) * 60000; | |
} | |
function unix() { | |
return Math.floor(this.valueOf() / 1000); | |
} | |
function toDate() { | |
return new Date(this.valueOf()); | |
} | |
function toArray() { | |
var m = this; | |
return [ | |
m.year(), | |
m.month(), | |
m.date(), | |
m.hour(), | |
m.minute(), | |
m.second(), | |
m.millisecond(), | |
]; | |
} | |
function toObject() { | |
var m = this; | |
return { | |
years: m.year(), | |
months: m.month(), | |
date: m.date(), | |
hours: m.hours(), | |
minutes: m.minutes(), | |
seconds: m.seconds(), | |
milliseconds: m.milliseconds(), | |
}; | |
} | |
function toJSON() { | |
// new Date(NaN).toJSON() === null | |
return this.isValid() ? this.toISOString() : null; | |
} | |
function isValid$2() { | |
return isValid(this); | |
} | |
function parsingFlags() { | |
return extend({}, getParsingFlags(this)); | |
} | |
function invalidAt() { | |
return getParsingFlags(this).overflow; | |
} | |
function creationData() { | |
return { | |
input: this._i, | |
format: this._f, | |
locale: this._locale, | |
isUTC: this._isUTC, | |
strict: this._strict, | |
}; | |
} | |
addFormatToken('N', 0, 0, 'eraAbbr'); | |
addFormatToken('NN', 0, 0, 'eraAbbr'); | |
addFormatToken('NNN', 0, 0, 'eraAbbr'); | |
addFormatToken('NNNN', 0, 0, 'eraName'); | |
addFormatToken('NNNNN', 0, 0, 'eraNarrow'); | |
addFormatToken('y', ['y', 1], 'yo', 'eraYear'); | |
addFormatToken('y', ['yy', 2], 0, 'eraYear'); | |
addFormatToken('y', ['yyy', 3], 0, 'eraYear'); | |
addFormatToken('y', ['yyyy', 4], 0, 'eraYear'); | |
addRegexToken('N', matchEraAbbr); | |
addRegexToken('NN', matchEraAbbr); | |
addRegexToken('NNN', matchEraAbbr); | |
addRegexToken('NNNN', matchEraName); | |
addRegexToken('NNNNN', matchEraNarrow); | |
addParseToken(['N', 'NN', 'NNN', 'NNNN', 'NNNNN'], function ( | |
input, | |
array, | |
config, | |
token | |
) { | |
var era = config._locale.erasParse(input, token, config._strict); | |
if (era) { | |
getParsingFlags(config).era = era; | |
} else { | |
getParsingFlags(config).invalidEra = input; | |
} | |
}); | |
addRegexToken('y', matchUnsigned); | |
addRegexToken('yy', matchUnsigned); | |
addRegexToken('yyy', matchUnsigned); | |
addRegexToken('yyyy', matchUnsigned); | |
addRegexToken('yo', matchEraYearOrdinal); | |
addParseToken(['y', 'yy', 'yyy', 'yyyy'], YEAR); | |
addParseToken(['yo'], function (input, array, config, token) { | |
var match; | |
if (config._locale._eraYearOrdinalRegex) { | |
match = input.match(config._locale._eraYearOrdinalRegex); | |
} | |
if (config._locale.eraYearOrdinalParse) { | |
array[YEAR] = config._locale.eraYearOrdinalParse(input, match); | |
} else { | |
array[YEAR] = parseInt(input, 10); | |
} | |
}); | |
function localeEras(m, format) { | |
var i, | |
l, | |
date, | |
eras = this._eras || getLocale('en')._eras; | |
for (i = 0, l = eras.length; i < l; ++i) { | |
switch (typeof eras[i].since) { | |
case 'string': | |
// truncate time | |
date = hooks(eras[i].since).startOf('day'); | |
eras[i].since = date.valueOf(); | |
break; | |
} | |
switch (typeof eras[i].until) { | |
case 'undefined': | |
eras[i].until = +Infinity; | |
break; | |
case 'string': | |
// truncate time | |
date = hooks(eras[i].until).startOf('day').valueOf(); | |
eras[i].until = date.valueOf(); | |
break; | |
} | |
} | |
return eras; | |
} | |
function localeErasParse(eraName, format, strict) { | |
var i, | |
l, | |
eras = this.eras(), | |
name, | |
abbr, | |
narrow; | |
eraName = eraName.toUpperCase(); | |
for (i = 0, l = eras.length; i < l; ++i) { | |
name = eras[i].name.toUpperCase(); | |
abbr = eras[i].abbr.toUpperCase(); | |
narrow = eras[i].narrow.toUpperCase(); | |
if (strict) { | |
switch (format) { | |
case 'N': | |
case 'NN': | |
case 'NNN': | |
if (abbr === eraName) { | |
return eras[i]; | |
} | |
break; | |
case 'NNNN': | |
if (name === eraName) { | |
return eras[i]; | |
} | |
break; | |
case 'NNNNN': | |
if (narrow === eraName) { | |
return eras[i]; | |
} | |
break; | |
} | |
} else if ([name, abbr, narrow].indexOf(eraName) >= 0) { | |
return eras[i]; | |
} | |
} | |
} | |
function localeErasConvertYear(era, year) { | |
var dir = era.since <= era.until ? +1 : -1; | |
if (year === undefined) { | |
return hooks(era.since).year(); | |
} else { | |
return hooks(era.since).year() + (year - era.offset) * dir; | |
} | |
} | |
function getEraName() { | |
var i, | |
l, | |
val, | |
eras = this.localeData().eras(); | |
for (i = 0, l = eras.length; i < l; ++i) { | |
// truncate time | |
val = this.startOf('day').valueOf(); | |
if (eras[i].since <= val && val <= eras[i].until) { | |
return eras[i].name; | |
} | |
if (eras[i].until <= val && val <= eras[i].since) { | |
return eras[i].name; | |
} | |
} | |
return ''; | |
} | |
function getEraNarrow() { | |
var i, | |
l, | |
val, | |
eras = this.localeData().eras(); | |
for (i = 0, l = eras.length; i < l; ++i) { | |
// truncate time | |
val = this.startOf('day').valueOf(); | |
if (eras[i].since <= val && val <= eras[i].until) { | |
return eras[i].narrow; | |
} | |
if (eras[i].until <= val && val <= eras[i].since) { | |
return eras[i].narrow; | |
} | |
} | |
return ''; | |
} | |
function getEraAbbr() { | |
var i, | |
l, | |
val, | |
eras = this.localeData().eras(); | |
for (i = 0, l = eras.length; i < l; ++i) { | |
// truncate time | |
val = this.startOf('day').valueOf(); | |
if (eras[i].since <= val && val <= eras[i].until) { | |
return eras[i].abbr; | |
} | |
if (eras[i].until <= val && val <= eras[i].since) { | |
return eras[i].abbr; | |
} | |
} | |
return ''; | |
} | |
function getEraYear() { | |
var i, | |
l, | |
dir, | |
val, | |
eras = this.localeData().eras(); | |
for (i = 0, l = eras.length; i < l; ++i) { | |
dir = eras[i].since <= eras[i].until ? +1 : -1; | |
// truncate time | |
val = this.startOf('day').valueOf(); | |
if ( | |
(eras[i].since <= val && val <= eras[i].until) || | |
(eras[i].until <= val && val <= eras[i].since) | |
) { | |
return ( | |
(this.year() - hooks(eras[i].since).year()) * dir + | |
eras[i].offset | |
); | |
} | |
} | |
return this.year(); | |
} | |
function erasNameRegex(isStrict) { | |
if (!hasOwnProp(this, '_erasNameRegex')) { | |
computeErasParse.call(this); | |
} | |
return isStrict ? this._erasNameRegex : this._erasRegex; | |
} | |
function erasAbbrRegex(isStrict) { | |
if (!hasOwnProp(this, '_erasAbbrRegex')) { | |
computeErasParse.call(this); | |
} | |
return isStrict ? this._erasAbbrRegex : this._erasRegex; | |
} | |
function erasNarrowRegex(isStrict) { | |
if (!hasOwnProp(this, '_erasNarrowRegex')) { | |
computeErasParse.call(this); | |
} | |
return isStrict ? this._erasNarrowRegex : this._erasRegex; | |
} | |
function matchEraAbbr(isStrict, locale) { | |
return locale.erasAbbrRegex(isStrict); | |
} | |
function matchEraName(isStrict, locale) { | |
return locale.erasNameRegex(isStrict); | |
} | |
function matchEraNarrow(isStrict, locale) { | |
return locale.erasNarrowRegex(isStrict); | |
} | |
function matchEraYearOrdinal(isStrict, locale) { | |
return locale._eraYearOrdinalRegex || matchUnsigned; | |
} | |
function computeErasParse() { | |
var abbrPieces = [], | |
namePieces = [], | |
narrowPieces = [], | |
mixedPieces = [], | |
i, | |
l, | |
eras = this.eras(); | |
for (i = 0, l = eras.length; i < l; ++i) { | |
namePieces.push(regexEscape(eras[i].name)); | |
abbrPieces.push(regexEscape(eras[i].abbr)); | |
narrowPieces.push(regexEscape(eras[i].narrow)); | |
mixedPieces.push(regexEscape(eras[i].name)); | |
mixedPieces.push(regexEscape(eras[i].abbr)); | |
mixedPieces.push(regexEscape(eras[i].narrow)); | |
} | |
this._erasRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i'); | |
this._erasNameRegex = new RegExp('^(' + namePieces.join('|') + ')', 'i'); | |
this._erasAbbrRegex = new RegExp('^(' + abbrPieces.join('|') + ')', 'i'); | |
this._erasNarrowRegex = new RegExp( | |
'^(' + narrowPieces.join('|') + ')', | |
'i' | |
); | |
} | |
// FORMATTING | |
addFormatToken(0, ['gg', 2], 0, function () { | |
return this.weekYear() % 100; | |
}); | |
addFormatToken(0, ['GG', 2], 0, function () { | |
return this.isoWeekYear() % 100; | |
}); | |
function addWeekYearFormatToken(token, getter) { | |
addFormatToken(0, [token, token.length], 0, getter); | |
} | |
addWeekYearFormatToken('gggg', 'weekYear'); | |
addWeekYearFormatToken('ggggg', 'weekYear'); | |
addWeekYearFormatToken('GGGG', 'isoWeekYear'); | |
addWeekYearFormatToken('GGGGG', 'isoWeekYear'); | |
// ALIASES | |
addUnitAlias('weekYear', 'gg'); | |
addUnitAlias('isoWeekYear', 'GG'); | |
// PRIORITY | |
addUnitPriority('weekYear', 1); | |
addUnitPriority('isoWeekYear', 1); | |
// PARSING | |
addRegexToken('G', matchSigned); | |
addRegexToken('g', matchSigned); | |
addRegexToken('GG', match1to2, match2); | |
addRegexToken('gg', match1to2, match2); | |
addRegexToken('GGGG', match1to4, match4); | |
addRegexToken('gggg', match1to4, match4); | |
addRegexToken('GGGGG', match1to6, match6); | |
addRegexToken('ggggg', match1to6, match6); | |
addWeekParseToken(['gggg', 'ggggg', 'GGGG', 'GGGGG'], function ( | |
input, | |
week, | |
config, | |
token | |
) { | |
week[token.substr(0, 2)] = toInt(input); | |
}); | |
addWeekParseToken(['gg', 'GG'], function (input, week, config, token) { | |
week[token] = hooks.parseTwoDigitYear(input); | |
}); | |
// MOMENTS | |
function getSetWeekYear(input) { | |
return getSetWeekYearHelper.call( | |
this, | |
input, | |
this.week(), | |
this.weekday(), | |
this.localeData()._week.dow, | |
this.localeData()._week.doy | |
); | |
} | |
function getSetISOWeekYear(input) { | |
return getSetWeekYearHelper.call( | |
this, | |
input, | |
this.isoWeek(), | |
this.isoWeekday(), | |
1, | |
4 | |
); | |
} | |
function getISOWeeksInYear() { | |
return weeksInYear(this.year(), 1, 4); | |
} | |
function getISOWeeksInISOWeekYear() { | |
return weeksInYear(this.isoWeekYear(), 1, 4); | |
} | |
function getWeeksInYear() { | |
var weekInfo = this.localeData()._week; | |
return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy); | |
} | |
function getWeeksInWeekYear() { | |
var weekInfo = this.localeData()._week; | |
return weeksInYear(this.weekYear(), weekInfo.dow, weekInfo.doy); | |
} | |
function getSetWeekYearHelper(input, week, weekday, dow, doy) { | |
var weeksTarget; | |
if (input == null) { | |
return weekOfYear(this, dow, doy).year; | |
} else { | |
weeksTarget = weeksInYear(input, dow, doy); | |
if (week > weeksTarget) { | |
week = weeksTarget; | |
} | |
return setWeekAll.call(this, input, week, weekday, dow, doy); | |
} | |
} | |
function setWeekAll(weekYear, week, weekday, dow, doy) { | |
var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy), | |
date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear); | |
this.year(date.getUTCFullYear()); | |
this.month(date.getUTCMonth()); | |
this.date(date.getUTCDate()); | |
return this; | |
} | |
// FORMATTING | |
addFormatToken('Q', 0, 'Qo', 'quarter'); | |
// ALIASES | |
addUnitAlias('quarter', 'Q'); | |
// PRIORITY | |
addUnitPriority('quarter', 7); | |
// PARSING | |
addRegexToken('Q', match1); | |
addParseToken('Q', function (input, array) { | |
array[MONTH] = (toInt(input) - 1) * 3; | |
}); | |
// MOMENTS | |
function getSetQuarter(input) { | |
return input == null | |
? Math.ceil((this.month() + 1) / 3) | |
: this.month((input - 1) * 3 + (this.month() % 3)); | |
} | |
// FORMATTING | |
addFormatToken('D', ['DD', 2], 'Do', 'date'); | |
// ALIASES | |
addUnitAlias('date', 'D'); | |
// PRIORITY | |
addUnitPriority('date', 9); | |
// PARSING | |
addRegexToken('D', match1to2); | |
addRegexToken('DD', match1to2, match2); | |
addRegexToken('Do', function (isStrict, locale) { | |
// TODO: Remove "ordinalParse" fallback in next major release. | |
return isStrict | |
? locale._dayOfMonthOrdinalParse || locale._ordinalParse | |
: locale._dayOfMonthOrdinalParseLenient; | |
}); | |
addParseToken(['D', 'DD'], DATE); | |
addParseToken('Do', function (input, array) { | |
array[DATE] = toInt(input.match(match1to2)[0]); | |
}); | |
// MOMENTS | |
var getSetDayOfMonth = makeGetSet('Date', true); | |
// FORMATTING | |
addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear'); | |
// ALIASES | |
addUnitAlias('dayOfYear', 'DDD'); | |
// PRIORITY | |
addUnitPriority('dayOfYear', 4); | |
// PARSING | |
addRegexToken('DDD', match1to3); | |
addRegexToken('DDDD', match3); | |
addParseToken(['DDD', 'DDDD'], function (input, array, config) { | |
config._dayOfYear = toInt(input); | |
}); | |
// HELPERS | |
// MOMENTS | |
function getSetDayOfYear(input) { | |
var dayOfYear = | |
Math.round( | |
(this.clone().startOf('day') - this.clone().startOf('year')) / 864e5 | |
) + 1; | |
return input == null ? dayOfYear : this.add(input - dayOfYear, 'd'); | |
} | |
// FORMATTING | |
addFormatToken('m', ['mm', 2], 0, 'minute'); | |
// ALIASES | |
addUnitAlias('minute', 'm'); | |
// PRIORITY | |
addUnitPriority('minute', 14); | |
// PARSING | |
addRegexToken('m', match1to2); | |
addRegexToken('mm', match1to2, match2); | |
addParseToken(['m', 'mm'], MINUTE); | |
// MOMENTS | |
var getSetMinute = makeGetSet('Minutes', false); | |
// FORMATTING | |
addFormatToken('s', ['ss', 2], 0, 'second'); | |
// ALIASES | |
addUnitAlias('second', 's'); | |
// PRIORITY | |
addUnitPriority('second', 15); | |
// PARSING | |
addRegexToken('s', match1to2); | |
addRegexToken('ss', match1to2, match2); | |
addParseToken(['s', 'ss'], SECOND); | |
// MOMENTS | |
var getSetSecond = makeGetSet('Seconds', false); | |
// FORMATTING | |
addFormatToken('S', 0, 0, function () { | |
return ~~(this.millisecond() / 100); | |
}); | |
addFormatToken(0, ['SS', 2], 0, function () { | |
return ~~(this.millisecond() / 10); | |
}); | |
addFormatToken(0, ['SSS', 3], 0, 'millisecond'); | |
addFormatToken(0, ['SSSS', 4], 0, function () { | |
return this.millisecond() * 10; | |
}); | |
addFormatToken(0, ['SSSSS', 5], 0, function () { | |
return this.millisecond() * 100; | |
}); | |
addFormatToken(0, ['SSSSSS', 6], 0, function () { | |
return this.millisecond() * 1000; | |
}); | |
addFormatToken(0, ['SSSSSSS', 7], 0, function () { | |
return this.millisecond() * 10000; | |
}); | |
addFormatToken(0, ['SSSSSSSS', 8], 0, function () { | |
return this.millisecond() * 100000; | |
}); | |
addFormatToken(0, ['SSSSSSSSS', 9], 0, function () { | |
return this.millisecond() * 1000000; | |
}); | |
// ALIASES | |
addUnitAlias('millisecond', 'ms'); | |
// PRIORITY | |
addUnitPriority('millisecond', 16); | |
// PARSING | |
addRegexToken('S', match1to3, match1); | |
addRegexToken('SS', match1to3, match2); | |
addRegexToken('SSS', match1to3, match3); | |
var token, getSetMillisecond; | |
for (token = 'SSSS'; token.length <= 9; token += 'S') { | |
addRegexToken(token, matchUnsigned); | |
} | |
function parseMs(input, array) { | |
array[MILLISECOND] = toInt(('0.' + input) * 1000); | |
} | |
for (token = 'S'; token.length <= 9; token += 'S') { | |
addParseToken(token, parseMs); | |
} | |
getSetMillisecond = makeGetSet('Milliseconds', false); | |
// FORMATTING | |
addFormatToken('z', 0, 0, 'zoneAbbr'); | |
addFormatToken('zz', 0, 0, 'zoneName'); | |
// MOMENTS | |
function getZoneAbbr() { | |
return this._isUTC ? 'UTC' : ''; | |
} | |
function getZoneName() { | |
return this._isUTC ? 'Coordinated Universal Time' : ''; | |
} | |
var proto = Moment.prototype; | |
proto.add = add; | |
proto.calendar = calendar$1; | |
proto.clone = clone; | |
proto.diff = diff; | |
proto.endOf = endOf; | |
proto.format = format; | |
proto.from = from; | |
proto.fromNow = fromNow; | |
proto.to = to; | |
proto.toNow = toNow; | |
proto.get = stringGet; | |
proto.invalidAt = invalidAt; | |
proto.isAfter = isAfter; | |
proto.isBefore = isBefore; | |
proto.isBetween = isBetween; | |
proto.isSame = isSame; | |
proto.isSameOrAfter = isSameOrAfter; | |
proto.isSameOrBefore = isSameOrBefore; | |
proto.isValid = isValid$2; | |
proto.lang = lang; | |
proto.locale = locale; | |
proto.localeData = localeData; | |
proto.max = prototypeMax; | |
proto.min = prototypeMin; | |
proto.parsingFlags = parsingFlags; | |
proto.set = stringSet; | |
proto.startOf = startOf; | |
proto.subtract = subtract; | |
proto.toArray = toArray; | |
proto.toObject = toObject; | |
proto.toDate = toDate; | |
proto.toISOString = toISOString; | |
proto.inspect = inspect; | |
if (typeof Symbol !== 'undefined' && Symbol.for != null) { | |
proto[Symbol.for('nodejs.util.inspect.custom')] = function () { | |
return 'Moment<' + this.format() + '>'; | |
}; | |
} | |
proto.toJSON = toJSON; | |
proto.toString = toString; | |
proto.unix = unix; | |
proto.valueOf = valueOf; | |
proto.creationData = creationData; | |
proto.eraName = getEraName; | |
proto.eraNarrow = getEraNarrow; | |
proto.eraAbbr = getEraAbbr; | |
proto.eraYear = getEraYear; | |
proto.year = getSetYear; | |
proto.isLeapYear = getIsLeapYear; | |
proto.weekYear = getSetWeekYear; | |
proto.isoWeekYear = getSetISOWeekYear; | |
proto.quarter = proto.quarters = getSetQuarter; | |
proto.month = getSetMonth; | |
proto.daysInMonth = getDaysInMonth; | |
proto.week = proto.weeks = getSetWeek; | |
proto.isoWeek = proto.isoWeeks = getSetISOWeek; | |
proto.weeksInYear = getWeeksInYear; | |
proto.weeksInWeekYear = getWeeksInWeekYear; | |
proto.isoWeeksInYear = getISOWeeksInYear; | |
proto.isoWeeksInISOWeekYear = getISOWeeksInISOWeekYear; | |
proto.date = getSetDayOfMonth; | |
proto.day = proto.days = getSetDayOfWeek; | |
proto.weekday = getSetLocaleDayOfWeek; | |
proto.isoWeekday = getSetISODayOfWeek; | |
proto.dayOfYear = getSetDayOfYear; | |
proto.hour = proto.hours = getSetHour; | |
proto.minute = proto.minutes = getSetMinute; | |
proto.second = proto.seconds = getSetSecond; | |
proto.millisecond = proto.milliseconds = getSetMillisecond; | |
proto.utcOffset = getSetOffset; | |
proto.utc = setOffsetToUTC; | |
proto.local = setOffsetToLocal; | |
proto.parseZone = setOffsetToParsedOffset; | |
proto.hasAlignedHourOffset = hasAlignedHourOffset; | |
proto.isDST = isDaylightSavingTime; | |
proto.isLocal = isLocal; | |
proto.isUtcOffset = isUtcOffset; | |
proto.isUtc = isUtc; | |
proto.isUTC = isUtc; | |
proto.zoneAbbr = getZoneAbbr; | |
proto.zoneName = getZoneName; | |
proto.dates = deprecate( | |
'dates accessor is deprecated. Use date instead.', | |
getSetDayOfMonth | |
); | |
proto.months = deprecate( | |
'months accessor is deprecated. Use month instead', | |
getSetMonth | |
); | |
proto.years = deprecate( | |
'years accessor is deprecated. Use year instead', | |
getSetYear | |
); | |
proto.zone = deprecate( | |
'moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/', | |
getSetZone | |
); | |
proto.isDSTShifted = deprecate( | |
'isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information', | |
isDaylightSavingTimeShifted | |
); | |
function createUnix(input) { | |
return createLocal(input * 1000); | |
} | |
function createInZone() { | |
return createLocal.apply(null, arguments).parseZone(); | |
} | |
function preParsePostFormat(string) { | |
return string; | |
} | |
var proto$1 = Locale.prototype; | |
proto$1.calendar = calendar; | |
proto$1.longDateFormat = longDateFormat; | |
proto$1.invalidDate = invalidDate; | |
proto$1.ordinal = ordinal; | |
proto$1.preparse = preParsePostFormat; | |
proto$1.postformat = preParsePostFormat; | |
proto$1.relativeTime = relativeTime; | |
proto$1.pastFuture = pastFuture; | |
proto$1.set = set; | |
proto$1.eras = localeEras; | |
proto$1.erasParse = localeErasParse; | |
proto$1.erasConvertYear = localeErasConvertYear; | |
proto$1.erasAbbrRegex = erasAbbrRegex; | |
proto$1.erasNameRegex = erasNameRegex; | |
proto$1.erasNarrowRegex = erasNarrowRegex; | |
proto$1.months = localeMonths; | |
proto$1.monthsShort = localeMonthsShort; | |
proto$1.monthsParse = localeMonthsParse; | |
proto$1.monthsRegex = monthsRegex; | |
proto$1.monthsShortRegex = monthsShortRegex; | |
proto$1.week = localeWeek; | |
proto$1.firstDayOfYear = localeFirstDayOfYear; | |
proto$1.firstDayOfWeek = localeFirstDayOfWeek; | |
proto$1.weekdays = localeWeekdays; | |
proto$1.weekdaysMin = localeWeekdaysMin; | |
proto$1.weekdaysShort = localeWeekdaysShort; | |
proto$1.weekdaysParse = localeWeekdaysParse; | |
proto$1.weekdaysRegex = weekdaysRegex; | |
proto$1.weekdaysShortRegex = weekdaysShortRegex; | |
proto$1.weekdaysMinRegex = weekdaysMinRegex; | |
proto$1.isPM = localeIsPM; | |
proto$1.meridiem = localeMeridiem; | |
function get$1(format, index, field, setter) { | |
var locale = getLocale(), | |
utc = createUTC().set(setter, index); | |
return locale[field](utc, format); | |
} | |
function listMonthsImpl(format, index, field) { | |
if (isNumber(format)) { | |
index = format; | |
format = undefined; | |
} | |
format = format || ''; | |
if (index != null) { | |
return get$1(format, index, field, 'month'); | |
} | |
var i, | |
out = []; | |
for (i = 0; i < 12; i++) { | |
out[i] = get$1(format, i, field, 'month'); | |
} | |
return out; | |
} | |
// () | |
// (5) | |
// (fmt, 5) | |
// (fmt) | |
// (true) | |
// (true, 5) | |
// (true, fmt, 5) | |
// (true, fmt) | |
function listWeekdaysImpl(localeSorted, format, index, field) { | |
if (typeof localeSorted === 'boolean') { | |
if (isNumber(format)) { | |
index = format; | |
format = undefined; | |
} | |
format = format || ''; | |
} else { | |
format = localeSorted; | |
index = format; | |
localeSorted = false; | |
if (isNumber(format)) { | |
index = format; | |
format = undefined; | |
} | |
format = format || ''; | |
} | |
var locale = getLocale(), | |
shift = localeSorted ? locale._week.dow : 0, | |
i, | |
out = []; | |
if (index != null) { | |
return get$1(format, (index + shift) % 7, field, 'day'); | |
} | |
for (i = 0; i < 7; i++) { | |
out[i] = get$1(format, (i + shift) % 7, field, 'day'); | |
} | |
return out; | |
} | |
function listMonths(format, index) { | |
return listMonthsImpl(format, index, 'months'); | |
} | |
function listMonthsShort(format, index) { | |
return listMonthsImpl(format, index, 'monthsShort'); | |
} | |
function listWeekdays(localeSorted, format, index) { | |
return listWeekdaysImpl(localeSorted, format, index, 'weekdays'); | |
} | |
function listWeekdaysShort(localeSorted, format, index) { | |
return listWeekdaysImpl(localeSorted, format, index, 'weekdaysShort'); | |
} | |
function listWeekdaysMin(localeSorted, format, index) { | |
return listWeekdaysImpl(localeSorted, format, index, 'weekdaysMin'); | |
} | |
getSetGlobalLocale('en', { | |
eras: [ | |
{ | |
since: '0001-01-01', | |
until: +Infinity, | |
offset: 1, | |
name: 'Anno Domini', | |
narrow: 'AD', | |
abbr: 'AD', | |
}, | |
{ | |
since: '0000-12-31', | |
until: -Infinity, | |
offset: 1, | |
name: 'Before Christ', | |
narrow: 'BC', | |
abbr: 'BC', | |
}, | |
], | |
dayOfMonthOrdinalParse: /\d{1,2}(th|st|nd|rd)/, | |
ordinal: function (number) { | |
var b = number % 10, | |
output = | |
toInt((number % 100) / 10) === 1 | |
? 'th' | |
: b === 1 | |
? 'st' | |
: b === 2 | |
? 'nd' | |
: b === 3 | |
? 'rd' | |
: 'th'; | |
return number + output; | |
}, | |
}); | |
// Side effect imports | |
hooks.lang = deprecate( | |
'moment.lang is deprecated. Use moment.locale instead.', | |
getSetGlobalLocale | |
); | |
hooks.langData = deprecate( | |
'moment.langData is deprecated. Use moment.localeData instead.', | |
getLocale | |
); | |
var mathAbs = Math.abs; | |
function abs() { | |
var data = this._data; | |
this._milliseconds = mathAbs(this._milliseconds); | |
this._days = mathAbs(this._days); | |
this._months = mathAbs(this._months); | |
data.milliseconds = mathAbs(data.milliseconds); | |
data.seconds = mathAbs(data.seconds); | |
data.minutes = mathAbs(data.minutes); | |
data.hours = mathAbs(data.hours); | |
data.months = mathAbs(data.months); | |
data.years = mathAbs(data.years); | |
return this; | |
} | |
function addSubtract$1(duration, input, value, direction) { | |
var other = createDuration(input, value); | |
duration._milliseconds += direction * other._milliseconds; | |
duration._days += direction * other._days; | |
duration._months += direction * other._months; | |
return duration._bubble(); | |
} | |
// supports only 2.0-style add(1, 's') or add(duration) | |
function add$1(input, value) { | |
return addSubtract$1(this, input, value, 1); | |
} | |
// supports only 2.0-style subtract(1, 's') or subtract(duration) | |
function subtract$1(input, value) { | |
return addSubtract$1(this, input, value, -1); | |
} | |
function absCeil(number) { | |
if (number < 0) { | |
return Math.floor(number); | |
} else { | |
return Math.ceil(number); | |
} | |
} | |
function bubble() { | |
var milliseconds = this._milliseconds, | |
days = this._days, | |
months = this._months, | |
data = this._data, | |
seconds, | |
minutes, | |
hours, | |
years, | |
monthsFromDays; | |
// if we have a mix of positive and negative values, bubble down first | |
// check: https://github.com/moment/moment/issues/2166 | |
if ( | |
!( | |
(milliseconds >= 0 && days >= 0 && months >= 0) || | |
(milliseconds <= 0 && days <= 0 && months <= 0) | |
) | |
) { | |
milliseconds += absCeil(monthsToDays(months) + days) * 864e5; | |
days = 0; | |
months = 0; | |
} | |
// The following code bubbles up values, see the tests for | |
// examples of what that means. | |
data.milliseconds = milliseconds % 1000; | |
seconds = absFloor(milliseconds / 1000); | |
data.seconds = seconds % 60; | |
minutes = absFloor(seconds / 60); | |
data.minutes = minutes % 60; | |
hours = absFloor(minutes / 60); | |
data.hours = hours % 24; | |
days += absFloor(hours / 24); | |
// convert days to months | |
monthsFromDays = absFloor(daysToMonths(days)); | |
months += monthsFromDays; | |
days -= absCeil(monthsToDays(monthsFromDays)); | |
// 12 months -> 1 year | |
years = absFloor(months / 12); | |
months %= 12; | |
data.days = days; | |
data.months = months; | |
data.years = years; | |
return this; | |
} | |
function daysToMonths(days) { | |
// 400 years have 146097 days (taking into account leap year rules) | |
// 400 years have 12 months === 4800 | |
return (days * 4800) / 146097; | |
} | |
function monthsToDays(months) { | |
// the reverse of daysToMonths | |
return (months * 146097) / 4800; | |
} | |
function as(units) { | |
if (!this.isValid()) { | |
return NaN; | |
} | |
var days, | |
months, | |
milliseconds = this._milliseconds; | |
units = normalizeUnits(units); | |
if (units === 'month' || units === 'quarter' || units === 'year') { | |
days = this._days + milliseconds / 864e5; | |
months = this._months + daysToMonths(days); | |
switch (units) { | |
case 'month': | |
return months; | |
case 'quarter': | |
return months / 3; | |
case 'year': | |
return months / 12; | |
} | |
} else { | |
// handle milliseconds separately because of floating point math errors (issue #1867) | |
days = this._days + Math.round(monthsToDays(this._months)); | |
switch (units) { | |
case 'week': | |
return days / 7 + milliseconds / 6048e5; | |
case 'day': | |
return days + milliseconds / 864e5; | |
case 'hour': | |
return days * 24 + milliseconds / 36e5; | |
case 'minute': | |
return days * 1440 + milliseconds / 6e4; | |
case 'second': | |
return days * 86400 + milliseconds / 1000; | |
// Math.floor prevents floating point math errors here | |
case 'millisecond': | |
return Math.floor(days * 864e5) + milliseconds; | |
default: | |
throw new Error('Unknown unit ' + units); | |
} | |
} | |
} | |
// TODO: Use this.as('ms')? | |
function valueOf$1() { | |
if (!this.isValid()) { | |
return NaN; | |
} | |
return ( | |
this._milliseconds + | |
this._days * 864e5 + | |
(this._months % 12) * 2592e6 + | |
toInt(this._months / 12) * 31536e6 | |
); | |
} | |
function makeAs(alias) { | |
return function () { | |
return this.as(alias); | |
}; | |
} | |
var asMilliseconds = makeAs('ms'), | |
asSeconds = makeAs('s'), | |
asMinutes = makeAs('m'), | |
asHours = makeAs('h'), | |
asDays = makeAs('d'), | |
asWeeks = makeAs('w'), | |
asMonths = makeAs('M'), | |
asQuarters = makeAs('Q'), | |
asYears = makeAs('y'); | |
function clone$1() { | |
return createDuration(this); | |
} | |
function get$2(units) { | |
units = normalizeUnits(units); | |
return this.isValid() ? this[units + 's']() : NaN; | |
} | |
function makeGetter(name) { | |
return function () { | |
return this.isValid() ? this._data[name] : NaN; | |
}; | |
} | |
var milliseconds = makeGetter('milliseconds'), | |
seconds = makeGetter('seconds'), | |
minutes = makeGetter('minutes'), | |
hours = makeGetter('hours'), | |
days = makeGetter('days'), | |
months = makeGetter('months'), | |
years = makeGetter('years'); | |
function weeks() { | |
return absFloor(this.days() / 7); | |
} | |
var round = Math.round, | |
thresholds = { | |
ss: 44, // a few seconds to seconds | |
s: 45, // seconds to minute | |
m: 45, // minutes to hour | |
h: 22, // hours to day | |
d: 26, // days to month/week | |
w: null, // weeks to month | |
M: 11, // months to year | |
}; | |
// helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize | |
function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) { | |
return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture); | |
} | |
function relativeTime$1(posNegDuration, withoutSuffix, thresholds, locale) { | |
var duration = createDuration(posNegDuration).abs(), | |
seconds = round(duration.as('s')), | |
minutes = round(duration.as('m')), | |
hours = round(duration.as('h')), | |
days = round(duration.as('d')), | |
months = round(duration.as('M')), | |
weeks = round(duration.as('w')), | |
years = round(duration.as('y')), | |
a = | |
(seconds <= thresholds.ss && ['s', seconds]) || | |
(seconds < thresholds.s && ['ss', seconds]) || | |
(minutes <= 1 && ['m']) || | |
(minutes < thresholds.m && ['mm', minutes]) || | |
(hours <= 1 && ['h']) || | |
(hours < thresholds.h && ['hh', hours]) || | |
(days <= 1 && ['d']) || | |
(days < thresholds.d && ['dd', days]); | |
if (thresholds.w != null) { | |
a = | |
a || | |
(weeks <= 1 && ['w']) || | |
(weeks < thresholds.w && ['ww', weeks]); | |
} | |
a = a || | |
(months <= 1 && ['M']) || | |
(months < thresholds.M && ['MM', months]) || | |
(years <= 1 && ['y']) || ['yy', years]; | |
a[2] = withoutSuffix; | |
a[3] = +posNegDuration > 0; | |
a[4] = locale; | |
return substituteTimeAgo.apply(null, a); | |
} | |
// This function allows you to set the rounding function for relative time strings | |
function getSetRelativeTimeRounding(roundingFunction) { | |
if (roundingFunction === undefined) { | |
return round; | |
} | |
if (typeof roundingFunction === 'function') { | |
round = roundingFunction; | |
return true; | |
} | |
return false; | |
} | |
// This function allows you to set a threshold for relative time strings | |
function getSetRelativeTimeThreshold(threshold, limit) { | |
if (thresholds[threshold] === undefined) { | |
return false; | |
} | |
if (limit === undefined) { | |
return thresholds[threshold]; | |
} | |
thresholds[threshold] = limit; | |
if (threshold === 's') { | |
thresholds.ss = limit - 1; | |
} | |
return true; | |
} | |
function humanize(argWithSuffix, argThresholds) { | |
if (!this.isValid()) { | |
return this.localeData().invalidDate(); | |
} | |
var withSuffix = false, | |
th = thresholds, | |
locale, | |
output; | |
if (typeof argWithSuffix === 'object') { | |
argThresholds = argWithSuffix; | |
argWithSuffix = false; | |
} | |
if (typeof argWithSuffix === 'boolean') { | |
withSuffix = argWithSuffix; | |
} | |
if (typeof argThresholds === 'object') { | |
th = Object.assign({}, thresholds, argThresholds); | |
if (argThresholds.s != null && argThresholds.ss == null) { | |
th.ss = argThresholds.s - 1; | |
} | |
} | |
locale = this.localeData(); | |
output = relativeTime$1(this, !withSuffix, th, locale); | |
if (withSuffix) { | |
output = locale.pastFuture(+this, output); | |
} | |
return locale.postformat(output); | |
} | |
var abs$1 = Math.abs; | |
function sign(x) { | |
return (x > 0) - (x < 0) || +x; | |
} | |
function toISOString$1() { | |
// for ISO strings we do not use the normal bubbling rules: | |
// * milliseconds bubble up until they become hours | |
// * days do not bubble at all | |
// * months bubble up until they become years | |
// This is because there is no context-free conversion between hours and days | |
// (think of clock changes) | |
// and also not between days and months (28-31 days per month) | |
if (!this.isValid()) { | |
return this.localeData().invalidDate(); | |
} | |
var seconds = abs$1(this._milliseconds) / 1000, | |
days = abs$1(this._days), | |
months = abs$1(this._months), | |
minutes, | |
hours, | |
years, | |
s, | |
total = this.asSeconds(), | |
totalSign, | |
ymSign, | |
daysSign, | |
hmsSign; | |
if (!total) { | |
// this is the same as C#'s (Noda) and python (isodate)... | |
// but not other JS (goog.date) | |
return 'P0D'; | |
} | |
// 3600 seconds -> 60 minutes -> 1 hour | |
minutes = absFloor(seconds / 60); | |
hours = absFloor(minutes / 60); | |
seconds %= 60; | |
minutes %= 60; | |
// 12 months -> 1 year | |
years = absFloor(months / 12); | |
months %= 12; | |
// inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js | |
s = seconds ? seconds.toFixed(3).replace(/\.?0+$/, '') : ''; | |
totalSign = total < 0 ? '-' : ''; | |
ymSign = sign(this._months) !== sign(total) ? '-' : ''; | |
daysSign = sign(this._days) !== sign(total) ? '-' : ''; | |
hmsSign = sign(this._milliseconds) !== sign(total) ? '-' : ''; | |
return ( | |
totalSign + | |
'P' + | |
(years ? ymSign + years + 'Y' : '') + | |
(months ? ymSign + months + 'M' : '') + | |
(days ? daysSign + days + 'D' : '') + | |
(hours || minutes || seconds ? 'T' : '') + | |
(hours ? hmsSign + hours + 'H' : '') + | |
(minutes ? hmsSign + minutes + 'M' : '') + | |
(seconds ? hmsSign + s + 'S' : '') | |
); | |
} | |
var proto$2 = Duration.prototype; | |
proto$2.isValid = isValid$1; | |
proto$2.abs = abs; | |
proto$2.add = add$1; | |
proto$2.subtract = subtract$1; | |
proto$2.as = as; | |
proto$2.asMilliseconds = asMilliseconds; | |
proto$2.asSeconds = asSeconds; | |
proto$2.asMinutes = asMinutes; | |
proto$2.asHours = asHours; | |
proto$2.asDays = asDays; | |
proto$2.asWeeks = asWeeks; | |
proto$2.asMonths = asMonths; | |
proto$2.asQuarters = asQuarters; | |
proto$2.asYears = asYears; | |
proto$2.valueOf = valueOf$1; | |
proto$2._bubble = bubble; | |
proto$2.clone = clone$1; | |
proto$2.get = get$2; | |
proto$2.milliseconds = milliseconds; | |
proto$2.seconds = seconds; | |
proto$2.minutes = minutes; | |
proto$2.hours = hours; | |
proto$2.days = days; | |
proto$2.weeks = weeks; | |
proto$2.months = months; | |
proto$2.years = years; | |
proto$2.humanize = humanize; | |
proto$2.toISOString = toISOString$1; | |
proto$2.toString = toISOString$1; | |
proto$2.toJSON = toISOString$1; | |
proto$2.locale = locale; | |
proto$2.localeData = localeData; | |
proto$2.toIsoString = deprecate( | |
'toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', | |
toISOString$1 | |
); | |
proto$2.lang = lang; | |
// FORMATTING | |
addFormatToken('X', 0, 0, 'unix'); | |
addFormatToken('x', 0, 0, 'valueOf'); | |
// PARSING | |
addRegexToken('x', matchSigned); | |
addRegexToken('X', matchTimestamp); | |
addParseToken('X', function (input, array, config) { | |
config._d = new Date(parseFloat(input) * 1000); | |
}); | |
addParseToken('x', function (input, array, config) { | |
config._d = new Date(toInt(input)); | |
}); | |
//! moment.js | |
hooks.version = '2.27.0'; | |
setHookCallback(createLocal); | |
hooks.fn = proto; | |
hooks.min = min; | |
hooks.max = max; | |
hooks.now = now; | |
hooks.utc = createUTC; | |
hooks.unix = createUnix; | |
hooks.months = listMonths; | |
hooks.isDate = isDate; | |
hooks.locale = getSetGlobalLocale; | |
hooks.invalid = createInvalid; | |
hooks.duration = createDuration; | |
hooks.isMoment = isMoment; | |
hooks.weekdays = listWeekdays; | |
hooks.parseZone = createInZone; | |
hooks.localeData = getLocale; | |
hooks.isDuration = isDuration; | |
hooks.monthsShort = listMonthsShort; | |
hooks.weekdaysMin = listWeekdaysMin; | |
hooks.defineLocale = defineLocale; | |
hooks.updateLocale = updateLocale; | |
hooks.locales = listLocales; | |
hooks.weekdaysShort = listWeekdaysShort; | |
hooks.normalizeUnits = normalizeUnits; | |
hooks.relativeTimeRounding = getSetRelativeTimeRounding; | |
hooks.relativeTimeThreshold = getSetRelativeTimeThreshold; | |
hooks.calendarFormat = getCalendarFormat; | |
hooks.prototype = proto; | |
// currently HTML5 input type only supports 24-hour formats | |
hooks.HTML5_FMT = { | |
DATETIME_LOCAL: 'YYYY-MM-DDTHH:mm', // <input type="datetime-local" /> | |
DATETIME_LOCAL_SECONDS: 'YYYY-MM-DDTHH:mm:ss', // <input type="datetime-local" step="1" /> | |
DATETIME_LOCAL_MS: 'YYYY-MM-DDTHH:mm:ss.SSS', // <input type="datetime-local" step="0.001" /> | |
DATE: 'YYYY-MM-DD', // <input type="date" /> | |
TIME: 'HH:mm', // <input type="time" /> | |
TIME_SECONDS: 'HH:mm:ss', // <input type="time" step="1" /> | |
TIME_MS: 'HH:mm:ss.SSS', // <input type="time" step="0.001" /> | |
WEEK: 'GGGG-[W]WW', // <input type="week" /> | |
MONTH: 'YYYY-MM', // <input type="month" /> | |
}; | |
return hooks; | |
}))); | |
}); | |
// Generated by LiveScript 1.6.0 | |
var apply, curry, flip, fix, over, memoize, toString$ = {}.toString; | |
apply = curry$(function(f, list){ | |
return f.apply(null, list); | |
}); | |
curry = function(f){ | |
return curry$(f); | |
}; | |
flip = curry$(function(f, x, y){ | |
return f(y, x); | |
}); | |
fix = function(f){ | |
return function(g){ | |
return function(){ | |
return f(g(g)).apply(null, arguments); | |
}; | |
}(function(g){ | |
return function(){ | |
return f(g(g)).apply(null, arguments); | |
}; | |
}); | |
}; | |
over = curry$(function(f, g, x, y){ | |
return f(g(x), g(y)); | |
}); | |
memoize = function(f){ | |
var memo; | |
memo = {}; | |
return function(){ | |
var args, res$, i$, to$, key, arg; | |
res$ = []; | |
for (i$ = 0, to$ = arguments.length; i$ < to$; ++i$) { | |
res$.push(arguments[i$]); | |
} | |
args = res$; | |
key = (function(){ | |
var i$, ref$, len$, results$ = []; | |
for (i$ = 0, len$ = (ref$ = args).length; i$ < len$; ++i$) { | |
arg = ref$[i$]; | |
results$.push(arg + toString$.call(arg).slice(8, -1)); | |
} | |
return results$; | |
}()).join(''); | |
return memo[key] = key in memo | |
? memo[key] | |
: f.apply(null, args); | |
}; | |
}; | |
var Func = { | |
curry: curry, | |
flip: flip, | |
fix: fix, | |
apply: apply, | |
over: over, | |
memoize: memoize | |
}; | |
function curry$(f, bound){ | |
var context, | |
_curry = function(args) { | |
return f.length > 1 ? function(){ | |
var params = args ? args.concat() : []; | |
context = bound ? context || this : this; | |
return params.push.apply(params, arguments) < | |
f.length && arguments.length ? | |
_curry.call(context, params) : f.apply(context, params); | |
} : f; | |
}; | |
return _curry(); | |
} | |
// Generated by LiveScript 1.6.0 | |
var each, map, compact, filter, reject, remove, partition, find, head, first, tail, last, initial, empty, reverse, unique, uniqueBy, fold, foldl, fold1, foldl1, foldr, foldr1, unfoldr, concat, concatMap, flatten, difference, intersection, union, countBy, groupBy, andList, orList, any, all, sort, sortWith, sortBy, sum, product, mean, average, maximum, minimum, maximumBy, minimumBy, scan, scanl, scan1, scanl1, scanr, scanr1, slice, take, drop, splitAt, takeWhile, dropWhile, span, breakList, zip, zipWith, zipAll, zipAllWith, at, elemIndex, elemIndices, findIndex, findIndices, toString$$1 = {}.toString; | |
each = curry$$1(function(f, xs){ | |
var i$, len$, x; | |
for (i$ = 0, len$ = xs.length; i$ < len$; ++i$) { | |
x = xs[i$]; | |
f(x); | |
} | |
return xs; | |
}); | |
map = curry$$1(function(f, xs){ | |
var i$, len$, x, results$ = []; | |
for (i$ = 0, len$ = xs.length; i$ < len$; ++i$) { | |
x = xs[i$]; | |
results$.push(f(x)); | |
} | |
return results$; | |
}); | |
compact = function(xs){ | |
var i$, len$, x, results$ = []; | |
for (i$ = 0, len$ = xs.length; i$ < len$; ++i$) { | |
x = xs[i$]; | |
if (x) { | |
results$.push(x); | |
} | |
} | |
return results$; | |
}; | |
filter = curry$$1(function(f, xs){ | |
var i$, len$, x, results$ = []; | |
for (i$ = 0, len$ = xs.length; i$ < len$; ++i$) { | |
x = xs[i$]; | |
if (f(x)) { | |
results$.push(x); | |
} | |
} | |
return results$; | |
}); | |
reject = curry$$1(function(f, xs){ | |
var i$, len$, x, results$ = []; | |
for (i$ = 0, len$ = xs.length; i$ < len$; ++i$) { | |
x = xs[i$]; | |
if (!f(x)) { | |
results$.push(x); | |
} | |
} | |
return results$; | |
}); | |
remove = curry$$1(function(el, xs){ | |
var i, x$; | |
i = elemIndex(el, xs); | |
x$ = xs.slice(); | |
if (i != null) { | |
x$.splice(i, 1); | |
} | |
return x$; | |
}); | |
partition = curry$$1(function(f, xs){ | |
var passed, failed, i$, len$, x; | |
passed = []; | |
failed = []; | |
for (i$ = 0, len$ = xs.length; i$ < len$; ++i$) { | |
x = xs[i$]; | |
(f(x) ? passed : failed).push(x); | |
} | |
return [passed, failed]; | |
}); | |
find = curry$$1(function(f, xs){ | |
var i$, len$, x; | |
for (i$ = 0, len$ = xs.length; i$ < len$; ++i$) { | |
x = xs[i$]; | |
if (f(x)) { | |
return x; | |
} | |
} | |
}); | |
head = first = function(xs){ | |
return xs[0]; | |
}; | |
tail = function(xs){ | |
if (!xs.length) { | |
return; | |
} | |
return xs.slice(1); | |
}; | |
last = function(xs){ | |
return xs[xs.length - 1]; | |
}; | |
initial = function(xs){ | |
if (!xs.length) { | |
return; | |
} | |
return xs.slice(0, -1); | |
}; | |
empty = function(xs){ | |
return !xs.length; | |
}; | |
reverse = function(xs){ | |
return xs.concat().reverse(); | |
}; | |
unique = function(xs){ | |
var result, i$, len$, x; | |
result = []; | |
for (i$ = 0, len$ = xs.length; i$ < len$; ++i$) { | |
x = xs[i$]; | |
if (!in$(x, result)) { | |
result.push(x); | |
} | |
} | |
return result; | |
}; | |
uniqueBy = curry$$1(function(f, xs){ | |
var seen, i$, len$, x, val, results$ = []; | |
seen = []; | |
for (i$ = 0, len$ = xs.length; i$ < len$; ++i$) { | |
x = xs[i$]; | |
val = f(x); | |
if (in$(val, seen)) { | |
continue; | |
} | |
seen.push(val); | |
results$.push(x); | |
} | |
return results$; | |
}); | |
fold = foldl = curry$$1(function(f, memo, xs){ | |
var i$, len$, x; | |
for (i$ = 0, len$ = xs.length; i$ < len$; ++i$) { | |
x = xs[i$]; | |
memo = f(memo, x); | |
} | |
return memo; | |
}); | |
fold1 = foldl1 = curry$$1(function(f, xs){ | |
return fold(f, xs[0], xs.slice(1)); | |
}); | |
foldr = curry$$1(function(f, memo, xs){ | |
var i$, x; | |
for (i$ = xs.length - 1; i$ >= 0; --i$) { | |
x = xs[i$]; | |
memo = f(x, memo); | |
} | |
return memo; | |
}); | |
foldr1 = curry$$1(function(f, xs){ | |
return foldr(f, xs[xs.length - 1], xs.slice(0, -1)); | |
}); | |
unfoldr = curry$$1(function(f, b){ | |
var result, x, that; | |
result = []; | |
x = b; | |
while ((that = f(x)) != null) { | |
result.push(that[0]); | |
x = that[1]; | |
} | |
return result; | |
}); | |
concat = function(xss){ | |
return [].concat.apply([], xss); | |
}; | |
concatMap = curry$$1(function(f, xs){ | |
var x; | |
return [].concat.apply([], (function(){ | |
var i$, ref$, len$, results$ = []; | |
for (i$ = 0, len$ = (ref$ = xs).length; i$ < len$; ++i$) { | |
x = ref$[i$]; | |
results$.push(f(x)); | |
} | |
return results$; | |
}())); | |
}); | |
flatten = function(xs){ | |
var x; | |
return [].concat.apply([], (function(){ | |
var i$, ref$, len$, results$ = []; | |
for (i$ = 0, len$ = (ref$ = xs).length; i$ < len$; ++i$) { | |
x = ref$[i$]; | |
if (toString$$1.call(x).slice(8, -1) === 'Array') { | |
results$.push(flatten(x)); | |
} else { | |
results$.push(x); | |
} | |
} | |
return results$; | |
}())); | |
}; | |
difference = function(xs){ | |
var yss, res$, i$, to$, results, len$, x, j$, len1$, ys; | |
res$ = []; | |
for (i$ = 1, to$ = arguments.length; i$ < to$; ++i$) { | |
res$.push(arguments[i$]); | |
} | |
yss = res$; | |
results = []; | |
outer: for (i$ = 0, len$ = xs.length; i$ < len$; ++i$) { | |
x = xs[i$]; | |
for (j$ = 0, len1$ = yss.length; j$ < len1$; ++j$) { | |
ys = yss[j$]; | |
if (in$(x, ys)) { | |
continue outer; | |
} | |
} | |
results.push(x); | |
} | |
return results; | |
}; | |
intersection = function(xs){ | |
var yss, res$, i$, to$, results, len$, x, j$, len1$, ys; | |
res$ = []; | |
for (i$ = 1, to$ = arguments.length; i$ < to$; ++i$) { | |
res$.push(arguments[i$]); | |
} | |
yss = res$; | |
results = []; | |
outer: for (i$ = 0, len$ = xs.length; i$ < len$; ++i$) { | |
x = xs[i$]; | |
for (j$ = 0, len1$ = yss.length; j$ < len1$; ++j$) { | |
ys = yss[j$]; | |
if (!in$(x, ys)) { | |
continue outer; | |
} | |
} | |
results.push(x); | |
} | |
return results; | |
}; | |
union = function(){ | |
var xss, res$, i$, to$, results, len$, xs, j$, len1$, x; | |
res$ = []; | |
for (i$ = 0, to$ = arguments.length; i$ < to$; ++i$) { | |
res$.push(arguments[i$]); | |
} | |
xss = res$; | |
results = []; | |
for (i$ = 0, len$ = xss.length; i$ < len$; ++i$) { | |
xs = xss[i$]; | |
for (j$ = 0, len1$ = xs.length; j$ < len1$; ++j$) { | |
x = xs[j$]; | |
if (!in$(x, results)) { | |
results.push(x); | |
} | |
} | |
} | |
return results; | |
}; | |
countBy = curry$$1(function(f, xs){ | |
var results, i$, len$, x, key; | |
results = {}; | |
for (i$ = 0, len$ = xs.length; i$ < len$; ++i$) { | |
x = xs[i$]; | |
key = f(x); | |
if (key in results) { | |
results[key] += 1; | |
} else { | |
results[key] = 1; | |
} | |
} | |
return results; | |
}); | |
groupBy = curry$$1(function(f, xs){ | |
var results, i$, len$, x, key; | |
results = {}; | |
for (i$ = 0, len$ = xs.length; i$ < len$; ++i$) { | |
x = xs[i$]; | |
key = f(x); | |
if (key in results) { | |
results[key].push(x); | |
} else { | |
results[key] = [x]; | |
} | |
} | |
return results; | |
}); | |
andList = function(xs){ | |
var i$, len$, x; | |
for (i$ = 0, len$ = xs.length; i$ < len$; ++i$) { | |
x = xs[i$]; | |
if (!x) { | |
return false; | |
} | |
} | |
return true; | |
}; | |
orList = function(xs){ | |
var i$, len$, x; | |
for (i$ = 0, len$ = xs.length; i$ < len$; ++i$) { | |
x = xs[i$]; | |
if (x) { | |
return true; | |
} | |
} | |
return false; | |
}; | |
any = curry$$1(function(f, xs){ | |
var i$, len$, x; | |
for (i$ = 0, len$ = xs.length; i$ < len$; ++i$) { | |
x = xs[i$]; | |
if (f(x)) { | |
return true; | |
} | |
} | |
return false; | |
}); | |
all = curry$$1(function(f, xs){ | |
var i$, len$, x; | |
for (i$ = 0, len$ = xs.length; i$ < len$; ++i$) { | |
x = xs[i$]; | |
if (!f(x)) { | |
return false; | |
} | |
} | |
return true; | |
}); | |
sort = function(xs){ | |
return xs.concat().sort(function(x, y){ | |
if (x > y) { | |
return 1; | |
} else if (x < y) { | |
return -1; | |
} else { | |
return 0; | |
} | |
}); | |
}; | |
sortWith = curry$$1(function(f, xs){ | |
return xs.concat().sort(f); | |
}); | |
sortBy = curry$$1(function(f, xs){ | |
return xs.concat().sort(function(x, y){ | |
if (f(x) > f(y)) { | |
return 1; | |
} else if (f(x) < f(y)) { | |
return -1; | |
} else { | |
return 0; | |
} | |
}); | |
}); | |
sum = function(xs){ | |
var result, i$, len$, x; | |
result = 0; | |
for (i$ = 0, len$ = xs.length; i$ < len$; ++i$) { | |
x = xs[i$]; | |
result += x; | |
} | |
return result; | |
}; | |
product = function(xs){ | |
var result, i$, len$, x; | |
result = 1; | |
for (i$ = 0, len$ = xs.length; i$ < len$; ++i$) { | |
x = xs[i$]; | |
result *= x; | |
} | |
return result; | |
}; | |
mean = average = function(xs){ | |
var sum, i$, len$, x; | |
sum = 0; | |
for (i$ = 0, len$ = xs.length; i$ < len$; ++i$) { | |
x = xs[i$]; | |
sum += x; | |
} | |
return sum / xs.length; | |
}; | |
maximum = function(xs){ | |
var max, i$, ref$, len$, x; | |
max = xs[0]; | |
for (i$ = 0, len$ = (ref$ = xs.slice(1)).length; i$ < len$; ++i$) { | |
x = ref$[i$]; | |
if (x > max) { | |
max = x; | |
} | |
} | |
return max; | |
}; | |
minimum = function(xs){ | |
var min, i$, ref$, len$, x; | |
min = xs[0]; | |
for (i$ = 0, len$ = (ref$ = xs.slice(1)).length; i$ < len$; ++i$) { | |
x = ref$[i$]; | |
if (x < min) { | |
min = x; | |
} | |
} | |
return min; | |
}; | |
maximumBy = curry$$1(function(f, xs){ | |
var max, i$, ref$, len$, x; | |
max = xs[0]; | |
for (i$ = 0, len$ = (ref$ = xs.slice(1)).length; i$ < len$; ++i$) { | |
x = ref$[i$]; | |
if (f(x) > f(max)) { | |
max = x; | |
} | |
} | |
return max; | |
}); | |
minimumBy = curry$$1(function(f, xs){ | |
var min, i$, ref$, len$, x; | |
min = xs[0]; | |
for (i$ = 0, len$ = (ref$ = xs.slice(1)).length; i$ < len$; ++i$) { | |
x = ref$[i$]; | |
if (f(x) < f(min)) { | |
min = x; | |
} | |
} | |
return min; | |
}); | |
scan = scanl = curry$$1(function(f, memo, xs){ | |
var last, x; | |
last = memo; | |
return [memo].concat((function(){ | |
var i$, ref$, len$, results$ = []; | |
for (i$ = 0, len$ = (ref$ = xs).length; i$ < len$; ++i$) { | |
x = ref$[i$]; | |
results$.push(last = f(last, x)); | |
} | |
return results$; | |
}())); | |
}); | |
scan1 = scanl1 = curry$$1(function(f, xs){ | |
if (!xs.length) { | |
return; | |
} | |
return scan(f, xs[0], xs.slice(1)); | |
}); | |
scanr = curry$$1(function(f, memo, xs){ | |
xs = xs.concat().reverse(); | |
return scan(f, memo, xs).reverse(); | |
}); | |
scanr1 = curry$$1(function(f, xs){ | |
if (!xs.length) { | |
return; | |
} | |
xs = xs.concat().reverse(); | |
return scan(f, xs[0], xs.slice(1)).reverse(); | |
}); | |
slice = curry$$1(function(x, y, xs){ | |
return xs.slice(x, y); | |
}); | |
take = curry$$1(function(n, xs){ | |
if (n <= 0) { | |
return xs.slice(0, 0); | |
} else { | |
return xs.slice(0, n); | |
} | |
}); | |
drop = curry$$1(function(n, xs){ | |
if (n <= 0) { | |
return xs; | |
} else { | |
return xs.slice(n); | |
} | |
}); | |
splitAt = curry$$1(function(n, xs){ | |
return [take(n, xs), drop(n, xs)]; | |
}); | |
takeWhile = curry$$1(function(p, xs){ | |
var len, i; | |
len = xs.length; | |
if (!len) { | |
return xs; | |
} | |
i = 0; | |
while (i < len && p(xs[i])) { | |
i += 1; | |
} | |
return xs.slice(0, i); | |
}); | |
dropWhile = curry$$1(function(p, xs){ | |
var len, i; | |
len = xs.length; | |
if (!len) { | |
return xs; | |
} | |
i = 0; | |
while (i < len && p(xs[i])) { | |
i += 1; | |
} | |
return xs.slice(i); | |
}); | |
span = curry$$1(function(p, xs){ | |
return [takeWhile(p, xs), dropWhile(p, xs)]; | |
}); | |
breakList = curry$$1(function(p, xs){ | |
return span(compose$(p, not$), xs); | |
}); | |
zip = curry$$1(function(xs, ys){ | |
var result, len, i$, len$, i, x; | |
result = []; | |
len = ys.length; | |
for (i$ = 0, len$ = xs.length; i$ < len$; ++i$) { | |
i = i$; | |
x = xs[i$]; | |
if (i === len) { | |
break; | |
} | |
result.push([x, ys[i]]); | |
} | |
return result; | |
}); | |
zipWith = curry$$1(function(f, xs, ys){ | |
var result, len, i$, len$, i, x; | |
result = []; | |
len = ys.length; | |
for (i$ = 0, len$ = xs.length; i$ < len$; ++i$) { | |
i = i$; | |
x = xs[i$]; | |
if (i === len) { | |
break; | |
} | |
result.push(f(x, ys[i])); | |
} | |
return result; | |
}); | |
zipAll = function(){ | |
var xss, res$, i$, to$, minLength, len$, xs, ref$, i, lresult$, j$, results$ = []; | |
res$ = []; | |
for (i$ = 0, to$ = arguments.length; i$ < to$; ++i$) { | |
res$.push(arguments[i$]); | |
} | |
xss = res$; | |
minLength = undefined; | |
for (i$ = 0, len$ = xss.length; i$ < len$; ++i$) { | |
xs = xss[i$]; | |
minLength <= (ref$ = xs.length) || (minLength = ref$); | |
} | |
for (i$ = 0; i$ < minLength; ++i$) { | |
i = i$; | |
lresult$ = []; | |
for (j$ = 0, len$ = xss.length; j$ < len$; ++j$) { | |
xs = xss[j$]; | |
lresult$.push(xs[i]); | |
} | |
results$.push(lresult$); | |
} | |
return results$; | |
}; | |
zipAllWith = function(f){ | |
var xss, res$, i$, to$, minLength, len$, xs, ref$, i, results$ = []; | |
res$ = []; | |
for (i$ = 1, to$ = arguments.length; i$ < to$; ++i$) { | |
res$.push(arguments[i$]); | |
} | |
xss = res$; | |
minLength = undefined; | |
for (i$ = 0, len$ = xss.length; i$ < len$; ++i$) { | |
xs = xss[i$]; | |
minLength <= (ref$ = xs.length) || (minLength = ref$); | |
} | |
for (i$ = 0; i$ < minLength; ++i$) { | |
i = i$; | |
results$.push(f.apply(null, (fn$()))); | |
} | |
return results$; | |
function fn$(){ | |
var i$, ref$, len$, results$ = []; | |
for (i$ = 0, len$ = (ref$ = xss).length; i$ < len$; ++i$) { | |
xs = ref$[i$]; | |
results$.push(xs[i]); | |
} | |
return results$; | |
} | |
}; | |
at = curry$$1(function(n, xs){ | |
if (n < 0) { | |
return xs[xs.length + n]; | |
} else { | |
return xs[n]; | |
} | |
}); | |
elemIndex = curry$$1(function(el, xs){ | |
var i$, len$, i, x; | |
for (i$ = 0, len$ = xs.length; i$ < len$; ++i$) { | |
i = i$; | |
x = xs[i$]; | |
if (x === el) { | |
return i; | |
} | |
} | |
}); | |
elemIndices = curry$$1(function(el, xs){ | |
var i$, len$, i, x, results$ = []; | |
for (i$ = 0, len$ = xs.length; i$ < len$; ++i$) { | |
i = i$; | |
x = xs[i$]; | |
if (x === el) { | |
results$.push(i); | |
} | |
} | |
return results$; | |
}); | |
findIndex = curry$$1(function(f, xs){ | |
var i$, len$, i, x; | |
for (i$ = 0, len$ = xs.length; i$ < len$; ++i$) { | |
i = i$; | |
x = xs[i$]; | |
if (f(x)) { | |
return i; | |
} | |
} | |
}); | |
findIndices = curry$$1(function(f, xs){ | |
var i$, len$, i, x, results$ = []; | |
for (i$ = 0, len$ = xs.length; i$ < len$; ++i$) { | |
i = i$; | |
x = xs[i$]; | |
if (f(x)) { | |
results$.push(i); | |
} | |
} | |
return results$; | |
}); | |
var List = { | |
each: each, | |
map: map, | |
filter: filter, | |
compact: compact, | |
reject: reject, | |
remove: remove, | |
partition: partition, | |
find: find, | |
head: head, | |
first: first, | |
tail: tail, | |
last: last, | |
initial: initial, | |
empty: empty, | |
reverse: reverse, | |
difference: difference, | |
intersection: intersection, | |
union: union, | |
countBy: countBy, | |
groupBy: groupBy, | |
fold: fold, | |
fold1: fold1, | |
foldl: foldl, | |
foldl1: foldl1, | |
foldr: foldr, | |
foldr1: foldr1, | |
unfoldr: unfoldr, | |
andList: andList, | |
orList: orList, | |
any: any, | |
all: all, | |
unique: unique, | |
uniqueBy: uniqueBy, | |
sort: sort, | |
sortWith: sortWith, | |
sortBy: sortBy, | |
sum: sum, | |
product: product, | |
mean: mean, | |
average: average, | |
concat: concat, | |
concatMap: concatMap, | |
flatten: flatten, | |
maximum: maximum, | |
minimum: minimum, | |
maximumBy: maximumBy, | |
minimumBy: minimumBy, | |
scan: scan, | |
scan1: scan1, | |
scanl: scanl, | |
scanl1: scanl1, | |
scanr: scanr, | |
scanr1: scanr1, | |
slice: slice, | |
take: take, | |
drop: drop, | |
splitAt: splitAt, | |
takeWhile: takeWhile, | |
dropWhile: dropWhile, | |
span: span, | |
breakList: breakList, | |
zip: zip, | |
zipWith: zipWith, | |
zipAll: zipAll, | |
zipAllWith: zipAllWith, | |
at: at, | |
elemIndex: elemIndex, | |
elemIndices: elemIndices, | |
findIndex: findIndex, | |
findIndices: findIndices | |
}; | |
function curry$$1(f, bound){ | |
var context, | |
_curry = function(args) { | |
return f.length > 1 ? function(){ | |
var params = args ? args.concat() : []; | |
context = bound ? context || this : this; | |
return params.push.apply(params, arguments) < | |
f.length && arguments.length ? | |
_curry.call(context, params) : f.apply(context, params); | |
} : f; | |
}; | |
return _curry(); | |
} | |
function in$(x, xs){ | |
var i = -1, l = xs.length >>> 0; | |
while (++i < l) if (x === xs[i]) return true; | |
return false; | |
} | |
function compose$() { | |
var functions = arguments; | |
return function() { | |
var i, result; | |
result = functions[0].apply(this, arguments); | |
for (i = 1; i < functions.length; ++i) { | |
result = functions[i](result); | |
} | |
return result; | |
}; | |
} | |
function not$(x){ return !x; } | |
// Generated by LiveScript 1.6.0 | |
var values, keys, pairsToObj, objToPairs, listsToObj, objToLists, empty$1, each$1, map$1, compact$1, filter$1, reject$1, partition$1, find$1; | |
values = function(object){ | |
var i$, x, results$ = []; | |
for (i$ in object) { | |
x = object[i$]; | |
results$.push(x); | |
} | |
return results$; | |
}; | |
keys = function(object){ | |
var x, results$ = []; | |
for (x in object) { | |
results$.push(x); | |
} | |
return results$; | |
}; | |
pairsToObj = function(object){ | |
var i$, len$, x, resultObj$ = {}; | |
for (i$ = 0, len$ = object.length; i$ < len$; ++i$) { | |
x = object[i$]; | |
resultObj$[x[0]] = x[1]; | |
} | |
return resultObj$; | |
}; | |
objToPairs = function(object){ | |
var key, value, results$ = []; | |
for (key in object) { | |
value = object[key]; | |
results$.push([key, value]); | |
} | |
return results$; | |
}; | |
listsToObj = curry$$2(function(keys, values){ | |
var i$, len$, i, key, resultObj$ = {}; | |
for (i$ = 0, len$ = keys.length; i$ < len$; ++i$) { | |
i = i$; | |
key = keys[i$]; | |
resultObj$[key] = values[i]; | |
} | |
return resultObj$; | |
}); | |
objToLists = function(object){ | |
var keys, values, key, value; | |
keys = []; | |
values = []; | |
for (key in object) { | |
value = object[key]; | |
keys.push(key); | |
values.push(value); | |
} | |
return [keys, values]; | |
}; | |
empty$1 = function(object){ | |
var x; | |
for (x in object) { | |
return false; | |
} | |
return true; | |
}; | |
each$1 = curry$$2(function(f, object){ | |
var i$, x; | |
for (i$ in object) { | |
x = object[i$]; | |
f(x); | |
} | |
return object; | |
}); | |
map$1 = curry$$2(function(f, object){ | |
var k, x, resultObj$ = {}; | |
for (k in object) { | |
x = object[k]; | |
resultObj$[k] = f(x); | |
} | |
return resultObj$; | |
}); | |
compact$1 = function(object){ | |
var k, x, resultObj$ = {}; | |
for (k in object) { | |
x = object[k]; | |
if (x) { | |
resultObj$[k] = x; | |
} | |
} | |
return resultObj$; | |
}; | |
filter$1 = curry$$2(function(f, object){ | |
var k, x, resultObj$ = {}; | |
for (k in object) { | |
x = object[k]; | |
if (f(x)) { | |
resultObj$[k] = x; | |
} | |
} | |
return resultObj$; | |
}); | |
reject$1 = curry$$2(function(f, object){ | |
var k, x, resultObj$ = {}; | |
for (k in object) { | |
x = object[k]; | |
if (!f(x)) { | |
resultObj$[k] = x; | |
} | |
} | |
return resultObj$; | |
}); | |
partition$1 = curry$$2(function(f, object){ | |
var passed, failed, k, x; | |
passed = {}; | |
failed = {}; | |
for (k in object) { | |
x = object[k]; | |
(f(x) ? passed : failed)[k] = x; | |
} | |
return [passed, failed]; | |
}); | |
find$1 = curry$$2(function(f, object){ | |
var i$, x; | |
for (i$ in object) { | |
x = object[i$]; | |
if (f(x)) { | |
return x; | |
} | |
} | |
}); | |
var Obj = { | |
values: values, | |
keys: keys, | |
pairsToObj: pairsToObj, | |
objToPairs: objToPairs, | |
listsToObj: listsToObj, | |
objToLists: objToLists, | |
empty: empty$1, | |
each: each$1, | |
map: map$1, | |
filter: filter$1, | |
compact: compact$1, | |
reject: reject$1, | |
partition: partition$1, | |
find: find$1 | |
}; | |
function curry$$2(f, bound){ | |
var context, | |
_curry = function(args) { | |
return f.length > 1 ? function(){ | |
var params = args ? args.concat() : []; | |
context = bound ? context || this : this; | |
return params.push.apply(params, arguments) < | |
f.length && arguments.length ? | |
_curry.call(context, params) : f.apply(context, params); | |
} : f; | |
}; | |
return _curry(); | |
} | |
// Generated by LiveScript 1.6.0 | |
var split, join, lines, unlines, words, unwords, chars, unchars, reverse$1, repeat, capitalize, camelize, dasherize; | |
split = curry$$3(function(sep, str){ | |
return str.split(sep); | |
}); | |
join = curry$$3(function(sep, xs){ | |
return xs.join(sep); | |
}); | |
lines = function(str){ | |
if (!str.length) { | |
return []; | |
} | |
return str.split('\n'); | |
}; | |
unlines = function(it){ | |
return it.join('\n'); | |
}; | |
words = function(str){ | |
if (!str.length) { | |
return []; | |
} | |
return str.split(/[ ]+/); | |
}; | |
unwords = function(it){ | |
return it.join(' '); | |
}; | |
chars = function(it){ | |
return it.split(''); | |
}; | |
unchars = function(it){ | |
return it.join(''); | |
}; | |
reverse$1 = function(str){ | |
return str.split('').reverse().join(''); | |
}; | |
repeat = curry$$3(function(n, str){ | |
var result, i$; | |
result = ''; | |
for (i$ = 0; i$ < n; ++i$) { | |
result += str; | |
} | |
return result; | |
}); | |
capitalize = function(str){ | |
return str.charAt(0).toUpperCase() + str.slice(1); | |
}; | |
camelize = function(it){ | |
return it.replace(/[-_]+(.)?/g, function(arg$, c){ | |
return (c != null ? c : '').toUpperCase(); | |
}); | |
}; | |
dasherize = function(str){ | |
return str.replace(/([^-A-Z])([A-Z]+)/g, function(arg$, lower, upper){ | |
return lower + "-" + (upper.length > 1 | |
? upper | |
: upper.toLowerCase()); | |
}).replace(/^([A-Z]+)/, function(arg$, upper){ | |
if (upper.length > 1) { | |
return upper + "-"; | |
} else { | |
return upper.toLowerCase(); | |
} | |
}); | |
}; | |
var Str = { | |
split: split, | |
join: join, | |
lines: lines, | |
unlines: unlines, | |
words: words, | |
unwords: unwords, | |
chars: chars, | |
unchars: unchars, | |
reverse: reverse$1, | |
repeat: repeat, | |
capitalize: capitalize, | |
camelize: camelize, | |
dasherize: dasherize | |
}; | |
function curry$$3(f, bound){ | |
var context, | |
_curry = function(args) { | |
return f.length > 1 ? function(){ | |
var params = args ? args.concat() : []; | |
context = bound ? context || this : this; | |
return params.push.apply(params, arguments) < | |
f.length && arguments.length ? | |
_curry.call(context, params) : f.apply(context, params); | |
} : f; | |
}; | |
return _curry(); | |
} | |
// Generated by LiveScript 1.6.0 | |
var max, min, negate, abs, signum, quot, rem, div, mod, recip, pi, tau, exp, sqrt, ln, pow, sin, tan, cos, asin, acos, atan, atan2, truncate, round, ceiling, floor, isItNaN, even, odd, gcd, lcm; | |
max = curry$$4(function(x$, y$){ | |
return x$ > y$ ? x$ : y$; | |
}); | |
min = curry$$4(function(x$, y$){ | |
return x$ < y$ ? x$ : y$; | |
}); | |
negate = function(x){ | |
return -x; | |
}; | |
abs = Math.abs; | |
signum = function(x){ | |
if (x < 0) { | |
return -1; | |
} else if (x > 0) { | |
return 1; | |
} else { | |
return 0; | |
} | |
}; | |
quot = curry$$4(function(x, y){ | |
return ~~(x / y); | |
}); | |
rem = curry$$4(function(x$, y$){ | |
return x$ % y$; | |
}); | |
div = curry$$4(function(x, y){ | |
return Math.floor(x / y); | |
}); | |
mod = curry$$4(function(x$, y$){ | |
var ref$; | |
return ((x$) % (ref$ = y$) + ref$) % ref$; | |
}); | |
recip = (function(it){ | |
return 1 / it; | |
}); | |
pi = Math.PI; | |
tau = pi * 2; | |
exp = Math.exp; | |
sqrt = Math.sqrt; | |
ln = Math.log; | |
pow = curry$$4(function(x$, y$){ | |
return Math.pow(x$, y$); | |
}); | |
sin = Math.sin; | |
tan = Math.tan; | |
cos = Math.cos; | |
asin = Math.asin; | |
acos = Math.acos; | |
atan = Math.atan; | |
atan2 = curry$$4(function(x, y){ | |
return Math.atan2(x, y); | |
}); | |
truncate = function(x){ | |
return ~~x; | |
}; | |
round = Math.round; | |
ceiling = Math.ceil; | |
floor = Math.floor; | |
isItNaN = function(x){ | |
return x !== x; | |
}; | |
even = function(x){ | |
return x % 2 === 0; | |
}; | |
odd = function(x){ | |
return x % 2 !== 0; | |
}; | |
gcd = curry$$4(function(x, y){ | |
var z; | |
x = Math.abs(x); | |
y = Math.abs(y); | |
while (y !== 0) { | |
z = x % y; | |
x = y; | |
y = z; | |
} | |
return x; | |
}); | |
lcm = curry$$4(function(x, y){ | |
return Math.abs(Math.floor(x / gcd(x, y) * y)); | |
}); | |
var Num = { | |
max: max, | |
min: min, | |
negate: negate, | |
abs: abs, | |
signum: signum, | |
quot: quot, | |
rem: rem, | |
div: div, | |
mod: mod, | |
recip: recip, | |
pi: pi, | |
tau: tau, | |
exp: exp, | |
sqrt: sqrt, | |
ln: ln, | |
pow: pow, | |
sin: sin, | |
tan: tan, | |
cos: cos, | |
acos: acos, | |
asin: asin, | |
atan: atan, | |
atan2: atan2, | |
truncate: truncate, | |
round: round, | |
ceiling: ceiling, | |
floor: floor, | |
isItNaN: isItNaN, | |
even: even, | |
odd: odd, | |
gcd: gcd, | |
lcm: lcm | |
}; | |
function curry$$4(f, bound){ | |
var context, | |
_curry = function(args) { | |
return f.length > 1 ? function(){ | |
var params = args ? args.concat() : []; | |
context = bound ? context || this : this; | |
return params.push.apply(params, arguments) < | |
f.length && arguments.length ? | |
_curry.call(context, params) : f.apply(context, params); | |
} : f; | |
}; | |
return _curry(); | |
} | |
// Generated by LiveScript 1.6.0 | |
var Func$1, List$1, Obj$1, Str$1, Num$1, id, isType, replicate, prelude, toString$$2 = {}.toString; | |
Func$1 = Func; | |
List$1 = List; | |
Obj$1 = Obj; | |
Str$1 = Str; | |
Num$1 = Num; | |
id = function(x){ | |
return x; | |
}; | |
isType = curry$$5(function(type, x){ | |
return toString$$2.call(x).slice(8, -1) === type; | |
}); | |
replicate = curry$$5(function(n, x){ | |
var i$, results$ = []; | |
for (i$ = 0; i$ < n; ++i$) { | |
results$.push(x); | |
} | |
return results$; | |
}); | |
Str$1.empty = List$1.empty; | |
Str$1.slice = List$1.slice; | |
Str$1.take = List$1.take; | |
Str$1.drop = List$1.drop; | |
Str$1.splitAt = List$1.splitAt; | |
Str$1.takeWhile = List$1.takeWhile; | |
Str$1.dropWhile = List$1.dropWhile; | |
Str$1.span = List$1.span; | |
Str$1.breakStr = List$1.breakList; | |
prelude = { | |
Func: Func$1, | |
List: List$1, | |
Obj: Obj$1, | |
Str: Str$1, | |
Num: Num$1, | |
id: id, | |
isType: isType, | |
replicate: replicate | |
}; | |
prelude.each = List$1.each; | |
prelude.map = List$1.map; | |
prelude.filter = List$1.filter; | |
prelude.compact = List$1.compact; | |
prelude.reject = List$1.reject; | |
prelude.partition = List$1.partition; | |
prelude.find = List$1.find; | |
prelude.head = List$1.head; | |
prelude.first = List$1.first; | |
prelude.tail = List$1.tail; | |
prelude.last = List$1.last; | |
prelude.initial = List$1.initial; | |
prelude.empty = List$1.empty; | |
prelude.reverse = List$1.reverse; | |
prelude.difference = List$1.difference; | |
prelude.intersection = List$1.intersection; | |
prelude.union = List$1.union; | |
prelude.countBy = List$1.countBy; | |
prelude.groupBy = List$1.groupBy; | |
prelude.fold = List$1.fold; | |
prelude.foldl = List$1.foldl; | |
prelude.fold1 = List$1.fold1; | |
prelude.foldl1 = List$1.foldl1; | |
prelude.foldr = List$1.foldr; | |
prelude.foldr1 = List$1.foldr1; | |
prelude.unfoldr = List$1.unfoldr; | |
prelude.andList = List$1.andList; | |
prelude.orList = List$1.orList; | |
prelude.any = List$1.any; | |
prelude.all = List$1.all; | |
prelude.unique = List$1.unique; | |
prelude.uniqueBy = List$1.uniqueBy; | |
prelude.sort = List$1.sort; | |
prelude.sortWith = List$1.sortWith; | |
prelude.sortBy = List$1.sortBy; | |
prelude.sum = List$1.sum; | |
prelude.product = List$1.product; | |
prelude.mean = List$1.mean; | |
prelude.average = List$1.average; | |
prelude.concat = List$1.concat; | |
prelude.concatMap = List$1.concatMap; | |
prelude.flatten = List$1.flatten; | |
prelude.maximum = List$1.maximum; | |
prelude.minimum = List$1.minimum; | |
prelude.maximumBy = List$1.maximumBy; | |
prelude.minimumBy = List$1.minimumBy; | |
prelude.scan = List$1.scan; | |
prelude.scanl = List$1.scanl; | |
prelude.scan1 = List$1.scan1; | |
prelude.scanl1 = List$1.scanl1; | |
prelude.scanr = List$1.scanr; | |
prelude.scanr1 = List$1.scanr1; | |
prelude.slice = List$1.slice; | |
prelude.take = List$1.take; | |
prelude.drop = List$1.drop; | |
prelude.splitAt = List$1.splitAt; | |
prelude.takeWhile = List$1.takeWhile; | |
prelude.dropWhile = List$1.dropWhile; | |
prelude.span = List$1.span; | |
prelude.breakList = List$1.breakList; | |
prelude.zip = List$1.zip; | |
prelude.zipWith = List$1.zipWith; | |
prelude.zipAll = List$1.zipAll; | |
prelude.zipAllWith = List$1.zipAllWith; | |
prelude.at = List$1.at; | |
prelude.elemIndex = List$1.elemIndex; | |
prelude.elemIndices = List$1.elemIndices; | |
prelude.findIndex = List$1.findIndex; | |
prelude.findIndices = List$1.findIndices; | |
prelude.apply = Func$1.apply; | |
prelude.curry = Func$1.curry; | |
prelude.flip = Func$1.flip; | |
prelude.fix = Func$1.fix; | |
prelude.over = Func$1.over; | |
prelude.split = Str$1.split; | |
prelude.join = Str$1.join; | |
prelude.lines = Str$1.lines; | |
prelude.unlines = Str$1.unlines; | |
prelude.words = Str$1.words; | |
prelude.unwords = Str$1.unwords; | |
prelude.chars = Str$1.chars; | |
prelude.unchars = Str$1.unchars; | |
prelude.repeat = Str$1.repeat; | |
prelude.capitalize = Str$1.capitalize; | |
prelude.camelize = Str$1.camelize; | |
prelude.dasherize = Str$1.dasherize; | |
prelude.values = Obj$1.values; | |
prelude.keys = Obj$1.keys; | |
prelude.pairsToObj = Obj$1.pairsToObj; | |
prelude.objToPairs = Obj$1.objToPairs; | |
prelude.listsToObj = Obj$1.listsToObj; | |
prelude.objToLists = Obj$1.objToLists; | |
prelude.max = Num$1.max; | |
prelude.min = Num$1.min; | |
prelude.negate = Num$1.negate; | |
prelude.abs = Num$1.abs; | |
prelude.signum = Num$1.signum; | |
prelude.quot = Num$1.quot; | |
prelude.rem = Num$1.rem; | |
prelude.div = Num$1.div; | |
prelude.mod = Num$1.mod; | |
prelude.recip = Num$1.recip; | |
prelude.pi = Num$1.pi; | |
prelude.tau = Num$1.tau; | |
prelude.exp = Num$1.exp; | |
prelude.sqrt = Num$1.sqrt; | |
prelude.ln = Num$1.ln; | |
prelude.pow = Num$1.pow; | |
prelude.sin = Num$1.sin; | |
prelude.tan = Num$1.tan; | |
prelude.cos = Num$1.cos; | |
prelude.acos = Num$1.acos; | |
prelude.asin = Num$1.asin; | |
prelude.atan = Num$1.atan; | |
prelude.atan2 = Num$1.atan2; | |
prelude.truncate = Num$1.truncate; | |
prelude.round = Num$1.round; | |
prelude.ceiling = Num$1.ceiling; | |
prelude.floor = Num$1.floor; | |
prelude.isItNaN = Num$1.isItNaN; | |
prelude.even = Num$1.even; | |
prelude.odd = Num$1.odd; | |
prelude.gcd = Num$1.gcd; | |
prelude.lcm = Num$1.lcm; | |
prelude.VERSION = '1.2.1'; | |
var lib$1 = prelude; | |
function curry$$5(f, bound){ | |
var context, | |
_curry = function(args) { | |
return f.length > 1 ? function(){ | |
var params = args ? args.concat() : []; | |
context = bound ? context || this : this; | |
return params.push.apply(params, arguments) < | |
f.length && arguments.length ? | |
_curry.call(context, params) : f.apply(context, params); | |
} : f; | |
}; | |
return _curry(); | |
} | |
var eventEmitter = createCommonjsModule(function (module, exports) { | |
// Generated by LiveScript 1.6.0 | |
var ref$, reject, maximum, map, EventEmitter, out$ = exports || commonjsGlobal, toString$ = {}.toString; | |
ref$ = lib$1, reject = ref$.reject, maximum = ref$.maximum, map = ref$.map; | |
out$.EventEmitter = EventEmitter = (function(){ | |
EventEmitter.displayName = 'EventEmitter'; | |
function EventEmitter(){ | |
this._events = {}; | |
this._one_time_events = {}; | |
} | |
EventEmitter.prototype.once = function(type, callback){ | |
var addListener, name, this$ = this; | |
addListener = function(type, callback){ | |
if (toString$.call(this$._one_time_events[type]).slice(8, -1) !== 'Array') { | |
this$._one_time_events[type] = []; | |
} | |
return this$._one_time_events[type].push(callback.bind(this$)); | |
}; | |
switch (toString$.call(type).slice(8, -1)) { | |
case 'String': | |
addListener(type, callback); | |
break; | |
case 'Object': | |
for (name in type) { | |
callback = type[name]; | |
addListener(name, callback); | |
} | |
} | |
}; | |
EventEmitter.prototype.on = function(type, id, callback){ | |
"usage:\n\n with simple string name:\n\n .on 'name', fn\n\n or with an object:\n\n .on do\n 'name1': fn\n 'name2': fn2"; | |
var _id, addListener, control, name, this$ = this; | |
if (toString$.call(id).slice(8, -1) === 'Function') { | |
callback = id; | |
_id = maximum( | |
map(parseInt)( | |
(function(){ | |
var i$, x$, ref$, len$, results$ = []; | |
for (i$ = 0, len$ = (ref$ = this._events).length; i$ < len$; ++i$) { | |
x$ = ref$[i$]; | |
results$.push(x$.id); | |
} | |
return results$; | |
}.call(this)))); | |
id = (_id || 0) + 1; | |
} | |
addListener = function(type, id, callback){ | |
var ref$; | |
((ref$ = this$._events)[type] || (ref$[type] = [])).push({ | |
id: id, | |
cb: callback.bind(this$) | |
}); | |
return { | |
cancel: function(){ | |
return this$.cancel(id); | |
} | |
}; | |
}; | |
control = null; | |
switch (toString$.call(type).slice(8, -1)) { | |
case 'String': | |
control = addListener(type, id, callback); | |
break; | |
case 'Object': | |
for (name in type) { | |
callback = type[name]; | |
addListener(name, id, callback); | |
} | |
} | |
return control; | |
}; | |
EventEmitter.prototype.off = function(type){ | |
return this._events[type] = []; | |
}; | |
EventEmitter.prototype.cancel = function(id){ | |
var type, ref$, listeners, i, listener; | |
for (type in ref$ = this._events) { | |
listeners = ref$[type]; | |
for (i in listeners) { | |
listener = listeners[i]; | |
if (listener.id === id) { | |
listeners.splice(i, 1); | |
break; | |
} | |
} | |
} | |
}; | |
EventEmitter.prototype.trigger = function(type){ | |
"usage:\n\n .trigger \"eventName\", ...x\n"; | |
var args, res$, i$, to$, that, len$, ref$, i, handler, results$ = []; | |
res$ = []; | |
for (i$ = 1, to$ = arguments.length; i$ < to$; ++i$) { | |
res$.push(arguments[i$]); | |
} | |
args = res$; | |
if (that = this._events[type]) { | |
for (i$ = 0, len$ = that.length; i$ < len$; ++i$) { | |
(fn$.call(this, that[i$])); | |
} | |
} | |
if (that = this._one_time_events[type]) { | |
for (i$ = 0, len$ = (ref$ = (fn1$())).length; i$ < len$; ++i$) { | |
i = ref$[i$]; | |
handler = that.shift(); | |
results$.push(handler.apply(null, args)); | |
} | |
return results$; | |
} | |
function fn$(handler){ | |
setImmediate(function(){ | |
return handler.cb.apply(handler, args); | |
}); | |
} | |
function fn1$(){ | |
var i$, to$, results$ = []; | |
for (i$ = 1, to$ = that.length; i$ <= to$; ++i$) { | |
results$.push(i$); | |
} | |
return results$; | |
} | |
}; | |
EventEmitter.prototype.hasListener = function(ev){ | |
var that, i$, x$, len$; | |
if (that = this._events[ev]) { | |
for (i$ = 0, len$ = that.length; i$ < len$; ++i$) { | |
x$ = that[i$]; | |
if (toString$.call(x$.cb).slice(8, -1) === 'Function') { | |
return true; | |
} | |
} | |
} | |
return false; | |
}; | |
return EventEmitter; | |
}()); | |
}); | |
var logger = createCommonjsModule(function (module, exports) { | |
// Generated by LiveScript 1.6.0 | |
var ref$, green, gray, yellow, magenta, bgRed, bgYellow, cyan, bgCyan, bgGreen, moment$1, map, EventEmitter, NEED_STACK_TRACE, fmt, startTime, alignLeft, getTimestamp, getPrefix, IS_NODE, LogManager, Logger, out$ = exports || commonjsGlobal, slice$ = [].slice, arrayFrom$ = Array.from || function(x){return slice$.call(x);}, toString$ = {}.toString; | |
ref$ = lib, green = ref$.green, gray = ref$.gray, yellow = ref$.yellow, magenta = ref$.magenta, bgRed = ref$.bgRed, bgYellow = ref$.bgYellow, cyan = ref$.cyan, bgCyan = ref$.bgCyan, bgGreen = ref$.bgGreen; | |
moment$1 = moment; | |
map = lib$1.map; | |
EventEmitter = eventEmitter.EventEmitter; | |
NEED_STACK_TRACE = false; | |
fmt = 'HH:mm:ss.SSS'; | |
startTime = new moment$1; | |
alignLeft = function(width, inp){ | |
var x; | |
return x = (inp + repeatString$(" ", width)).slice(0, width); | |
}; | |
getTimestamp = function(){ | |
return (new moment$1).format(fmt); | |
}; | |
getPrefix = function(_source, color){ | |
var padded; | |
if (!color) { | |
color = gray; | |
} | |
padded = alignLeft(15, _source + ""); | |
return color("[" + getTimestamp() + "]") + (" " + padded + " :"); | |
}; | |
IS_NODE = function(){ | |
var isNode; | |
isNode = false; | |
if (typeof process === 'object') { | |
if (typeof process.versions === 'object') { | |
if (typeof process.versions.node !== 'undefined') { | |
isNode = true; | |
} | |
} | |
} | |
return isNode; | |
}(); | |
LogManager = (function(superclass){ | |
var prototype = extend$((import$(LogManager, superclass).displayName = 'LogManager', LogManager), superclass).prototype, constructor = LogManager; | |
constructor.instance = null; | |
function LogManager(){ | |
if (constructor.instance) { | |
return constructor.instance; | |
} | |
LogManager.superclass.call(this); | |
constructor.instance = this; | |
this.loggers = []; | |
} | |
LogManager.prototype.register = function(ctx){ | |
return this.loggers.push(ctx); | |
}; | |
return LogManager; | |
}(EventEmitter)); | |
out$.Logger = Logger = (function(superclass){ | |
var prototype = extend$((import$(Logger, superclass).displayName = 'Logger', Logger), superclass).prototype; | |
function Logger(sourceName, opts){ | |
this.debug = bind$(this, 'debug', prototype); | |
this.todo = bind$(this, 'todo', prototype); | |
this.info = bind$(this, 'info', prototype); | |
this.warn = bind$(this, 'warn', prototype); | |
this.err = bind$(this, 'err', prototype); | |
this.success = bind$(this, 'success', prototype); | |
this.log = bind$(this, 'log', prototype); | |
Logger.superclass.call(this); | |
this.name = sourceName; | |
this.mgr = new LogManager(); | |
this.prefix = null; | |
this.error = this.err; | |
} | |
Logger.prototype.getPrefix = function(color){ | |
return getPrefix((this.prefix ? this.prefix + "/" : '') + "" + this.name, color); | |
}; | |
Logger.prototype.log = function(){ | |
var args, res$, i$, to$, prefix, ref$, _args, my, len$, arg, log; | |
res$ = []; | |
for (i$ = 0, to$ = arguments.length; i$ < to$; ++i$) { | |
res$.push(arguments[i$]); | |
} | |
args = res$; | |
prefix = getPrefix(this.name); | |
if (IS_NODE) { | |
return (ref$ = console.log).call.apply(ref$, [console, prefix].concat(arrayFrom$(args))); | |
} else { | |
_args = []; | |
my = "%c"; | |
for (i$ = 0, len$ = (ref$ = [prefix].concat(args)).length; i$ < len$; ++i$) { | |
arg = ref$[i$]; | |
_args.push(arg); | |
my += " " + (toString$.call(arg).slice(8, -1) === 'String' | |
? "%s" | |
: toString$.call(arg).slice(8, -1) === 'Number' ? "%d" : "%O"); | |
} | |
if (NEED_STACK_TRACE) { | |
console.groupCollapsed.apply(console, [my, "font-weight: normal;"].concat(arrayFrom$(_args))); | |
console.trace(prefix); | |
return console.groupEnd(); | |
} else { | |
log = Function.prototype.bind.call(console.log, console); | |
return log.call.apply(log, [console, my, "font-weight: normal;"].concat(arrayFrom$(_args))); | |
} | |
} | |
}; | |
Logger.prototype.success = function(){ | |
var args, res$, i$, to$; | |
res$ = []; | |
for (i$ = 0, to$ = arguments.length; i$ < to$; ++i$) { | |
res$.push(arguments[i$]); | |
} | |
args = res$; | |
return console.log.apply(console, [this.getPrefix(bgGreen)].concat(args)); | |
}; | |
Logger.prototype.err = function(){ | |
var args, res$, i$, to$, ref$; | |
res$ = []; | |
for (i$ = 0, to$ = arguments.length; i$ < to$; ++i$) { | |
res$.push(arguments[i$]); | |
} | |
args = res$; | |
console.error.apply(console, [this.getPrefix(bgRed)].concat(args)); | |
this.trigger.apply(this, ['err'].concat(arrayFrom$(args))); | |
return (ref$ = this.mgr).trigger.apply(ref$, ['err'].concat(arrayFrom$(args))); | |
}; | |
Logger.prototype.warn = function(){ | |
var args, res$, i$, to$; | |
res$ = []; | |
for (i$ = 0, to$ = arguments.length; i$ < to$; ++i$) { | |
res$.push(arguments[i$]); | |
} | |
args = res$; | |
return console.warn.apply(console, [this.getPrefix(bgYellow), yellow('[WARNING]')].concat(args)); | |
}; | |
Logger.prototype.info = function(){ | |
var args, res$, i$, to$; | |
res$ = []; | |
for (i$ = 0, to$ = arguments.length; i$ < to$; ++i$) { | |
res$.push(arguments[i$]); | |
} | |
args = res$; | |
return console.info.apply(console, [this.getPrefix(), cyan('[I]')].concat(args)); | |
}; | |
Logger.prototype.todo = function(){ | |
var args, res$, i$, to$; | |
res$ = []; | |
for (i$ = 0, to$ = arguments.length; i$ < to$; ++i$) { | |
res$.push(arguments[i$]); | |
} | |
args = res$; | |
return console.warn.apply(console, [this.getPrefix(), magenta('[TODO]')].concat(args)); | |
}; | |
Logger.prototype.debug = function(){ | |
var args, res$, i$, to$; | |
res$ = []; | |
for (i$ = 0, to$ = arguments.length; i$ < to$; ++i$) { | |
res$.push(arguments[i$]); | |
} | |
args = res$; | |
return console.warn.apply(console, [this.getPrefix(), yellow('[D]')].concat(args)); | |
}; | |
return Logger; | |
}(EventEmitter)); | |
function repeatString$(str, n){ | |
for (var r = ''; n > 0; (n >>= 1) && (str += str)) if (n & 1) r += str; | |
return r; | |
} | |
function extend$(sub, sup){ | |
function fun(){} fun.prototype = (sub.superclass = sup).prototype; | |
(sub.prototype = new fun).constructor = sub; | |
if (typeof sup.extended == 'function') sup.extended(sub); | |
return sub; | |
} | |
function import$(obj, src){ | |
var own = {}.hasOwnProperty; | |
for (var key in src) if (own.call(src, key)) obj[key] = src[key]; | |
return obj; | |
} | |
function bind$(obj, key, target){ | |
return function(){ return (target || obj)[key].apply(obj, arguments) }; | |
} | |
}); | |
(function (global, undefined$1) { | |
if (global.setImmediate) { | |
return; | |
} | |
var nextHandle = 1; // Spec says greater than zero | |
var tasksByHandle = {}; | |
var currentlyRunningATask = false; | |
var doc = global.document; | |
var registerImmediate; | |
function setImmediate(callback) { | |
// Callback can either be a function or a string | |
if (typeof callback !== "function") { | |
callback = new Function("" + callback); | |
} | |
// Copy function arguments | |
var args = new Array(arguments.length - 1); | |
for (var i = 0; i < args.length; i++) { | |
args[i] = arguments[i + 1]; | |
} | |
// Store and register the task | |
var task = { callback: callback, args: args }; | |
tasksByHandle[nextHandle] = task; | |
registerImmediate(nextHandle); | |
return nextHandle++; | |
} | |
function clearImmediate(handle) { | |
delete tasksByHandle[handle]; | |
} | |
function run(task) { | |
var callback = task.callback; | |
var args = task.args; | |
switch (args.length) { | |
case 0: | |
callback(); | |
break; | |
case 1: | |
callback(args[0]); | |
break; | |
case 2: | |
callback(args[0], args[1]); | |
break; | |
case 3: | |
callback(args[0], args[1], args[2]); | |
break; | |
default: | |
callback.apply(undefined$1, args); | |
break; | |
} | |
} | |
function runIfPresent(handle) { | |
// From the spec: "Wait until any invocations of this algorithm started before this one have completed." | |
// So if we're currently running a task, we'll need to delay this invocation. | |
if (currentlyRunningATask) { | |
// Delay by doing a setTimeout. setImmediate was tried instead, but in Firefox 7 it generated a | |
// "too much recursion" error. | |
setTimeout(runIfPresent, 0, handle); | |
} else { | |
var task = tasksByHandle[handle]; | |
if (task) { | |
currentlyRunningATask = true; | |
try { | |
run(task); | |
} finally { | |
clearImmediate(handle); | |
currentlyRunningATask = false; | |
} | |
} | |
} | |
} | |
function installNextTickImplementation() { | |
registerImmediate = function(handle) { | |
process.nextTick(function () { runIfPresent(handle); }); | |
}; | |
} | |
function canUsePostMessage() { | |
// The test against `importScripts` prevents this implementation from being installed inside a web worker, | |
// where `global.postMessage` means something completely different and can't be used for this purpose. | |
if (global.postMessage && !global.importScripts) { | |
var postMessageIsAsynchronous = true; | |
var oldOnMessage = global.onmessage; | |
global.onmessage = function() { | |
postMessageIsAsynchronous = false; | |
}; | |
global.postMessage("", "*"); | |
global.onmessage = oldOnMessage; | |
return postMessageIsAsynchronous; | |
} | |
} | |
function installPostMessageImplementation() { | |
// Installs an event handler on `global` for the `message` event: see | |
// * https://developer.mozilla.org/en/DOM/window.postMessage | |
// * http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages | |
var messagePrefix = "setImmediate$" + Math.random() + "$"; | |
var onGlobalMessage = function(event) { | |
if (event.source === global && | |
typeof event.data === "string" && | |
event.data.indexOf(messagePrefix) === 0) { | |
runIfPresent(+event.data.slice(messagePrefix.length)); | |
} | |
}; | |
if (global.addEventListener) { | |
global.addEventListener("message", onGlobalMessage, false); | |
} else { | |
global.attachEvent("onmessage", onGlobalMessage); | |
} | |
registerImmediate = function(handle) { | |
global.postMessage(messagePrefix + handle, "*"); | |
}; | |
} | |
function installMessageChannelImplementation() { | |
var channel = new MessageChannel(); | |
channel.port1.onmessage = function(event) { | |
var handle = event.data; | |
runIfPresent(handle); | |
}; | |
registerImmediate = function(handle) { | |
channel.port2.postMessage(handle); | |
}; | |
} | |
function installReadyStateChangeImplementation() { | |
var html = doc.documentElement; | |
registerImmediate = function(handle) { | |
// Create a <script> element; its readystatechange event will be fired asynchronously once it is inserted | |
// into the document. Do so, thus queuing up the task. Remember to clean up once it's been called. | |
var script = doc.createElement("script"); | |
script.onreadystatechange = function () { | |
runIfPresent(handle); | |
script.onreadystatechange = null; | |
html.removeChild(script); | |
script = null; | |
}; | |
html.appendChild(script); | |
}; | |
} | |
function installSetTimeoutImplementation() { | |
registerImmediate = function(handle) { | |
setTimeout(runIfPresent, 0, handle); | |
}; | |
} | |
// If supported, we should attach to the prototype of global, since that is where setTimeout et al. live. | |
var attachTo = Object.getPrototypeOf && Object.getPrototypeOf(global); | |
attachTo = attachTo && attachTo.setTimeout ? attachTo : global; | |
// Don't get fooled by e.g. browserify environments. | |
if ({}.toString.call(global.process) === "[object process]") { | |
// For Node.js before 0.9 | |
installNextTickImplementation(); | |
} else if (canUsePostMessage()) { | |
// For non-IE10 modern browsers | |
installPostMessageImplementation(); | |
} else if (global.MessageChannel) { | |
// For web workers, where supported | |
installMessageChannelImplementation(); | |
} else if (doc && "onreadystatechange" in doc.createElement("script")) { | |
// For IE 6–8 | |
installReadyStateChangeImplementation(); | |
} else { | |
// For older browsers | |
installSetTimeoutImplementation(); | |
} | |
attachTo.setImmediate = setImmediate; | |
attachTo.clearImmediate = clearImmediate; | |
}(typeof self === "undefined" ? typeof commonjsGlobal === "undefined" ? commonjsGlobal : commonjsGlobal : self)); | |
var sleep_1 = createCommonjsModule(function (module, exports) { | |
// Generated by LiveScript 1.6.0 | |
var sleep, clearTimer, out$ = exports || commonjsGlobal; | |
out$.sleep = sleep = function(ms, f){ | |
return setTimeout(f, ms); | |
}; | |
out$.clearTimer = clearTimer = function(x){ | |
return clearInterval(x); | |
}; | |
}); | |
var isBrowser = typeof window !== 'undefined'; | |
var environment = { | |
isBrowser: isBrowser | |
}; | |
var Processor = function Processor(options){ | |
this.selfOptions = options || {}; | |
this.pipes = {}; | |
}; | |
Processor.prototype.options = function(options) { | |
if (options) { | |
this.selfOptions = options; | |
} | |
return this.selfOptions; | |
}; | |
Processor.prototype.pipe = function(name, pipe) { | |
if (typeof name === 'string') { | |
if (typeof pipe === 'undefined') { | |
return this.pipes[name]; | |
} else { | |
this.pipes[name] = pipe; | |
} | |
} | |
if (name && name.name) { | |
pipe = name; | |
if (pipe.processor === this) { return pipe; } | |
this.pipes[pipe.name] = pipe; | |
} | |
pipe.processor = this; | |
return pipe; | |
}; | |
Processor.prototype.process = function(input, pipe) { | |
var context = input; | |
context.options = this.options(); | |
var nextPipe = pipe || input.pipe || 'default'; | |
var lastPipe, lastContext; | |
while (nextPipe) { | |
if (typeof context.nextAfterChildren !== 'undefined') { | |
// children processed and coming back to parent | |
context.next = context.nextAfterChildren; | |
context.nextAfterChildren = null; | |
} | |
if (typeof nextPipe === 'string') { | |
nextPipe = this.pipe(nextPipe); | |
} | |
nextPipe.process(context); | |
lastContext = context; | |
lastPipe = nextPipe; | |
nextPipe = null; | |
if (context) { | |
if (context.next) { | |
context = context.next; | |
nextPipe = lastContext.nextPipe || context.pipe || lastPipe; | |
} | |
} | |
} | |
return context.hasResult ? context.result : undefined; | |
}; | |
var Processor_1 = Processor; | |
var processor = { | |
Processor: Processor_1 | |
}; | |
var Pipe = function Pipe(name) { | |
this.name = name; | |
this.filters = []; | |
}; | |
Pipe.prototype.process = function(input) { | |
if (!this.processor) { | |
throw new Error('add this pipe to a processor before using it'); | |
} | |
var debug = this.debug; | |
var length = this.filters.length; | |
var context = input; | |
for (var index = 0; index < length; index++) { | |
var filter = this.filters[index]; | |
if (debug) { | |
this.log('filter: ' + filter.filterName); | |
} | |
filter(context); | |
if (typeof context === 'object' && context.exiting) { | |
context.exiting = false; | |
break; | |
} | |
} | |
if (!context.next && this.resultCheck) { | |
this.resultCheck(context); | |
} | |
}; | |
Pipe.prototype.log = function(msg) { | |
console.log('[jsondiffpatch] ' + this.name + ' pipe, ' + msg); | |
}; | |
Pipe.prototype.append = function() { | |
this.filters.push.apply(this.filters, arguments); | |
return this; | |
}; | |
Pipe.prototype.prepend = function() { | |
this.filters.unshift.apply(this.filters, arguments); | |
return this; | |
}; | |
Pipe.prototype.indexOf = function(filterName) { | |
if (!filterName) { | |
throw new Error('a filter name is required'); | |
} | |
for (var index = 0; index < this.filters.length; index++) { | |
var filter = this.filters[index]; | |
if (filter.filterName === filterName) { | |
return index; | |
} | |
} | |
throw new Error('filter not found: ' + filterName); | |
}; | |
Pipe.prototype.list = function() { | |
var names = []; | |
for (var index = 0; index < this.filters.length; index++) { | |
var filter = this.filters[index]; | |
names.push(filter.filterName); | |
} | |
return names; | |
}; | |
Pipe.prototype.after = function(filterName) { | |
var index = this.indexOf(filterName); | |
var params = Array.prototype.slice.call(arguments, 1); | |
if (!params.length) { | |
throw new Error('a filter is required'); | |
} | |
params.unshift(index + 1, 0); | |
Array.prototype.splice.apply(this.filters, params); | |
return this; | |
}; | |
Pipe.prototype.before = function(filterName) { | |
var index = this.indexOf(filterName); | |
var params = Array.prototype.slice.call(arguments, 1); | |
if (!params.length) { | |
throw new Error('a filter is required'); | |
} | |
params.unshift(index, 0); | |
Array.prototype.splice.apply(this.filters, params); | |
return this; | |
}; | |
Pipe.prototype.replace = function(filterName) { | |
var index = this.indexOf(filterName); | |
var params = Array.prototype.slice.call(arguments, 1); | |
if (!params.length) { | |
throw new Error('a filter is required'); | |
} | |
params.unshift(index, 1); | |
Array.prototype.splice.apply(this.filters, params); | |
return this; | |
}; | |
Pipe.prototype.remove = function(filterName) { | |
var index = this.indexOf(filterName); | |
this.filters.splice(index, 1); | |
return this; | |
}; | |
Pipe.prototype.clear = function() { | |
this.filters.length = 0; | |
return this; | |
}; | |
Pipe.prototype.shouldHaveResult = function(should) { | |
if (should === false) { | |
this.resultCheck = null; | |
return; | |
} | |
if (this.resultCheck) { | |
return; | |
} | |
var pipe = this; | |
this.resultCheck = function(context) { | |
if (!context.hasResult) { | |
console.log(context); | |
var error = new Error(pipe.name + ' failed'); | |
error.noResult = true; | |
throw error; | |
} | |
}; | |
return this; | |
}; | |
var Pipe_1 = Pipe; | |
var pipe = { | |
Pipe: Pipe_1 | |
}; | |
var Pipe$1 = pipe.Pipe; | |
var Context = function Context(){ | |
}; | |
Context.prototype.setResult = function(result) { | |
this.result = result; | |
this.hasResult = true; | |
return this; | |
}; | |
Context.prototype.exit = function() { | |
this.exiting = true; | |
return this; | |
}; | |
Context.prototype.switchTo = function(next, pipe) { | |
if (typeof next === 'string' || next instanceof Pipe$1) { | |
this.nextPipe = next; | |
} else { | |
this.next = next; | |
if (pipe) { | |
this.nextPipe = pipe; | |
} | |
} | |
return this; | |
}; | |
Context.prototype.push = function(child, name) { | |
child.parent = this; | |
if (typeof name !== 'undefined') { | |
child.childName = name; | |
} | |
child.root = this.root || this; | |
child.options = child.options || this.options; | |
if (!this.children) { | |
this.children = [child]; | |
this.nextAfterChildren = this.next || null; | |
this.next = child; | |
} else { | |
this.children[this.children.length - 1].next = child; | |
this.children.push(child); | |
} | |
child.next = this; | |
return this; | |
}; | |
var Context_1 = Context; | |
var context = { | |
Context: Context_1 | |
}; | |
var isArray = (typeof Array.isArray === 'function') ? | |
// use native function | |
Array.isArray : | |
// use instanceof operator | |
function(a) { | |
return a instanceof Array; | |
}; | |
function cloneRegExp(re) { | |
var regexMatch = /^\/(.*)\/([gimyu]*)$/.exec(re.toString()); | |
return new RegExp(regexMatch[1], regexMatch[2]); | |
} | |
function clone(arg) { | |
if (typeof arg !== 'object') { | |
return arg; | |
} | |
if (arg === null) { | |
return null; | |
} | |
if (isArray(arg)) { | |
return arg.map(clone); | |
} | |
if (arg instanceof Date) { | |
return new Date(arg.getTime()); | |
} | |
if (arg instanceof RegExp) { | |
return cloneRegExp(arg); | |
} | |
var cloned = {}; | |
for (var name in arg) { | |
if (Object.prototype.hasOwnProperty.call(arg, name)) { | |
cloned[name] = clone(arg[name]); | |
} | |
} | |
return cloned; | |
} | |
var clone_1 = clone; | |
var Context$1 = context.Context; | |
var DiffContext = function DiffContext(left, right) { | |
this.left = left; | |
this.right = right; | |
this.pipe = 'diff'; | |
}; | |
DiffContext.prototype = new Context$1(); | |
DiffContext.prototype.setResult = function(result) { | |
if (this.options.cloneDiffValues && typeof result === 'object') { | |
var clone = typeof this.options.cloneDiffValues === 'function' ? | |
this.options.cloneDiffValues : clone_1; | |
if (typeof result[0] === 'object') { | |
result[0] = clone(result[0]); | |
} | |
if (typeof result[1] === 'object') { | |
result[1] = clone(result[1]); | |
} | |
} | |
return Context$1.prototype.setResult.apply(this, arguments); | |
}; | |
var DiffContext_1 = DiffContext; | |
var diff = { | |
DiffContext: DiffContext_1 | |
}; | |
var Context$2 = context.Context; | |
var PatchContext = function PatchContext(left, delta) { | |
this.left = left; | |
this.delta = delta; | |
this.pipe = 'patch'; | |
}; | |
PatchContext.prototype = new Context$2(); | |
var PatchContext_1 = PatchContext; | |
var patch = { | |
PatchContext: PatchContext_1 | |
}; | |
var Context$3 = context.Context; | |
var ReverseContext = function ReverseContext(delta) { | |
this.delta = delta; | |
this.pipe = 'reverse'; | |
}; | |
ReverseContext.prototype = new Context$3(); | |
var ReverseContext_1 = ReverseContext; | |
var reverse$2 = { | |
ReverseContext: ReverseContext_1 | |
}; | |
var isArray$1 = (typeof Array.isArray === 'function') ? | |
// use native function | |
Array.isArray : | |
// use instanceof operator | |
function(a) { | |
return a instanceof Array; | |
}; | |
var diffFilter = function trivialMatchesDiffFilter(context) { | |
if (context.left === context.right) { | |
context.setResult(undefined).exit(); | |
return; | |
} | |
if (typeof context.left === 'undefined') { | |
if (typeof context.right === 'function') { | |
throw new Error('functions are not supported'); | |
} | |
context.setResult([context.right]).exit(); | |
return; | |
} | |
if (typeof context.right === 'undefined') { | |
context.setResult([context.left, 0, 0]).exit(); | |
return; | |
} | |
if (typeof context.left === 'function' || typeof context.right === 'function') { | |
throw new Error('functions are not supported'); | |
} | |
context.leftType = context.left === null ? 'null' : typeof context.left; | |
context.rightType = context.right === null ? 'null' : typeof context.right; | |
if (context.leftType !== context.rightType) { | |
context.setResult([context.left, context.right]).exit(); | |
return; | |
} | |
if (context.leftType === 'boolean' || context.leftType === 'number') { | |
context.setResult([context.left, context.right]).exit(); | |
return; | |
} | |
if (context.leftType === 'object') { | |
context.leftIsArray = isArray$1(context.left); | |
} | |
if (context.rightType === 'object') { | |
context.rightIsArray = isArray$1(context.right); | |
} | |
if (context.leftIsArray !== context.rightIsArray) { | |
context.setResult([context.left, context.right]).exit(); | |
return; | |
} | |
if (context.left instanceof RegExp) { | |
if (context.right instanceof RegExp) { | |
context.setResult([context.left.toString(), context.right.toString()]).exit(); | |
} else { | |
context.setResult([context.left, context.right]).exit(); | |
return; | |
} | |
} | |
}; | |
diffFilter.filterName = 'trivial'; | |
var patchFilter = function trivialMatchesPatchFilter(context) { | |
if (typeof context.delta === 'undefined') { | |
context.setResult(context.left).exit(); | |
return; | |
} | |
context.nested = !isArray$1(context.delta); | |
if (context.nested) { | |
return; | |
} | |
if (context.delta.length === 1) { | |
context.setResult(context.delta[0]).exit(); | |
return; | |
} | |
if (context.delta.length === 2) { | |
if (context.left instanceof RegExp) { | |
var regexArgs = /^\/(.*)\/([gimyu]+)$/.exec(context.delta[1]); | |
if (regexArgs) { | |
context.setResult(new RegExp(regexArgs[1], regexArgs[2])).exit(); | |
return; | |
} | |
} | |
context.setResult(context.delta[1]).exit(); | |
return; | |
} | |
if (context.delta.length === 3 && context.delta[2] === 0) { | |
context.setResult(undefined).exit(); | |
return; | |
} | |
}; | |
patchFilter.filterName = 'trivial'; | |
var reverseFilter = function trivialReferseFilter(context) { | |
if (typeof context.delta === 'undefined') { | |
context.setResult(context.delta).exit(); | |
return; | |
} | |
context.nested = !isArray$1(context.delta); | |
if (context.nested) { | |
return; | |
} | |
if (context.delta.length === 1) { | |
context.setResult([context.delta[0], 0, 0]).exit(); | |
return; | |
} | |
if (context.delta.length === 2) { | |
context.setResult([context.delta[1], context.delta[0]]).exit(); | |
return; | |
} | |
if (context.delta.length === 3 && context.delta[2] === 0) { | |
context.setResult([context.delta[0]]).exit(); | |
return; | |
} | |
}; | |
reverseFilter.filterName = 'trivial'; | |
var diffFilter_1 = diffFilter; | |
var patchFilter_1 = patchFilter; | |
var reverseFilter_1 = reverseFilter; | |
var trivial = { | |
diffFilter: diffFilter_1, | |
patchFilter: patchFilter_1, | |
reverseFilter: reverseFilter_1 | |
}; | |
var DiffContext$1 = diff.DiffContext; | |
var PatchContext$1 = patch.PatchContext; | |
var ReverseContext$1 = reverse$2.ReverseContext; | |
var collectChildrenDiffFilter = function collectChildrenDiffFilter(context) { | |
if (!context || !context.children) { | |
return; | |
} | |
var length = context.children.length; | |
var child; | |
var result = context.result; | |
for (var index = 0; index < length; index++) { | |
child = context.children[index]; | |
if (typeof child.result === 'undefined') { | |
continue; | |
} | |
result = result || {}; | |
result[child.childName] = child.result; | |
} | |
if (result && context.leftIsArray) { | |
result._t = 'a'; | |
} | |
context.setResult(result).exit(); | |
}; | |
collectChildrenDiffFilter.filterName = 'collectChildren'; | |
var objectsDiffFilter = function objectsDiffFilter(context) { | |
if (context.leftIsArray || context.leftType !== 'object') { | |
return; | |
} | |
var name, child, propertyFilter = context.options.propertyFilter; | |
for (name in context.left) { | |
if (!Object.prototype.hasOwnProperty.call(context.left, name)) { | |
continue; | |
} | |
if (propertyFilter && !propertyFilter(name, context)) { | |
continue; | |
} | |
child = new DiffContext$1(context.left[name], context.right[name]); | |
context.push(child, name); | |
} | |
for (name in context.right) { | |
if (!Object.prototype.hasOwnProperty.call(context.right, name)) { | |
continue; | |
} | |
if (propertyFilter && !propertyFilter(name, context)) { | |
continue; | |
} | |
if (typeof context.left[name] === 'undefined') { | |
child = new DiffContext$1(undefined, context.right[name]); | |
context.push(child, name); | |
} | |
} | |
if (!context.children || context.children.length === 0) { | |
context.setResult(undefined).exit(); | |
return; | |
} | |
context.exit(); | |
}; | |
objectsDiffFilter.filterName = 'objects'; | |
var patchFilter$1 = function nestedPatchFilter(context) { | |
if (!context.nested) { | |
return; | |
} | |
if (context.delta._t) { | |
return; | |
} | |
var name, child; | |
for (name in context.delta) { | |
child = new PatchContext$1(context.left[name], context.delta[name]); | |
context.push(child, name); | |
} | |
context.exit(); | |
}; | |
patchFilter$1.filterName = 'objects'; | |
var collectChildrenPatchFilter = function collectChildrenPatchFilter(context) { | |
if (!context || !context.children) { | |
return; | |
} | |
if (context.delta._t) { | |
return; | |
} | |
var length = context.children.length; | |
var child; | |
for (var index = 0; index < length; index++) { | |
child = context.children[index]; | |
if (Object.prototype.hasOwnProperty.call(context.left, child.childName) && child.result === undefined) { | |
delete context.left[child.childName]; | |
} else if (context.left[child.childName] !== child.result) { | |
context.left[child.childName] = child.result; | |
} | |
} | |
context.setResult(context.left).exit(); | |
}; | |
collectChildrenPatchFilter.filterName = 'collectChildren'; | |
var reverseFilter$1 = function nestedReverseFilter(context) { | |
if (!context.nested) { | |
return; | |
} | |
if (context.delta._t) { | |
return; | |
} | |
var name, child; | |
for (name in context.delta) { | |
child = new ReverseContext$1(context.delta[name]); | |
context.push(child, name); | |
} | |
context.exit(); | |
}; | |
reverseFilter$1.filterName = 'objects'; | |
var collectChildrenReverseFilter = function collectChildrenReverseFilter(context) { | |
if (!context || !context.children) { | |
return; | |
} | |
if (context.delta._t) { | |
return; | |
} | |
var length = context.children.length; | |
var child; | |
var delta = {}; | |
for (var index = 0; index < length; index++) { | |
child = context.children[index]; | |
if (delta[child.childName] !== child.result) { | |
delta[child.childName] = child.result; | |
} | |
} | |
context.setResult(delta).exit(); | |
}; | |
collectChildrenReverseFilter.filterName = 'collectChildren'; | |
var collectChildrenDiffFilter_1 = collectChildrenDiffFilter; | |
var objectsDiffFilter_1 = objectsDiffFilter; | |
var patchFilter_1$1 = patchFilter$1; | |
var collectChildrenPatchFilter_1 = collectChildrenPatchFilter; | |
var reverseFilter_1$1 = reverseFilter$1; | |
var collectChildrenReverseFilter_1 = collectChildrenReverseFilter; | |
var nested = { | |
collectChildrenDiffFilter: collectChildrenDiffFilter_1, | |
objectsDiffFilter: objectsDiffFilter_1, | |
patchFilter: patchFilter_1$1, | |
collectChildrenPatchFilter: collectChildrenPatchFilter_1, | |
reverseFilter: reverseFilter_1$1, | |
collectChildrenReverseFilter: collectChildrenReverseFilter_1 | |
}; | |
/* | |
LCS implementation that supports arrays or strings | |
reference: http://en.wikipedia.org/wiki/Longest_common_subsequence_problem | |
*/ | |
var defaultMatch = function(array1, array2, index1, index2) { | |
return array1[index1] === array2[index2]; | |
}; | |
var lengthMatrix = function(array1, array2, match, context) { | |
var len1 = array1.length; | |
var len2 = array2.length; | |
var x, y; | |
// initialize empty matrix of len1+1 x len2+1 | |
var matrix = [len1 + 1]; | |
for (x = 0; x < len1 + 1; x++) { | |
matrix[x] = [len2 + 1]; | |
for (y = 0; y < len2 + 1; y++) { | |
matrix[x][y] = 0; | |
} | |
} | |
matrix.match = match; | |
// save sequence lengths for each coordinate | |
for (x = 1; x < len1 + 1; x++) { | |
for (y = 1; y < len2 + 1; y++) { | |
if (match(array1, array2, x - 1, y - 1, context)) { | |
matrix[x][y] = matrix[x - 1][y - 1] + 1; | |
} else { | |
matrix[x][y] = Math.max(matrix[x - 1][y], matrix[x][y - 1]); | |
} | |
} | |
} | |
return matrix; | |
}; | |
var backtrack = function(matrix, array1, array2, index1, index2, context) { | |
if (index1 === 0 || index2 === 0) { | |
return { | |
sequence: [], | |
indices1: [], | |
indices2: [] | |
}; | |
} | |
if (matrix.match(array1, array2, index1 - 1, index2 - 1, context)) { | |
var subsequence = backtrack(matrix, array1, array2, index1 - 1, index2 - 1, context); | |
subsequence.sequence.push(array1[index1 - 1]); | |
subsequence.indices1.push(index1 - 1); | |
subsequence.indices2.push(index2 - 1); | |
return subsequence; | |
} | |
if (matrix[index1][index2 - 1] > matrix[index1 - 1][index2]) { | |
return backtrack(matrix, array1, array2, index1, index2 - 1, context); | |
} else { | |
return backtrack(matrix, array1, array2, index1 - 1, index2, context); | |
} | |
}; | |
var get = function(array1, array2, match, context) { | |
context = context || {}; | |
var matrix = lengthMatrix(array1, array2, match || defaultMatch, context); | |
var result = backtrack(matrix, array1, array2, array1.length, array2.length, context); | |
if (typeof array1 === 'string' && typeof array2 === 'string') { | |
result.sequence = result.sequence.join(''); | |
} | |
return result; | |
}; | |
var get_1 = get; | |
var lcs = { | |
get: get_1 | |
}; | |
var DiffContext$2 = diff.DiffContext; | |
var PatchContext$2 = patch.PatchContext; | |
var ReverseContext$2 = reverse$2.ReverseContext; | |
var ARRAY_MOVE = 3; | |
var isArray$2 = (typeof Array.isArray === 'function') ? | |
// use native function | |
Array.isArray : | |
// use instanceof operator | |
function(a) { | |
return a instanceof Array; | |
}; | |
var arrayIndexOf = typeof Array.prototype.indexOf === 'function' ? | |
function(array, item) { | |
return array.indexOf(item); | |
} : function(array, item) { | |
var length = array.length; | |
for (var i = 0; i < length; i++) { | |
if (array[i] === item) { | |
return i; | |
} | |
} | |
return -1; | |
}; | |
function arraysHaveMatchByRef(array1, array2, len1, len2) { | |
for (var index1 = 0; index1 < len1; index1++) { | |
var val1 = array1[index1]; | |
for (var index2 = 0; index2 < len2; index2++) { | |
var val2 = array2[index2]; | |
if (index1 !== index2 && val1 === val2) { | |
return true; | |
} | |
} | |
} | |
} | |
function matchItems(array1, array2, index1, index2, context) { | |
var value1 = array1[index1]; | |
var value2 = array2[index2]; | |
if (value1 === value2) { | |
return true; | |
} | |
if (typeof value1 !== 'object' || typeof value2 !== 'object') { | |
return false; | |
} | |
var objectHash = context.objectHash; | |
if (!objectHash) { | |
// no way to match objects was provided, try match by position | |
return context.matchByPosition && index1 === index2; | |
} | |
var hash1; | |
var hash2; | |
if (typeof index1 === 'number') { | |
context.hashCache1 = context.hashCache1 || []; | |
hash1 = context.hashCache1[index1]; | |
if (typeof hash1 === 'undefined') { | |
context.hashCache1[index1] = hash1 = objectHash(value1, index1); | |
} | |
} else { | |
hash1 = objectHash(value1); | |
} | |
if (typeof hash1 === 'undefined') { | |
return false; | |
} | |
if (typeof index2 === 'number') { | |
context.hashCache2 = context.hashCache2 || []; | |
hash2 = context.hashCache2[index2]; | |
if (typeof hash2 === 'undefined') { | |
context.hashCache2[index2] = hash2 = objectHash(value2, index2); | |
} | |
} else { | |
hash2 = objectHash(value2); | |
} | |
if (typeof hash2 === 'undefined') { | |
return false; | |
} | |
return hash1 === hash2; | |
} | |
var diffFilter$1 = function arraysDiffFilter(context) { | |
if (!context.leftIsArray) { | |
return; | |
} | |
var matchContext = { | |
objectHash: context.options && context.options.objectHash, | |
matchByPosition: context.options && context.options.matchByPosition | |
}; | |
var commonHead = 0; | |
var commonTail = 0; | |
var index; | |
var index1; | |
var index2; | |
var array1 = context.left; | |
var array2 = context.right; | |
var len1 = array1.length; | |
var len2 = array2.length; | |
var child; | |
if (len1 > 0 && len2 > 0 && !matchContext.objectHash && | |
typeof matchContext.matchByPosition !== 'boolean') { | |
matchContext.matchByPosition = !arraysHaveMatchByRef(array1, array2, len1, len2); | |
} | |
// separate common head | |
while (commonHead < len1 && commonHead < len2 && | |
matchItems(array1, array2, commonHead, commonHead, matchContext)) { | |
index = commonHead; | |
child = new DiffContext$2(context.left[index], context.right[index]); | |
context.push(child, index); | |
commonHead++; | |
} | |
// separate common tail | |
while (commonTail + commonHead < len1 && commonTail + commonHead < len2 && | |
matchItems(array1, array2, len1 - 1 - commonTail, len2 - 1 - commonTail, matchContext)) { | |
index1 = len1 - 1 - commonTail; | |
index2 = len2 - 1 - commonTail; | |
child = new DiffContext$2(context.left[index1], context.right[index2]); | |
context.push(child, index2); | |
commonTail++; | |
} | |
var result; | |
if (commonHead + commonTail === len1) { | |
if (len1 === len2) { | |
// arrays are identical | |
context.setResult(undefined).exit(); | |
return; | |
} | |
// trivial case, a block (1 or more consecutive items) was added | |
result = result || { | |
_t: 'a' | |
}; | |
for (index = commonHead; index < len2 - commonTail; index++) { | |
result[index] = [array2[index]]; | |
} | |
context.setResult(result).exit(); | |
return; | |
} | |
if (commonHead + commonTail === len2) { | |
// trivial case, a block (1 or more consecutive items) was removed | |
result = result || { | |
_t: 'a' | |
}; | |
for (index = commonHead; index < len1 - commonTail; index++) { | |
result['_' + index] = [array1[index], 0, 0]; | |
} | |
context.setResult(result).exit(); | |
return; | |
} | |
// reset hash cache | |
delete matchContext.hashCache1; | |
delete matchContext.hashCache2; | |
// diff is not trivial, find the LCS (Longest Common Subsequence) | |
var trimmed1 = array1.slice(commonHead, len1 - commonTail); | |
var trimmed2 = array2.slice(commonHead, len2 - commonTail); | |
var seq = lcs.get( | |
trimmed1, trimmed2, | |
matchItems, | |
matchContext | |
); | |
var removedItems = []; | |
result = result || { | |
_t: 'a' | |
}; | |
for (index = commonHead; index < len1 - commonTail; index++) { | |
if (arrayIndexOf(seq.indices1, index - commonHead) < 0) { | |
// removed | |
result['_' + index] = [array1[index], 0, 0]; | |
removedItems.push(index); | |
} | |
} | |
var detectMove = true; | |
if (context.options && context.options.arrays && context.options.arrays.detectMove === false) { | |
detectMove = false; | |
} | |
var includeValueOnMove = false; | |
if (context.options && context.options.arrays && context.options.arrays.includeValueOnMove) { | |
includeValueOnMove = true; | |
} | |
var removedItemsLength = removedItems.length; | |
for (index = commonHead; index < len2 - commonTail; index++) { | |
var indexOnArray2 = arrayIndexOf(seq.indices2, index - commonHead); | |
if (indexOnArray2 < 0) { | |
// added, try to match with a removed item and register as position move | |
var isMove = false; | |
if (detectMove && removedItemsLength > 0) { | |
for (var removeItemIndex1 = 0; removeItemIndex1 < removedItemsLength; removeItemIndex1++) { | |
index1 = removedItems[removeItemIndex1]; | |
if (matchItems(trimmed1, trimmed2, index1 - commonHead, | |
index - commonHead, matchContext)) { | |
// store position move as: [originalValue, newPosition, ARRAY_MOVE] | |
result['_' + index1].splice(1, 2, index, ARRAY_MOVE); | |
if (!includeValueOnMove) { | |
// don't include moved value on diff, to save bytes | |
result['_' + index1][0] = ''; | |
} | |
index2 = index; | |
child = new DiffContext$2(context.left[index1], context.right[index2]); | |
context.push(child, index2); | |
removedItems.splice(removeItemIndex1, 1); | |
isMove = true; | |
break; | |
} | |
} | |
} | |
if (!isMove) { | |
// added | |
result[index] = [array2[index]]; | |
} | |
} else { | |
// match, do inner diff | |
index1 = seq.indices1[indexOnArray2] + commonHead; | |
index2 = seq.indices2[indexOnArray2] + commonHead; | |
child = new DiffContext$2(context.left[index1], context.right[index2]); | |
context.push(child, index2); | |
} | |
} | |
context.setResult(result).exit(); | |
}; | |
diffFilter$1.filterName = 'arrays'; | |
var compare = { | |
numerically: function(a, b) { | |
return a - b; | |
}, | |
numericallyBy: function(name) { | |
return function(a, b) { | |
return a[name] - b[name]; | |
}; | |
} | |
}; | |
var patchFilter$2 = function nestedPatchFilter(context) { | |
if (!context.nested) { | |
return; | |
} | |
if (context.delta._t !== 'a') { | |
return; | |
} | |
var index, index1; | |
var delta = context.delta; | |
var array = context.left; | |
// first, separate removals, insertions and modifications | |
var toRemove = []; | |
var toInsert = []; | |
var toModify = []; | |
for (index in delta) { | |
if (index !== '_t') { | |
if (index[0] === '_') { | |
// removed item from original array | |
if (delta[index][2] === 0 || delta[index][2] === ARRAY_MOVE) { | |
toRemove.push(parseInt(index.slice(1), 10)); | |
} else { | |
throw new Error('only removal or move can be applied at original array indices' + | |
', invalid diff type: ' + delta[index][2]); | |
} | |
} else { | |
if (delta[index].length === 1) { | |
// added item at new array | |
toInsert.push({ | |
index: parseInt(index, 10), | |
value: delta[index][0] | |
}); | |
} else { | |
// modified item at new array | |
toModify.push({ | |
index: parseInt(index, 10), | |
delta: delta[index] | |
}); | |
} | |
} | |
} | |
} | |
// remove items, in reverse order to avoid sawing our own floor | |
toRemove = toRemove.sort(compare.numerically); | |
for (index = toRemove.length - 1; index >= 0; index--) { | |
index1 = toRemove[index]; | |
var indexDiff = delta['_' + index1]; | |
var removedValue = array.splice(index1, 1)[0]; | |
if (indexDiff[2] === ARRAY_MOVE) { | |
// reinsert later | |
toInsert.push({ | |
index: indexDiff[1], | |
value: removedValue | |
}); | |
} | |
} | |
// insert items, in reverse order to avoid moving our own floor | |
toInsert = toInsert.sort(compare.numericallyBy('index')); | |
var toInsertLength = toInsert.length; | |
for (index = 0; index < toInsertLength; index++) { | |
var insertion = toInsert[index]; | |
array.splice(insertion.index, 0, insertion.value); | |
} | |
// apply modifications | |
var toModifyLength = toModify.length; | |
var child; | |
if (toModifyLength > 0) { | |
for (index = 0; index < toModifyLength; index++) { | |
var modification = toModify[index]; | |
child = new PatchContext$2(context.left[modification.index], modification.delta); | |
context.push(child, modification.index); | |
} | |
} | |
if (!context.children) { | |
context.setResult(context.left).exit(); | |
return; | |
} | |
context.exit(); | |
}; | |
patchFilter$2.filterName = 'arrays'; | |
var collectChildrenPatchFilter$1 = function collectChildrenPatchFilter(context) { | |
if (!context || !context.children) { | |
return; | |
} | |
if (context.delta._t !== 'a') { | |
return; | |
} | |
var length = context.children.length; | |
var child; | |
for (var index = 0; index < length; index++) { | |
child = context.children[index]; | |
context.left[child.childName] = child.result; | |
} | |
context.setResult(context.left).exit(); | |
}; | |
collectChildrenPatchFilter$1.filterName = 'arraysCollectChildren'; | |
var reverseFilter$2 = function arraysReverseFilter(context) { | |
if (!context.nested) { | |
if (context.delta[2] === ARRAY_MOVE) { | |
context.newName = '_' + context.delta[1]; | |
context.setResult([context.delta[0], parseInt(context.childName.substr(1), 10), ARRAY_MOVE]).exit(); | |
} | |
return; | |
} | |
if (context.delta._t !== 'a') { | |
return; | |
} | |
var name, child; | |
for (name in context.delta) { | |
if (name === '_t') { | |
continue; | |
} | |
child = new ReverseContext$2(context.delta[name]); | |
context.push(child, name); | |
} | |
context.exit(); | |
}; | |
reverseFilter$2.filterName = 'arrays'; | |
var reverseArrayDeltaIndex = function(delta, index, itemDelta) { | |
if (typeof index === 'string' && index[0] === '_') { | |
return parseInt(index.substr(1), 10); | |
} else if (isArray$2(itemDelta) && itemDelta[2] === 0) { | |
return '_' + index; | |
} | |
var reverseIndex = +index; | |
for (var deltaIndex in delta) { | |
var deltaItem = delta[deltaIndex]; | |
if (isArray$2(deltaItem)) { | |
if (deltaItem[2] === ARRAY_MOVE) { | |
var moveFromIndex = parseInt(deltaIndex.substr(1), 10); | |
var moveToIndex = deltaItem[1]; | |
if (moveToIndex === +index) { | |
return moveFromIndex; | |
} | |
if (moveFromIndex <= reverseIndex && moveToIndex > reverseIndex) { | |
reverseIndex++; | |
} else if (moveFromIndex >= reverseIndex && moveToIndex < reverseIndex) { | |
reverseIndex--; | |
} | |
} else if (deltaItem[2] === 0) { | |
var deleteIndex = parseInt(deltaIndex.substr(1), 10); | |
if (deleteIndex <= reverseIndex) { | |
reverseIndex++; | |
} | |
} else if (deltaItem.length === 1 && deltaIndex <= reverseIndex) { | |
reverseIndex--; | |
} | |
} | |
} | |
return reverseIndex; | |
}; | |
var collectChildrenReverseFilter$1 = function collectChildrenReverseFilter(context) { | |
if (!context || !context.children) { | |
return; | |
} | |
if (context.delta._t !== 'a') { | |
return; | |
} | |
var length = context.children.length; | |
var child; | |
var delta = { | |
_t: 'a' | |
}; | |
for (var index = 0; index < length; index++) { | |
child = context.children[index]; | |
var name = child.newName; | |
if (typeof name === 'undefined') { | |
name = reverseArrayDeltaIndex(context.delta, child.childName, child.result); | |
} | |
if (delta[name] !== child.result) { | |
delta[name] = child.result; | |
} | |
} | |
context.setResult(delta).exit(); | |
}; | |
collectChildrenReverseFilter$1.filterName = 'arraysCollectChildren'; | |
var diffFilter_1$1 = diffFilter$1; | |
var patchFilter_1$2 = patchFilter$2; | |
var collectChildrenPatchFilter_1$1 = collectChildrenPatchFilter$1; | |
var reverseFilter_1$2 = reverseFilter$2; | |
var collectChildrenReverseFilter_1$1 = collectChildrenReverseFilter$1; | |
var arrays = { | |
diffFilter: diffFilter_1$1, | |
patchFilter: patchFilter_1$2, | |
collectChildrenPatchFilter: collectChildrenPatchFilter_1$1, | |
reverseFilter: reverseFilter_1$2, | |
collectChildrenReverseFilter: collectChildrenReverseFilter_1$1 | |
}; | |
var diffFilter$2 = function datesDiffFilter(context) { | |
if (context.left instanceof Date) { | |
if (context.right instanceof Date) { | |
if (context.left.getTime() !== context.right.getTime()) { | |
context.setResult([context.left, context.right]); | |
} else { | |
context.setResult(undefined); | |
} | |
} else { | |
context.setResult([context.left, context.right]); | |
} | |
context.exit(); | |
} else if (context.right instanceof Date) { | |
context.setResult([context.left, context.right]).exit(); | |
} | |
}; | |
diffFilter$2.filterName = 'dates'; | |
var diffFilter_1$2 = diffFilter$2; | |
var dates = { | |
diffFilter: diffFilter_1$2 | |
}; | |
/* global diff_match_patch */ | |
var TEXT_DIFF = 2; | |
var DEFAULT_MIN_LENGTH = 60; | |
var cachedDiffPatch = null; | |
var getDiffMatchPatch = function(required) { | |
/*jshint camelcase: false */ | |
if (!cachedDiffPatch) { | |
var instance; | |
if (typeof diff_match_patch !== 'undefined') { | |
// already loaded, probably a browser | |
instance = typeof diff_match_patch === 'function' ? | |
new diff_match_patch() : new diff_match_patch.diff_match_patch(); | |
} else if (typeof commonjsRequire === 'function') { | |
try { | |
var dmpModuleName = 'diff_match_patch_uncompressed'; | |
var dmp = commonjsRequire('../../public/external/' + dmpModuleName); | |
instance = new dmp.diff_match_patch(); | |
} catch (err) { | |
instance = null; | |
} | |
} | |
if (!instance) { | |
if (!required) { | |
return null; | |
} | |
var error = new Error('text diff_match_patch library not found'); | |
error.diff_match_patch_not_found = true; | |
throw error; | |
} | |
cachedDiffPatch = { | |
diff: function(txt1, txt2) { | |
return instance.patch_toText(instance.patch_make(txt1, txt2)); | |
}, | |
patch: function(txt1, patch) { | |
var results = instance.patch_apply(instance.patch_fromText(patch), txt1); | |
for (var i = 0; i < results[1].length; i++) { | |
if (!results[1][i]) { | |
var error = new Error('text patch failed'); | |
error.textPatchFailed = true; | |
} | |
} | |
return results[0]; | |
} | |
}; | |
} | |
return cachedDiffPatch; | |
}; | |
var diffFilter$3 = function textsDiffFilter(context) { | |
if (context.leftType !== 'string') { | |
return; | |
} | |
var minLength = (context.options && context.options.textDiff && | |
context.options.textDiff.minLength) || DEFAULT_MIN_LENGTH; | |
if (context.left.length < minLength || | |
context.right.length < minLength) { | |
context.setResult([context.left, context.right]).exit(); | |
return; | |
} | |
// large text, try to use a text-diff algorithm | |
var diffMatchPatch = getDiffMatchPatch(); | |
if (!diffMatchPatch) { | |
// diff-match-patch library not available, fallback to regular string replace | |
context.setResult([context.left, context.right]).exit(); | |
return; | |
} | |
var diff = diffMatchPatch.diff; | |
context.setResult([diff(context.left, context.right), 0, TEXT_DIFF]).exit(); | |
}; | |
diffFilter$3.filterName = 'texts'; | |
var patchFilter$3 = function textsPatchFilter(context) { | |
if (context.nested) { | |
return; | |
} | |
if (context.delta[2] !== TEXT_DIFF) { | |
return; | |
} | |
// text-diff, use a text-patch algorithm | |
var patch = getDiffMatchPatch(true).patch; | |
context.setResult(patch(context.left, context.delta[0])).exit(); | |
}; | |
patchFilter$3.filterName = 'texts'; | |
var textDeltaReverse = function(delta) { | |
var i, l, lines, line, lineTmp, header = null, | |
headerRegex = /^@@ +\-(\d+),(\d+) +\+(\d+),(\d+) +@@$/, | |
lineHeader; | |
lines = delta.split('\n'); | |
for (i = 0, l = lines.length; i < l; i++) { | |
line = lines[i]; | |
var lineStart = line.slice(0, 1); | |
if (lineStart === '@') { | |
header = headerRegex.exec(line); | |
lineHeader = i; | |
// fix header | |
lines[lineHeader] = '@@ -' + header[3] + ',' + header[4] + ' +' + header[1] + ',' + header[2] + ' @@'; | |
} else if (lineStart === '+') { | |
lines[i] = '-' + lines[i].slice(1); | |
if (lines[i - 1].slice(0, 1) === '+') { | |
// swap lines to keep default order (-+) | |
lineTmp = lines[i]; | |
lines[i] = lines[i - 1]; | |
lines[i - 1] = lineTmp; | |
} | |
} else if (lineStart === '-') { | |
lines[i] = '+' + lines[i].slice(1); | |
} | |
} | |
return lines.join('\n'); | |
}; | |
var reverseFilter$3 = function textsReverseFilter(context) { | |
if (context.nested) { | |
return; | |
} | |
if (context.delta[2] !== TEXT_DIFF) { | |
return; | |
} | |
// text-diff, use a text-diff algorithm | |
context.setResult([textDeltaReverse(context.delta[0]), 0, TEXT_DIFF]).exit(); | |
}; | |
reverseFilter$3.filterName = 'texts'; | |
var diffFilter_1$3 = diffFilter$3; | |
var patchFilter_1$3 = patchFilter$3; | |
var reverseFilter_1$3 = reverseFilter$3; | |
var texts = { | |
diffFilter: diffFilter_1$3, | |
patchFilter: patchFilter_1$3, | |
reverseFilter: reverseFilter_1$3 | |
}; | |
var Processor$1 = processor.Processor; | |
var Pipe$2 = pipe.Pipe; | |
var DiffContext$3 = diff.DiffContext; | |
var PatchContext$3 = patch.PatchContext; | |
var ReverseContext$3 = reverse$2.ReverseContext; | |
var DiffPatcher = function DiffPatcher(options) { | |
this.processor = new Processor$1(options); | |
this.processor.pipe(new Pipe$2('diff').append( | |
nested.collectChildrenDiffFilter, | |
trivial.diffFilter, | |
dates.diffFilter, | |
texts.diffFilter, | |
nested.objectsDiffFilter, | |
arrays.diffFilter | |
).shouldHaveResult()); | |
this.processor.pipe(new Pipe$2('patch').append( | |
nested.collectChildrenPatchFilter, | |
arrays.collectChildrenPatchFilter, | |
trivial.patchFilter, | |
texts.patchFilter, | |
nested.patchFilter, | |
arrays.patchFilter | |
).shouldHaveResult()); | |
this.processor.pipe(new Pipe$2('reverse').append( | |
nested.collectChildrenReverseFilter, | |
arrays.collectChildrenReverseFilter, | |
trivial.reverseFilter, | |
texts.reverseFilter, | |
nested.reverseFilter, | |
arrays.reverseFilter | |
).shouldHaveResult()); | |
}; | |
DiffPatcher.prototype.options = function() { | |
return this.processor.options.apply(this.processor, arguments); | |
}; | |
DiffPatcher.prototype.diff = function(left, right) { | |
return this.processor.process(new DiffContext$3(left, right)); | |
}; | |
DiffPatcher.prototype.patch = function(left, delta) { | |
return this.processor.process(new PatchContext$3(left, delta)); | |
}; | |
DiffPatcher.prototype.reverse = function(delta) { | |
return this.processor.process(new ReverseContext$3(delta)); | |
}; | |
DiffPatcher.prototype.unpatch = function(right, delta) { | |
return this.patch(right, this.reverse(delta)); | |
}; | |
DiffPatcher.prototype.clone = function(value) { | |
return clone_1(value); | |
}; | |
var DiffPatcher_1 = DiffPatcher; | |
var diffpatcher = { | |
DiffPatcher: DiffPatcher_1 | |
}; | |
// use as 2nd parameter for JSON.parse to revive Date instances | |
var dateReviver = function dateReviver(key, value) { | |
var parts; | |
if (typeof value === 'string') { | |
parts = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.(\d*))?(Z|([+\-])(\d{2}):(\d{2}))$/.exec(value); | |
if (parts) { | |
return new Date(Date.UTC(+parts[1], +parts[2] - 1, +parts[3], +parts[4], +parts[5], +parts[6], +(parts[7] || 0))); | |
} | |
} | |
return value; | |
}; | |
var main = createCommonjsModule(function (module, exports) { | |
var DiffPatcher = diffpatcher.DiffPatcher; | |
exports.DiffPatcher = DiffPatcher; | |
exports.create = function(options){ | |
return new DiffPatcher(options); | |
}; | |
exports.dateReviver = dateReviver; | |
var defaultInstance; | |
exports.diff = function() { | |
if (!defaultInstance) { | |
defaultInstance = new DiffPatcher(); | |
} | |
return defaultInstance.diff.apply(defaultInstance, arguments); | |
}; | |
exports.patch = function() { | |
if (!defaultInstance) { | |
defaultInstance = new DiffPatcher(); | |
} | |
return defaultInstance.patch.apply(defaultInstance, arguments); | |
}; | |
exports.unpatch = function() { | |
if (!defaultInstance) { | |
defaultInstance = new DiffPatcher(); | |
} | |
return defaultInstance.unpatch.apply(defaultInstance, arguments); | |
}; | |
exports.reverse = function() { | |
if (!defaultInstance) { | |
defaultInstance = new DiffPatcher(); | |
} | |
return defaultInstance.reverse.apply(defaultInstance, arguments); | |
}; | |
exports.clone = function() { | |
if (!defaultInstance) { | |
defaultInstance = new DiffPatcher(); | |
} | |
return defaultInstance.clone.apply(defaultInstance, arguments); | |
}; | |
if (environment.isBrowser) { | |
exports.homepage = '{{package-homepage}}'; | |
exports.version = '{{package-version}}'; | |
} else { | |
var packageInfo = commonjsRequire(); | |
exports.homepage = packageInfo.homepage; | |
exports.version = packageInfo.version; | |
var formatters = commonjsRequire(); | |
exports.formatters = formatters; | |
// shortcut for console | |
exports.console = formatters.console; | |
} | |
}); | |
var packing = createCommonjsModule(function (module, exports) { | |
// Generated by LiveScript 1.6.0 | |
var CloneError, clone, jsondiffpatch, diff, out$ = exports || commonjsGlobal, toString$ = {}.toString; | |
out$.pack = pack; | |
function pack(x){ | |
return JSON.stringify(x, function(key, val){ | |
if (toString$.call(val).slice(8, -1) === 'Function') { | |
return val + ''; | |
} | |
return val; | |
}); | |
} | |
out$.unpack = unpack; | |
function unpack(x){ | |
return JSON.parse(x); | |
} | |
out$.CloneError = CloneError = (function(superclass){ | |
var prototype = extend$((import$(CloneError, superclass).displayName = 'CloneError', CloneError), superclass).prototype; | |
function CloneError(message, argument){ | |
this.message = message; | |
this.argument = argument; | |
CloneError.superclass.apply(this, arguments); | |
Error.captureStackTrace(this, CloneError); | |
} | |
return CloneError; | |
}(Error)); | |
out$.clone = clone = function(x){ | |
var ref$; | |
if ((ref$ = toString$.call(x).slice(8, -1)) === 'Object' || ref$ === 'Array') { | |
return unpack(pack(x)); | |
} else { | |
throw new CloneError("argument must be object or array, supplied: " + pack(x), x); | |
} | |
}; | |
jsondiffpatch = main; | |
out$.diff = diff = function(a, b){ | |
return jsondiffpatch.diff(a, b); | |
}; | |
function extend$(sub, sup){ | |
function fun(){} fun.prototype = (sub.superclass = sup).prototype; | |
(sub.prototype = new fun).constructor = sub; | |
if (typeof sup.extended == 'function') sup.extended(sub); | |
return sub; | |
} | |
function import$(obj, src){ | |
var own = {}.hasOwnProperty; | |
for (var key in src) if (own.call(src, key)) obj[key] = src[key]; | |
return obj; | |
} | |
}); | |
var merge_1 = createCommonjsModule(function (module, exports) { | |
// Generated by LiveScript 1.6.0 | |
var pack, basedOn, tests, start, testCount, i$, name, test, ref$, result, expected, out$ = exports || commonjsGlobal, toString$ = {}.toString; | |
pack = packing.pack; | |
/** / | |
export merge = (obj1, obj2) -> | |
if (typeof! obj1 is \Array) and (typeof! obj2 is \Array) | |
for i in obj2 | |
try | |
for j in obj1 | |
throw if pack(i) is pack(j) | |
# append if item is not found in first one | |
obj1.push i | |
return obj1 | |
else | |
for p of obj2 | |
try | |
throw if typeof! obj2[p] isnt \Object | |
throw if typeof! obj1[p] isnt \Object | |
# go on if and only if right hand is object | |
obj1[p] `merge` obj2[p] | |
catch | |
if Array.isArray obj1[p] | |
# array, merge with current one | |
for i, j of obj2[p] | |
try | |
for a in obj1[p] | |
throw if pack(a) is pack(j) | |
obj1[p].push j | |
else if obj2[p] isnt void | |
obj1[p] = obj2[p] | |
else | |
delete obj1[p] | |
obj1 | |
/**/ | |
out$.merge = merge; | |
function merge(obj1, obj2){ | |
var i$, len$, i, j$, len1$, j, p, tObj1, ref$; | |
if (toString$.call(obj1).slice(8, -1) === 'Array' && toString$.call(obj2).slice(8, -1) === 'Array') { | |
for (i$ = 0, len$ = obj2.length; i$ < len$; ++i$) { | |
i = obj2[i$]; | |
try { | |
for (j$ = 0, len1$ = obj1.length; j$ < len1$; ++j$) { | |
j = obj1[j$]; | |
if (pack(i) === pack(j)) { | |
throw null; | |
} | |
} | |
obj1.push(i); | |
} catch (e$) {} | |
} | |
return obj1; | |
} else { | |
for (p in obj2) { | |
tObj1 = toString$.call(obj1[p]).slice(8, -1); | |
if ((ref$ = toString$.call(obj2[p]).slice(8, -1)) === 'Object' || ref$ === 'Array') { | |
if (tObj1 === 'Object' || tObj1 === 'Array') { | |
merge(obj1[p], obj2[p]); | |
} else { | |
obj1[p] = obj2[p]; | |
} | |
} else { | |
if (obj2[p] !== void 8) { | |
obj1[p] = obj2[p]; | |
} else { | |
delete obj1[p]; | |
} | |
} | |
} | |
return obj1; | |
} | |
} | |
/* */ | |
out$.mergeAll = mergeAll; | |
function mergeAll(obj1){ | |
var sources, res$, i$, to$, len$, obj2; | |
res$ = []; | |
for (i$ = 1, to$ = arguments.length; i$ < to$; ++i$) { | |
res$.push(arguments[i$]); | |
} | |
sources = res$; | |
for (i$ = 0, len$ = sources.length; i$ < len$; ++i$) { | |
obj2 = sources[i$]; | |
merge(obj1, obj2); | |
} | |
return obj1; | |
} | |
out$.basedOn = basedOn = function(a, b){ | |
return merge(b || {}, a || {}); | |
}; | |
tests = { | |
'simple merge': function(){ | |
var a, b, result, expected; | |
a = { | |
a: 1, | |
b: 2 | |
}; | |
b = { | |
c: 5 | |
}; | |
result = merge(a, b); | |
expected = { | |
a: 1, | |
b: 2, | |
c: 5 | |
}; | |
return { | |
result: result, | |
expected: expected | |
}; | |
}, | |
'simple merge2': function(){ | |
var a, b, result, expected; | |
a = { | |
a: 1, | |
b: 2, | |
c: { | |
ca: 1, | |
cb: 2 | |
} | |
}; | |
b = { | |
c: { | |
cb: 5 | |
} | |
}; | |
result = merge(a, b); | |
expected = { | |
a: 1, | |
b: 2, | |
c: { | |
ca: 1, | |
cb: 5 | |
} | |
}; | |
return { | |
result: result, | |
expected: expected | |
}; | |
}, | |
'merge lists': function(){ | |
var a, b, result, expected; | |
a = { | |
a: 1, | |
b: 2, | |
c: [1, 2] | |
}; | |
b = { | |
b: 8, | |
c: [1, 4] | |
}; | |
result = merge(a, b); | |
expected = { | |
a: 1, | |
b: 8, | |
c: [1, 2, 4] | |
}; | |
return { | |
result: result, | |
expected: expected | |
}; | |
}, | |
'merge lists2': function(){ | |
var a, b, result, expected; | |
a = { | |
a: 1, | |
b: 2, | |
c: ['hello', 'world'] | |
}; | |
b = { | |
b: 8, | |
c: ['hi', 'world'] | |
}; | |
result = merge(a, b); | |
expected = { | |
a: 1, | |
b: 8, | |
c: ['hello', 'world', 'hi'] | |
}; | |
return { | |
result: result, | |
expected: expected | |
}; | |
}, | |
'merge lists of objects': function(){ | |
var a, b, result, expected; | |
a = { | |
a: 1, | |
b: 2, | |
c: [ | |
{ | |
a: 1, | |
b: 2 | |
}, { | |
a: 3, | |
b: 4 | |
} | |
] | |
}; | |
b = { | |
b: 8, | |
c: [ | |
{ | |
a: 1, | |
b: 2 | |
}, { | |
a: 5, | |
b: 6 | |
} | |
] | |
}; | |
result = merge(a, b); | |
expected = { | |
a: 1, | |
b: 8, | |
c: [ | |
{ | |
a: 1, | |
b: 2 | |
}, { | |
a: 3, | |
b: 4 | |
}, { | |
a: 5, | |
b: 6 | |
} | |
] | |
}; | |
return { | |
result: result, | |
expected: expected | |
}; | |
}, | |
'merge lists of objects2': function(){ | |
var x, y, result, expected; | |
x = [ | |
{ | |
a: 1, | |
b: 2 | |
}, { | |
a: 3, | |
b: 4 | |
} | |
]; | |
y = [ | |
{ | |
a: 5, | |
b: 6 | |
}, { | |
a: 7, | |
b: 8 | |
}, { | |
a: 9, | |
b: 10 | |
}, { | |
a: 11, | |
b: 12 | |
} | |
]; | |
result = merge(x, y); | |
expected = [ | |
{ | |
a: 1, | |
b: 2 | |
}, { | |
a: 3, | |
b: 4 | |
}, { | |
a: 5, | |
b: 6 | |
}, { | |
a: 7, | |
b: 8 | |
}, { | |
a: 9, | |
b: 10 | |
}, { | |
a: 11, | |
b: 12 | |
} | |
]; | |
return { | |
result: result, | |
expected: expected | |
}; | |
}, | |
'deleting something': function(){ | |
var a, result, expected; | |
a = { | |
a: 1, | |
b: 2, | |
c: { | |
ca: 11, | |
cb: 2 | |
} | |
}; | |
result = merge(a, { | |
c: void 8 | |
}); | |
expected = { | |
a: 1, | |
b: 2 | |
}; | |
return { | |
result: result, | |
expected: expected | |
}; | |
}, | |
'force overwrite': function(){ | |
var a, b, result, expected; | |
a = { | |
a: 1, | |
b: 2, | |
c: { | |
ca: 11, | |
cb: 2 | |
} | |
}; | |
b = { | |
c: { | |
cb: 5 | |
} | |
}; | |
result = mergeAll(a, { | |
c: void 8 | |
}, b); | |
expected = { | |
a: 1, | |
b: 2, | |
c: { | |
cb: 5 | |
} | |
}; | |
return { | |
result: result, | |
expected: expected | |
}; | |
}, | |
'merging object with functions': function(){ | |
var a, b, result, expected; | |
a = { | |
a: 1, | |
b: 2, | |
c: { | |
ca: 11, | |
cb: 2 | |
} | |
}; | |
b = { | |
c: { | |
cb: function(x){ | |
return x; | |
} | |
} | |
}; | |
result = merge(a, b); | |
expected = { | |
a: 1, | |
b: 2, | |
c: { | |
ca: 11, | |
cb: function(x){ | |
return x; | |
} | |
} | |
}; | |
return { | |
result: result, | |
expected: expected | |
}; | |
}, | |
'Field or method does not already exist, and cant create it on String': function(){ | |
var a, b, result, expected; | |
a = { | |
a: 1, | |
b: 2, | |
c: "hey" | |
}; | |
b = { | |
c: { | |
cb: "aa" | |
} | |
}; | |
result = merge(a, b); | |
expected = { | |
a: 1, | |
b: 2, | |
c: { | |
cb: "aa" | |
} | |
}; | |
return { | |
result: result, | |
expected: expected | |
}; | |
} | |
}; | |
start = Date.now(); | |
testCount = 1; | |
for (i$ = 0; i$ <= testCount; ++i$) { | |
for (name in tests) { | |
test = tests[name]; | |
ref$ = test(), result = ref$.result, expected = ref$.expected; | |
if (pack(expected) !== pack(result)) { | |
console.log("merge test failed test: ", name); | |
console.log("EXPECTED: ", expected); | |
console.log("RESULT : ", result); | |
throw "Test failed in merge.ls!, test: " + name; | |
} | |
} | |
} | |
if (testCount > 1) { | |
console.log("Merge tests took: " + (Date.now() - start) + " milliseconds..."); | |
} | |
}); | |
var ipToHex_1 = createCommonjsModule(function (module, exports) { | |
// Generated by LiveScript 1.6.0 | |
var reverse, hex, ipToHex, out$ = exports || commonjsGlobal; | |
reverse = lib$1.reverse; | |
out$.hex = hex = function(n){ | |
return n.toString(16).toUpperCase(); | |
}; | |
out$.ipToHex = ipToHex = function(ip){ | |
var i, result, i$, ref$, len$, part; | |
i = 0; | |
result = 0; | |
for (i$ = 0, len$ = (ref$ = reverse(ip.split('.'))).length; i$ < len$; ++i$) { | |
part = ref$[i$]; | |
result += part * Math.pow(256, i++); | |
} | |
return hex(result); | |
}; | |
}); | |
// Generated by LiveScript 1.6.0 | |
var Logger, EventEmitter, sleep, ref$, pack, unpack, clone$1, diff$1, merge, basedOn, ipToHex, hex; | |
Logger = logger.Logger; | |
EventEmitter = eventEmitter.EventEmitter; | |
sleep = sleep_1.sleep; | |
ref$ = packing, pack = ref$.pack, unpack = ref$.unpack, clone$1 = ref$.clone, diff$1 = ref$.diff; | |
ref$ = merge_1, merge = ref$.merge, basedOn = ref$.basedOn; | |
ref$ = ipToHex_1, ipToHex = ref$.ipToHex, hex = ref$.hex; | |
var lib$2 = { | |
Logger: Logger, | |
EventEmitter: EventEmitter, | |
sleep: sleep, | |
pack: pack, | |
unpack: unpack, | |
clone: clone$1, | |
diff: diff$1, | |
merge: merge, | |
basedOn: basedOn, | |
ipToHex: ipToHex, | |
hex: hex | |
}; | |
var debugTools = createCommonjsModule(function (module, exports) { | |
// Generated by LiveScript 1.6.0 | |
var brief, out$ = exports || commonjsGlobal; | |
out$.brief = brief = function(msg){ | |
var s, k, v, dataStr; | |
s = {}; | |
for (k in msg) { | |
v = msg[k]; | |
if (k === 'data') { | |
continue; | |
} | |
s[k] = v; | |
} | |
if (msg.data) { | |
dataStr = JSON.stringify(msg.data); | |
s.data = dataStr.length > 70 | |
? "..." + dataStr.length + "..." | |
: msg.data; | |
} | |
if (msg.permissions) { | |
s.permissions = "..." + msg.permissions.length + "..."; | |
} | |
return s; | |
}; | |
}); | |
var topicMatch_1 = createCommonjsModule(function (module, exports) { | |
// Generated by LiveScript 1.6.0 | |
var ref$, max, split, splitDot, topicMatch, testTopicMatch, out$ = exports || commonjsGlobal, toString$ = {}.toString; | |
ref$ = lib$1, max = ref$.max, split = ref$.split; | |
splitDot = split('.'); | |
out$.topicMatch = topicMatch = function(topics, keypaths, opts){ | |
var asArray, i$, ref$, len$, topic, j$, ref1$, len1$, keypath, topicArr, keypathArr, e, k$, ref2$, len2$, index, topicPart, keypathPart; | |
opts == null && (opts = {}); | |
if (!(topics != null && keypaths != null)) { | |
return false; | |
} | |
asArray = function(x){ | |
if (toString$.call(x).slice(8, -1) === 'String') { | |
return x.trim().split(' '); | |
} else { | |
return x; | |
} | |
}; | |
for (i$ = 0, len$ = (ref$ = asArray( | |
topics)).length; i$ < len$; ++i$) { | |
topic = ref$[i$]; | |
for (j$ = 0, len1$ = (ref1$ = asArray( | |
keypaths)).length; j$ < len1$; ++j$) { | |
keypath = ref1$[j$]; | |
try { | |
if ('**' === topic || '**' === keypath) { | |
if (opts.debug) { | |
console.log("topic is **, immediately matches with anything"); | |
} | |
return true; | |
} | |
try { | |
topicArr = splitDot(topic); | |
keypathArr = splitDot(keypath); | |
} catch (e$) { | |
e = e$; | |
console.error("both topic and keypath should be string."); | |
return false; | |
} | |
for (k$ = 0, len2$ = (ref2$ = (fn$())).length; k$ < len2$; ++k$) { | |
index = ref2$[k$]; | |
topicPart = (fn1$()); | |
keypathPart = (fn2$()); | |
if (opts.debug) { | |
console.log("topic-part: " + topicPart + ", keypath-part: " + keypathPart); | |
} | |
if ('*' === keypathPart || '*' === topicPart) { | |
if (undefined === keypathPart || undefined === topicPart) { | |
if (opts.debug) { | |
console.log("returning false because there is no command to look for match"); | |
} | |
throw null; | |
} | |
continue; | |
} | |
if ('**' !== keypathPart && '**' !== topicPart) { | |
if (undefined === keypathPart || undefined === topicPart) { | |
if (opts.debug) { | |
console.log("returning false because there is no command to look for match"); | |
} | |
throw null; | |
} | |
} | |
if ('**' === keypathPart || '**' === topicPart) { | |
if (opts.debug) { | |
console.log("returning true because '**' will match with anything."); | |
} | |
return true; | |
} | |
if (topicPart !== keypathPart) { | |
throw "not matching"; | |
} | |
} | |
if (opts.debug) { | |
console.log("no condition broke the match."); | |
} | |
return true; | |
} catch (e$) {} | |
} | |
} | |
return false; | |
function fn$(){ | |
var i$, to$, results$ = []; | |
for (i$ = 0, to$ = max(topicArr.length, keypathArr.length); i$ < to$; ++i$) { | |
results$.push(i$); | |
} | |
return results$; | |
} | |
function fn1$(){ | |
try { | |
return topicArr[index]; | |
} catch (e$) {} | |
} | |
function fn2$(){ | |
try { | |
return keypathArr[index]; | |
} catch (e$) {} | |
} | |
}; | |
(testTopicMatch = function(){ | |
/* | |
** will match with anything, including null | |
*/ | |
var examples, num, example, result, results$ = []; | |
examples = [ | |
{ | |
topic: "foo.bar", | |
keypath: "foo.*", | |
expected: true | |
}, { | |
topic: "*.bar", | |
keypath: "foo.*", | |
expected: true | |
}, { | |
topic: "foo.bar", | |
keypath: "baz.bar", | |
expected: false | |
}, { | |
topic: "foo.bar", | |
keypath: "baz.bar foo.*", | |
expected: true | |
}, { | |
topic: "foo.bar", | |
keypath: "foo.*.*", | |
expected: false | |
}, { | |
topic: "foo.*.bar", | |
keypath: "foo.*", | |
expected: false | |
}, { | |
topic: "foo.**", | |
keypath: "foo", | |
expected: true | |
}, { | |
topic: "@foo", | |
keypath: ['@foo.**', '@bar.**'], | |
expected: true | |
}, { | |
topic: ['@bar.**', '@foo-bar.**'], | |
keypath: "@foo-bar", | |
expected: true | |
}, { | |
topic: "foo.*.**", | |
keypath: "foo.bar.baz", | |
expected: true | |
}, { | |
topic: "foo.*.**", | |
keypath: "foo.bar", | |
expected: true | |
}, { | |
topic: "foo.*.**", | |
keypath: "foo.bar.baz.qux", | |
expected: true | |
}, { | |
topic: "foo.**", | |
keypath: "foo.bar.baz.qux", | |
expected: true | |
}, { | |
topic: "foo.**", | |
keypath: "*.bar.baz.qux", | |
expected: true | |
}, { | |
topic: "foo.bar", | |
keypath: "*.*", | |
expected: true | |
}, { | |
topic: "foo.bar", | |
keypath: "*", | |
expected: false | |
}, { | |
topic: "*", | |
keypath: "foo.bar", | |
expected: false | |
}, { | |
topic: "foo.bar", | |
keypath: "**", | |
expected: true | |
}, { | |
topic: "*", | |
keypath: "*", | |
expected: true | |
}, { | |
topic: "**", | |
keypath: "*", | |
expected: true | |
}, { | |
topic: "*", | |
keypath: "**", | |
expected: true | |
}, { | |
topic: "**", | |
keypath: "**", | |
expected: true | |
}, { | |
topic: "*.*", | |
keypath: "**", | |
expected: true | |
}, { | |
topic: "**", | |
keypath: "*.*", | |
expected: true | |
} | |
]; | |
for (num in examples) { | |
example = examples[num]; | |
result = topicMatch(example.topic, example.keypath); | |
if (result !== example.expected) { | |
console.log("Test failed in #" + num + ", re-running in debug mode: "); | |
console.log("comparing if '" + example.topic + "' matches with '" + example.keypath + "' expecting: " + example.expected); | |
console.log("---------------------------------------------------"); | |
topicMatch(example.topic, example.keypath, { | |
debug: true | |
}); | |
console.log("---------------------------------------------------"); | |
results$.push(process.exit(1)); | |
} | |
} | |
return results$; | |
})(); | |
}); | |
var actorManager = createCommonjsModule(function (module, exports) { | |
// Generated by LiveScript 1.6.0 | |
var ref$, reject, find, routeMatch, Logger, sleep, hex, brief, ActorManager, out$ = exports || commonjsGlobal, slice$ = [].slice, arrayFrom$ = Array.from || function(x){return slice$.call(x);}; | |
ref$ = lib$1, reject = ref$.reject, find = ref$.find; | |
routeMatch = topicMatch_1.topicMatch; | |
ref$ = lib$2, Logger = ref$.Logger, sleep = ref$.sleep, hex = ref$.hex; | |
brief = debugTools.brief; | |
out$.ActorManager = ActorManager = (function(){ | |
ActorManager.displayName = 'ActorManager'; | |
var constructor = ActorManager; | |
ActorManager.instance = null; | |
function ActorManager(){ | |
if (constructor.instance) { | |
return constructor.instance; | |
} | |
constructor.instance = this; | |
this.actorUid = 1; | |
this.actors = []; | |
this.managerId = hex( | |
Date.now()); | |
this.log = new Logger("ActorMan." + this.managerId); | |
} | |
ActorManager.prototype.nextActorId = function(){ | |
return "a" + (this.actorUid++) + "-" + this.managerId; | |
}; | |
ActorManager.prototype.registerActor = function(actor){ | |
if (!find(function(it){ | |
return it.id === actor.id; | |
}, this.actors)) { | |
return this.actors.push(actor); | |
} | |
}; | |
ActorManager.prototype.findActor = function(id){ | |
if (!id) { | |
throw 'id is required!'; | |
} | |
return find(function(it){ | |
return it.id === id; | |
}, this.actors); | |
}; | |
ActorManager.prototype.deregisterActor = function(actor){ | |
return this.actors = reject(function(it){ | |
return it.id === actor.id; | |
}, this.actors); | |
}; | |
ActorManager.prototype.distribute = function(msg, sender){ | |
var dueDate, i$, ref$, len$, actor, that, delay, results$ = []; | |
if (msg.debug) { | |
this.log.debug("Distributing message: ", brief(msg)); | |
} | |
dueDate = Date.now(); | |
for (i$ = 0, len$ = (ref$ = this.actors).length; i$ < len$; ++i$) { | |
actor = ref$[i$]; | |
if (actor.id !== sender) { | |
if (routeMatch(msg.to, actor.subscriptions)) { | |
if (that = msg._exclude) { | |
if (that === actor.id) { | |
continue; | |
} | |
delete msg._exclude; | |
} | |
delay = Date.now() - dueDate; | |
if (delay > 10) { | |
this.log.warn("System load is high? Message is delivered after " + delay + "ms"); | |
} | |
results$.push(actor._inbox(msg)); | |
} else { | |
results$.push(null); | |
} | |
} | |
} | |
return results$; | |
}; | |
ActorManager.prototype.kill = function(){ | |
var args, res$, i$, to$, ref$, len$, actor, results$ = []; | |
res$ = []; | |
for (i$ = 0, to$ = arguments.length; i$ < to$; ++i$) { | |
res$.push(arguments[i$]); | |
} | |
args = res$; | |
for (i$ = 0, len$ = (ref$ = this.actors).length; i$ < len$; ++i$) { | |
actor = ref$[i$]; | |
results$.push(actor.trigger.apply(actor, ['kill'].concat(arrayFrom$(args)))); | |
} | |
return results$; | |
}; | |
return ActorManager; | |
}()); | |
}); | |
// Generated by LiveScript 1.6.0 | |
var ref$$1, sleep$1, Logger$1, getFormattedDate, slice$ = [].slice, arrayFrom$ = Array.from || function(x){return slice$.call(x);}; | |
try { | |
ref$$1 = lib$2, sleep$1 = ref$$1.sleep, Logger$1 = ref$$1.Logger; | |
} catch (e$) { | |
sleep$1 = function(ms, f){ | |
return setTimeout(f, ms); | |
}; | |
getFormattedDate = function(){ | |
var d; | |
d = new Date; | |
return d.getFullYear() + "-" + (d.getMonth() + 1) + "-" + d.getDate() + " " + d.getHours() + ":" + d.getMinutes() + ":" + d.getSeconds() + "." + d.getMilliseconds(); | |
}; | |
Logger$1 = (function(){ | |
Logger.displayName = 'Logger'; | |
function Logger(name){ | |
this.name = name; | |
} | |
Logger.prototype.log = function(){ | |
return console.log.apply(console, ['[', getFormattedDate(), ']', this.name + ":"].concat(arrayFrom$(arguments))); | |
}; | |
return Logger; | |
}()); | |
} | |
var deps = { | |
sleep: sleep$1, | |
Logger: Logger$1 | |
}; | |
var signal = createCommonjsModule(function (module, exports) { | |
// Generated by LiveScript 1.6.0 | |
var ref$, sleep, Logger, isItNaN, Signal, out$ = exports || commonjsGlobal, toString$ = {}.toString, slice$ = [].slice, arrayFrom$ = Array.from || function(x){return slice$.call(x);}; | |
ref$ = deps, sleep = ref$.sleep, Logger = ref$.Logger; | |
isItNaN = lib$1.isItNaN; | |
out$.Signal = Signal = (function(){ | |
Signal.displayName = 'Signal'; | |
function Signal(opts){ | |
opts == null && (opts = {}); | |
if (opts.debug) { | |
this.debug = true; | |
} | |
this.name = opts.name || 'Signal'; | |
this.log = new Logger(this.name); | |
this.response = []; | |
this.callback = { | |
ctx: null, | |
handler: null | |
}; | |
if (this.debug) { | |
this.log.debug("Initialized new signal."); | |
} | |
this.reusable = opts.reusable; | |
this.reset(); | |
} | |
Signal.prototype.cancel = function(){ | |
return this.reset(); | |
}; | |
Signal.prototype.reset = function(){ | |
if (!this.reusable) { | |
delete this.callback.handler; | |
delete this.callback.ctx; | |
} | |
this.shouldRun = false; | |
try { | |
clearTimeout(this.timer); | |
} catch (e$) {} | |
this.timer = void 8; | |
return this.skipNext = false; | |
}; | |
Object.defineProperty(Signal.prototype, 'waiting', { | |
get: function(){ | |
var ref$; | |
return toString$.call((ref$ = this.callback) != null ? ref$.handler : void 8).slice(8, -1) === 'Function'; | |
}, | |
configurable: true, | |
enumerable: true | |
}); | |
Signal.prototype.fire = function(error){ | |
var ref$, params, ref1$, handler, ctx, t0, err, this$ = this; | |
if (toString$.call((ref$ = this.callback) != null ? ref$.handler : void 8).slice(8, -1) !== 'Function') { | |
return; | |
} | |
params = !this.error | |
? this.response | |
: []; | |
ref1$ = this.callback, handler = ref1$.handler, ctx = ref1$.ctx; | |
t0 = Date.now(); | |
err = this.error; | |
return setImmediate(function(){ | |
this$.reset(); | |
handler.call.apply(handler, [ctx, err].concat(arrayFrom$(params))); | |
if (this$.debug) { | |
this$.log.debug("...signal has been fired."); | |
} | |
if (Date.now() - t0 > 100) { | |
return this$.log.warn("System seems busy now? Actual firing took place after " + (Date.now() - t0) + "ms"); | |
} | |
}); | |
}; | |
Signal.prototype.wait = function(timeout, callback){ | |
if (toString$.call(timeout).slice(8, -1) === 'Function') { | |
callback = timeout; | |
timeout = 0; | |
} | |
if (this.waiting) { | |
this.log.error("Can not wait over and over, skipping this one."); | |
return; | |
} | |
this.callback = { | |
ctx: this, | |
handler: callback | |
}; | |
if (!isItNaN(timeout)) { | |
if (timeout > 0) { | |
this.timeout = timeout; | |
if (this.debug) { | |
this.log.info("Heartbeating! timeout: " + this.timeout); | |
} | |
this.heartbeat(); | |
} | |
} | |
if (this.shouldRun) { | |
return this.fire(); | |
} | |
}; | |
Signal.prototype.skipNextGo = function(){ | |
return this.skipNext = true; | |
}; | |
Signal.prototype.clear = function(){ | |
return this.shouldRun = false; | |
}; | |
Signal.prototype.go = function(err){ | |
var args, res$, i$, to$; | |
res$ = []; | |
for (i$ = 1, to$ = arguments.length; i$ < to$; ++i$) { | |
res$.push(arguments[i$]); | |
} | |
args = res$; | |
if (this.skipNext) { | |
this.skipNext = false; | |
return; | |
} | |
this.shouldRun = true; | |
this.response = args; | |
this.error = err; | |
if (this.waiting) { | |
return this.fire(); | |
} | |
}; | |
Signal.prototype.heartbeat = function(duration){ | |
var this$ = this; | |
if (duration > 0) { | |
this.timeout = duration; | |
} | |
try { | |
clearTimeout(this.timer); | |
} catch (e$) {} | |
return this.timer = sleep(this.timeout, function(){ | |
if (this$.waiting) { | |
this$.shouldRun = true; | |
if (this$.debug) { | |
this$.log.log("firing with timeout! timeout: " + this$.timeout); | |
} | |
if (toString$.call(this$.timeoutHandler).slice(8, -1) === 'Function') { | |
return this$.timeoutHandler(); | |
} else { | |
this$.error = 'TIMEOUT'; | |
return this$.fire(); | |
} | |
} | |
}); | |
}; | |
Signal.prototype.onTimeout = function(callback){ | |
return this.timeoutHandler = callback; | |
}; | |
return Signal; | |
}()); | |
}); | |
var signalBranch = createCommonjsModule(function (module, exports) { | |
// Generated by LiveScript 1.6.0 | |
var Signal, SignalBranch, out$ = exports || commonjsGlobal; | |
Signal = signal.Signal; | |
out$.SignalBranch = SignalBranch = (function(){ | |
SignalBranch.displayName = 'SignalBranch'; | |
function SignalBranch(opts){ | |
opts == null && (opts = {}); | |
this.timeout = opts.timeout || -1; | |
this.count = 0; | |
this.main = new Signal; | |
this.signals = []; | |
this.error = null; | |
this.branches = []; | |
} | |
SignalBranch.prototype.cancel = function(){ | |
var i, results$ = []; | |
this.main.cancel(); | |
this.main = null; | |
for (i in this.signals) { | |
this.signals[i].cancel(); | |
results$.push(this.signals[i] = null); | |
} | |
return results$; | |
}; | |
SignalBranch.prototype.add = function(opts){ | |
var timeout, name, signal, this$ = this; | |
timeout = (opts != null ? opts.timeout : void 8) || this.timeout; | |
name = (opts != null ? opts.name : void 8) || this.count + ""; | |
signal = new Signal({ | |
name: name | |
}); | |
this.signals.push(signal); | |
this.count++; | |
signal.wait(timeout, function(err){ | |
var that; | |
if (that = err) { | |
this$.error = that; | |
} | |
if (--this$.count === 0) { | |
return this$.main.go(this$.error); | |
} | |
}); | |
return signal; | |
}; | |
SignalBranch.prototype.joined = function(callback){ | |
var err, this$ = this; | |
if (this.count === 0) { | |
this.main.go(err = null); | |
} | |
return this.main.wait(this.timeout, function(err){ | |
var i$, x$, ref$, len$; | |
for (i$ = 0, len$ = (ref$ = this$.signals).length; i$ < len$; ++i$) { | |
x$ = ref$[i$]; | |
if (x$.error) { | |
if (!err) { | |
err = {}; | |
} | |
err.signals = true; | |
} | |
x$.clear(); | |
} | |
return callback(err, this$.signals); | |
}); | |
}; | |
return SignalBranch; | |
}()); | |
}); | |
// Generated by LiveScript 1.6.0 | |
var Signal$1, SignalBranch; | |
Signal$1 = signal.Signal; | |
SignalBranch = signalBranch.SignalBranch; | |
var signal$1 = { | |
Signal: Signal$1, | |
SignalBranch: SignalBranch | |
}; | |
commonjsGlobal.Signal = Signal$1; | |
commonjsGlobal.SignalBranch = SignalBranch; | |
var request = createCommonjsModule(function (module, exports) { | |
// Generated by LiveScript 1.6.0 | |
var merge, out$ = exports || commonjsGlobal, toString$ = {}.toString; | |
merge = lib$2.merge; | |
import$(out$, { | |
sendRequest: function(opts, data, callback){ | |
var meta, timeout, that, seq, requestId, enveloped, partHandler, completeHandler, lastPartSent, regPartHandlers, responseSignal, error, message, mergeMethodManual, requestDate, this$ = this; | |
meta = {}; | |
timeout = 5000; | |
if (toString$.call(opts).slice(8, -1) === 'String') { | |
meta.to = opts; | |
} else { | |
meta.to = opts.topic || opts.route || opts.to; | |
if (that = opts.timeout) { | |
timeout = that; | |
} | |
} | |
seq = this.msgSeq++; | |
requestId = seq + ""; | |
meta.part = this.getNextPartId(opts.part, requestId); | |
if (opts.debug) { | |
meta.debug = true; | |
} | |
if (toString$.call(data).slice(8, -1) === 'Function') { | |
callback = data; | |
data = null; | |
} | |
enveloped = (meta.from = this.me, meta.seq = seq, meta.data = data, meta.req = true, meta.timestamp = Date.now(), meta); | |
this.subscribe(meta.to); | |
partHandler = function(){}; | |
completeHandler = function(){}; | |
lastPartSent = false; | |
regPartHandlers = { | |
onPart: function(func){ | |
return partHandler = func; | |
}, | |
onReceive: function(func){ | |
return completeHandler = func; | |
}, | |
sendPart: function(data, lastPart){ | |
var msg; | |
lastPart == null && (lastPart = true); | |
if (lastPartSent) { | |
this$.log.err("Last part is already sent."); | |
return; | |
} | |
msg = (enveloped.data = data, enveloped); | |
msg.part = this$.getNextPartId(!lastPart, requestId); | |
this$.log.log("Sending next part with id: ", msg.part); | |
this$.sendEnveloped(msg); | |
if (lastPart) { | |
return lastPartSent = true; | |
} | |
} | |
}; | |
responseSignal = new Signal({ | |
debug: enveloped.debug, | |
name: "ReqSig:" + enveloped.seq | |
}); | |
this.requestQueue[requestId] = responseSignal; | |
error = null; | |
message = {}; | |
mergeMethodManual = false; | |
requestDate = Date.now(); | |
(function lo(op){ | |
responseSignal.clear(); | |
return responseSignal.wait(timeout, function(err, msg){ | |
if (err) { | |
error = err; | |
return op(); | |
} else { | |
partHandler(msg); | |
if (requestDate != null) { | |
if (requestDate + 200 < Date.now()) { | |
this$.log.debug("First response is too late for seq:" + enveloped.seq + " latency:" + (Date.now() - requestDate) + "ms, req: ", enveloped); | |
} | |
requestDate = undefined; | |
} | |
if (msg.timeout) { | |
if (enveloped.debug) { | |
this$.log.debug("New timeout is set from target: " + msg.timeout + "ms for request seq: " + enveloped.seq); | |
} | |
timeout = msg.timeout; | |
} | |
if (msg.merge != null && msg.merge === false) { | |
mergeMethodManual = true; | |
} | |
if (!mergeMethodManual) { | |
merge(message, msg); | |
} | |
if (msg.part == null || msg.part < 0) { | |
/* | |
if not msg.part? | |
@log.debug "this was a single part response." | |
else | |
@log.debug "this was the last part of the message chain." | |
*/ | |
return op(); | |
} | |
} | |
return lo(op); | |
}); | |
})(function(){ | |
if (this$._state.killFinished) { | |
this$.log.warn("Got response activity after killed?", error, message); | |
return; | |
} | |
if (!callback) { | |
if (error === 'TIMEOUT') { | |
this$.log.warn("Request is timed out. Timeout was " + timeout + "ms, seq: " + enveloped.seq + ". req was:", brief(enveloped)); | |
} | |
} | |
this$.unsubscribe(meta.to); | |
delete this$.requestQueue[requestId]; | |
if (mergeMethodManual) { | |
error = "Merge method is set to manual. We can't concat the messages."; | |
} | |
completeHandler(error, message); | |
if (toString$.call(callback).slice(8, -1) === 'Function') { | |
return callback(error, message); | |
} | |
}); | |
if (meta.debug) { | |
this.log.debug("Sending request seq: " + enveloped.seq); | |
} | |
this.sendEnveloped(enveloped); | |
return regPartHandlers; | |
} | |
}); | |
function import$(obj, src){ | |
var own = {}.hasOwnProperty; | |
for (var key in src) if (own.call(src, key)) obj[key] = src[key]; | |
return obj; | |
} | |
}); | |
var actor = createCommonjsModule(function (module, exports) { | |
// Generated by LiveScript 1.6.0 | |
var ref$, sleep, pack, EventEmitter, Logger, merge, brief, ActorManager, split, flatten, keys, unique, isItNaN, routeMatch, request$1, TopicTypeError, LAST_PART, messageOwner, Actor, A1, A2, out$ = exports || commonjsGlobal, toString$ = {}.toString; | |
ref$ = lib$2, sleep = ref$.sleep, pack = ref$.pack, EventEmitter = ref$.EventEmitter, Logger = ref$.Logger, merge = ref$.merge; | |
brief = debugTools.brief; | |
ActorManager = actorManager.ActorManager; | |
ref$ = lib$1, split = ref$.split, flatten = ref$.flatten, keys = ref$.keys, unique = ref$.unique, isItNaN = ref$.isItNaN; | |
routeMatch = topicMatch_1.topicMatch; | |
request$1 = request; | |
out$.TopicTypeError = TopicTypeError = (function(superclass){ | |
var prototype = extend$((import$(TopicTypeError, superclass).displayName = 'TopicTypeError', TopicTypeError), superclass).prototype; | |
function TopicTypeError(message, route){ | |
this.message = message; | |
this.route = route; | |
TopicTypeError.superclass.apply(this, arguments); | |
Error.captureStackTrace(this, TopicTypeError); | |
this.type = 'TopicTypeError'; | |
} | |
return TopicTypeError; | |
}(Error)); | |
LAST_PART = -1; | |
messageOwner = function(it){ | |
var ref$; | |
return (ref$ = it.to.split('.'))[ref$.length - 1]; | |
}; | |
out$.Actor = Actor = (function(superclass){ | |
var prototype = extend$((import$(Actor, superclass).displayName = 'Actor', Actor), superclass).prototype; | |
importAll$(prototype, arguments[1]); | |
function Actor(name, opts){ | |
this.send = bind$(this, 'send', prototype); | |
Actor.superclass.call(this); | |
this.mgr = new ActorManager(); | |
this.id = this.mgr.nextActorId(); | |
this.me = this.id; | |
this.name = name || this.id; | |
this.log = new Logger(this.name); | |
this.msgSeq = 0; | |
this.subscriptions = [this.me]; | |
this.requestQueue = {}; | |
this._route_handlers = {}; | |
this._state = {}; | |
this._partial_msg_states = {}; | |
this._request_concat_cache = {}; | |
this._last_login = 0; | |
this.mgr.registerActor(this); | |
if (toString$.call(this.action).slice(8, -1) === 'Function') { | |
this.action(); | |
} | |
} | |
Actor.prototype.setName = function(name){ | |
this.name = name; | |
return this.log.name = name; | |
}; | |
Actor.prototype.subscribe = function(routes){ | |
var i$, ref$, len$, route, results$ = []; | |
for (i$ = 0, len$ = (ref$ = unique(flatten([routes]))).length; i$ < len$; ++i$) { | |
route = ref$[i$]; | |
results$.push(this.subscriptions.push(route)); | |
} | |
return results$; | |
}; | |
Actor.prototype.unsubscribe = function(route){ | |
return this.subscriptions.splice(this.subscriptions.indexOf(route), 1); | |
}; | |
Actor.prototype.send = function(route, data){ | |
var enveloped; | |
if (toString$.call(route).slice(8, -1) === 'String') { | |
route = { | |
to: route | |
}; | |
} | |
enveloped = import$({ | |
from: this.me, | |
data: data, | |
seq: this.msgSeq++ | |
}, route); | |
return this.sendEnveloped(enveloped); | |
}; | |
Actor.prototype.getNextPartId = function(autoinc, msgId){ | |
var nextPart; | |
nextPart = undefined; | |
if (autoinc) { | |
if (this._partial_msg_states[msgId] == null) { | |
this._partial_msg_states[msgId] = 0; | |
} | |
nextPart = this._partial_msg_states[msgId]++; | |
} else { | |
if (this._partial_msg_states[msgId] != null) { | |
delete this._partial_msg_states[msgId]; | |
nextPart = LAST_PART; | |
} | |
} | |
return nextPart; | |
}; | |
Actor.prototype.sendResponse = function(req, meta, data){ | |
var enveloped; | |
if (!req.req) { | |
this.log.err("No request is required, doing nothing."); | |
debugger; | |
return; | |
} | |
if (toString$.call(data).slice(8, -1) === 'Undefined') { | |
data = meta; | |
meta = {}; | |
} | |
meta.part = this.getNextPartId(meta.part, req.from + "." + req.seq); | |
enveloped = import$({ | |
from: this.me, | |
to: req.from, | |
seq: this.msgSeq++, | |
data: data, | |
re: req.seq, | |
resToken: req.resToken, | |
debug: req.debug | |
}, meta); | |
if (req.debug || meta.debug) { | |
this.log.debug("sending the response for request: ", brief(enveloped)); | |
} | |
return this.sendEnveloped(enveloped); | |
}; | |
Actor.prototype._inbox = function(msg){ | |
var this$ = this; | |
if (this.debug || msg.debug) { | |
this.log.debug("Got msg to inbox: ", brief(msg)); | |
} | |
if (this._state.killFinished) { | |
debugger; | |
} | |
msg.permissions = msg.permissions || []; | |
return setImmediate(function(){ | |
var ref$; | |
if (msg.re != null && messageOwner(msg) === this$.me) { | |
if (this$.requestQueue[msg.re]) { | |
if (this$.debug || msg.debug) { | |
this$.log.debug("We were expecting this response: ", msg); | |
this$.log.debug("Current request queue: ", keys(this$.requestQueue)); | |
} | |
if ((ref$ = this$.requestQueue[msg.re]) != null) { | |
ref$.go(null, msg); | |
} | |
} else { | |
this$.log.err("This is not a message we were expecting (or interested in)?is it timed out already? I'm " + this$.me + ")", msg); | |
if (this$.debug) { | |
this$.log.warn("Current request queue: ", this$.requestQueue); | |
} | |
} | |
return; | |
} | |
if ('data' in msg) { | |
this$.trigger('data', msg); | |
} | |
return this$.trigger('receive', msg); | |
}); | |
}; | |
Actor.prototype.onTopic = function(route, handler){ | |
var ref$, this$ = this; | |
if (!route) { | |
throw "Need a route."; | |
} | |
if (!in$(route, this.subscriptions)) { | |
this.subscribe(route); | |
} | |
this.on('data', function(msg){ | |
var requestId; | |
if (routeMatch(msg.to, route)) { | |
if (msg.req && msg.part != null) { | |
this$.sendResponse(msg, { | |
part: true, | |
ack: true | |
}, null); | |
requestId = msg.from + "." + msg.seq; | |
if (!this$._request_concat_cache[requestId]) { | |
this$._request_concat_cache[requestId] = function(){ | |
var message; | |
message = {}; | |
return function(msg){ | |
var ref$, ref1$; | |
merge(message, msg); | |
if (msg.part === LAST_PART) { | |
handler.call(this$, message); | |
return ref1$ = (ref$ = this$._request_concat_cache)[requestId], delete ref$[requestId], ref1$; | |
} | |
}; | |
}(); | |
} | |
return this$._request_concat_cache[requestId](msg); | |
} else { | |
return handler.call(this$, msg); | |
} | |
} | |
}); | |
return ((ref$ = this._route_handlers)[route] || (ref$[route] = [])).push(handler); | |
}; | |
Actor.prototype.triggerTopic = function(route){ | |
var args, res$, i$, to$, that, len$, handler, results$ = []; | |
res$ = []; | |
for (i$ = 1, to$ = arguments.length; i$ < to$; ++i$) { | |
res$.push(arguments[i$]); | |
} | |
args = res$; | |
if (that = this._route_handlers[route]) { | |
for (i$ = 0, len$ = that.length; i$ < len$; ++i$) { | |
handler = that[i$]; | |
results$.push(handler.apply(null, args)); | |
} | |
return results$; | |
} else { | |
return this.log.debug("No such route handler found: " + route); | |
} | |
}; | |
Actor.prototype.onceTopic = function(route, handler){ | |
var this$ = this; | |
if (!in$(route, this.subscriptions)) { | |
this.subscribe(route); | |
} | |
return this.once('data', function(msg){ | |
if (routeMatch(msg.to, route)) { | |
handler(msg); | |
return this$.unsubscribe(route); | |
} | |
}); | |
}; | |
Actor.prototype.sendEnveloped = function(msg){ | |
var this$ = this; | |
if (!(msg.to || 'auth' in msg)) { | |
debugger; | |
return this.log.err("send-enveloped: Message has no route. Not sending.", msg); | |
} | |
setImmediate(function(){ | |
if (!msg.timestamp) { | |
msg.timestamp = Date.now(); | |
} | |
if (this$.debug) { | |
this$.log.debug("sending message: ", msg); | |
} | |
return this$.mgr.distribute(msg, this$.id); | |
}); | |
}; | |
Actor.prototype.kill = function(reason){ | |
var id, ref$, signal; | |
if (!this._state.killStarted) { | |
this._state.killStarted = true; | |
this.mgr.deregisterActor(this); | |
for (id in ref$ = this.requestQueue) { | |
signal = ref$[id]; | |
signal.reset(); | |
delete this.requestQueue[id]; | |
} | |
this.trigger('kill', reason); | |
return this._state.killFinished = true; | |
} | |
}; | |
Actor.prototype.onEveryLogin = function(callback){ | |
var minPeriod, this$ = this; | |
minPeriod = 1000; | |
this.onTopic('app.dcs.connect', function(msg){ | |
if (this$._last_login + minPeriod < Date.now()) { | |
callback(msg); | |
return this$._last_login = Date.now(); | |
} | |
}); | |
return this.sendRequest('app.dcs.update', function(err, msg){ | |
if (!err && (msg != null && msg.data)) { | |
if (this$._last_login + minPeriod < Date.now()) { | |
callback(msg); | |
return this$._last_login = Date.now(); | |
} | |
} | |
}); | |
}; | |
return Actor; | |
}(EventEmitter, request$1)); | |
if (commonjsRequire.main === module) { | |
console.log("initializing actor test"); | |
new (A1 = (function(superclass){ | |
var prototype = extend$((import$(A1, superclass).displayName = 'A1', A1), superclass).prototype; | |
A1.prototype.action = function(){ | |
var this$ = this; | |
return this.onTopic("hello", function(msg){ | |
return this$.log.log("received hello message", msg); | |
}); | |
}; | |
function A1(){ | |
A1.superclass.apply(this, arguments); | |
} | |
return A1; | |
}(Actor))); | |
new (A2 = (function(superclass){ | |
var prototype = extend$((import$(A2, superclass).displayName = 'A2', A2), superclass).prototype; | |
A2.prototype.action = function(){ | |
var this$ = this; | |
this.onTopic("hello", function(msg){ | |
return this$.log.err("received hello message", msg); | |
}); | |
return this.send("hello", { | |
hello: 'there' | |
}); | |
}; | |
function A2(){ | |
A2.superclass.apply(this, arguments); | |
} | |
return A2; | |
}(Actor))); | |
} | |
function extend$(sub, sup){ | |
function fun(){} fun.prototype = (sub.superclass = sup).prototype; | |
(sub.prototype = new fun).constructor = sub; | |
if (typeof sup.extended == 'function') sup.extended(sub); | |
return sub; | |
} | |
function import$(obj, src){ | |
var own = {}.hasOwnProperty; | |
for (var key in src) if (own.call(src, key)) obj[key] = src[key]; | |
return obj; | |
} | |
function bind$(obj, key, target){ | |
return function(){ return (target || obj)[key].apply(obj, arguments) }; | |
} | |
function importAll$(obj, src){ | |
for (var key in src) obj[key] = src[key]; | |
return obj; | |
} | |
function in$(x, xs){ | |
var i = -1, l = xs.length >>> 0; | |
while (++i < l) if (x === xs[i]) return true; | |
return false; | |
} | |
}); | |
var filters = createCommonjsModule(function (module, exports) { | |
// Generated by LiveScript 1.6.0 | |
var sleep, FpsExec, out$ = exports || commonjsGlobal, toString$ = {}.toString; | |
sleep = lib$2.sleep; | |
out$.FpsExec = FpsExec = (function(){ | |
FpsExec.displayName = 'FpsExec'; | |
var prototype = FpsExec.prototype; | |
function FpsExec(opts){ | |
var fps, this$ = this instanceof ctor$ ? this : new ctor$; | |
opts == null && (opts = 20); | |
fps = toString$.call(opts).slice(8, -1) === 'Number' ? opts : void 8; | |
this$.debug = (function(){ | |
try { | |
return opts.debug; | |
} catch (e$) {} | |
}()); | |
this$.period = opts.period || 1000 / fps; | |
this$.timer = null; | |
this$.lastExec = 0; | |
this$.paused = false; | |
return this$; | |
} function ctor$(){} ctor$.prototype = prototype; | |
FpsExec.prototype.now = function(){ | |
return new Date().getTime(); | |
}; | |
FpsExec.prototype.pause = function(){ | |
return this.paused = true; | |
}; | |
FpsExec.prototype.resume = function(){ | |
var that; | |
if ((that = this._fn) != null) { | |
that.apply(null, this._args); | |
this._fn = null; | |
} | |
return this.paused = false; | |
}; | |
FpsExec.prototype.exec = function(func){ | |
var args, res$, i$, to$, timeToExec, this$ = this; | |
res$ = []; | |
for (i$ = 1, to$ = arguments.length; i$ < to$; ++i$) { | |
res$.push(arguments[i$]); | |
} | |
args = res$; | |
timeToExec = this.period - (this.now() - this.lastExec); | |
if (timeToExec < 0) { | |
timeToExec = 0; | |
} | |
try { | |
clearTimeout(this.timer); | |
if (this.debug) { | |
console.info("FpsExec is skipping an execution."); | |
} | |
} catch (e$) {} | |
return this.timer = sleep(timeToExec, function(){ | |
if (!this$.paused) { | |
func.apply(null, args); | |
return this$.lastExec = this$.now(); | |
} else { | |
this$._fn = func; | |
return this$._args = args; | |
} | |
}); | |
}; | |
return FpsExec; | |
}()); | |
/* | |
x = new FpsExec 15fps | |
# or | |
x = new FpsExec period: 3000ms | |
### Example Output: | |
[13:39:26.587] DbLogger : Read something: 10487 | |
[13:39:27.089] DbLogger : Read something: 10488 | |
[13:39:27.590] DbLogger : Read something: 10489 | |
[13:39:28.087] DbLogger : This is going to be recorded: 10489 | |
[13:39:28.091] DbLogger : Read something: 10490 | |
[13:39:28.591] DbLogger : Read something: 10491 | |
[13:39:29.092] DbLogger : Read something: 10492 | |
[13:39:29.593] DbLogger : Read something: 10493 | |
[13:39:30.091] DbLogger : This is going to be recorded: 10493 | |
[13:39:30.093] DbLogger : Read something: 10494 | |
[13:39:30.594] DbLogger : Read something: 10495 | |
[13:39:31.094] DbLogger : Read something: 10496 | |
[13:39:31.593] DbLogger : Read something: 10497 | |
[13:39:32.093] DbLogger : This is going to be recorded: 10497 | |
[13:39:32.096] DbLogger : Read something: 10498 | |
[13:39:32.597] DbLogger : Read something: 10499 | |
[13:39:33.098] DbLogger : Read something: 10500 | |
[13:39:33.598] DbLogger : Read something: 10501 | |
[13:39:34.096] DbLogger : This is going to be recorded: 10501 | |
[13:39:34.099] DbLogger : Read something: 10502 | |
[13:39:34.599] DbLogger : Read something: 10503 | |
[13:39:35.100] DbLogger : Read something: 10504 | |
[13:39:35.601] DbLogger : Read something: 10505 | |
[13:39:36.099] DbLogger : This is going to be recorded: 10505 | |
*/ | |
}); | |
var inherits_browser = createCommonjsModule(function (module) { | |
if (typeof Object.create === 'function') { | |
// implementation from standard node.js 'util' module | |
module.exports = function inherits(ctor, superCtor) { | |
if (superCtor) { | |
ctor.super_ = superCtor; | |
ctor.prototype = Object.create(superCtor.prototype, { | |
constructor: { | |
value: ctor, | |
enumerable: false, | |
writable: true, | |
configurable: true | |
} | |
}); | |
} | |
}; | |
} else { | |
// old school shim for old browsers | |
module.exports = function inherits(ctor, superCtor) { | |
if (superCtor) { | |
ctor.super_ = superCtor; | |
var TempCtor = function () {}; | |
TempCtor.prototype = superCtor.prototype; | |
ctor.prototype = new TempCtor(); | |
ctor.prototype.constructor = ctor; | |
} | |
}; | |
} | |
}); | |
var inherits = createCommonjsModule(function (module) { | |
try { | |
var util = util__default['default']; | |
/* istanbul ignore next */ | |
if (typeof util.inherits !== 'function') throw ''; | |
module.exports = util.inherits; | |
} catch (e) { | |
/* istanbul ignore next */ | |
module.exports = inherits_browser; | |
} | |
}); | |
var safeBuffer = createCommonjsModule(function (module, exports) { | |
/* eslint-disable node/no-deprecated-api */ | |
var Buffer = buffer__default['default'].Buffer; | |
// alternative to using Object.keys for old browsers | |
function copyProps (src, dst) { | |
for (var key in src) { | |
dst[key] = src[key]; | |
} | |
} | |
if (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) { | |
module.exports = buffer__default['default']; | |
} else { | |
// Copy properties from require('buffer') | |
copyProps(buffer__default['default'], exports); | |
exports.Buffer = SafeBuffer; | |
} | |
function SafeBuffer (arg, encodingOrOffset, length) { | |
return Buffer(arg, encodingOrOffset, length) | |
} | |
// Copy static methods from Buffer | |
copyProps(Buffer, SafeBuffer); | |
SafeBuffer.from = function (arg, encodingOrOffset, length) { | |
if (typeof arg === 'number') { | |
throw new TypeError('Argument must not be a number') | |
} | |
return Buffer(arg, encodingOrOffset, length) | |
}; | |
SafeBuffer.alloc = function (size, fill, encoding) { | |
if (typeof size !== 'number') { | |
throw new TypeError('Argument must be a number') | |
} | |
var buf = Buffer(size); | |
if (fill !== undefined) { | |
if (typeof encoding === 'string') { | |
buf.fill(fill, encoding); | |
} else { | |
buf.fill(fill); | |
} | |
} else { | |
buf.fill(0); | |
} | |
return buf | |
}; | |
SafeBuffer.allocUnsafe = function (size) { | |
if (typeof size !== 'number') { | |
throw new TypeError('Argument must be a number') | |
} | |
return Buffer(size) | |
}; | |
SafeBuffer.allocUnsafeSlow = function (size) { | |
if (typeof size !== 'number') { | |
throw new TypeError('Argument must be a number') | |
} | |
return buffer__default['default'].SlowBuffer(size) | |
}; | |
}); | |
var Buffer = safeBuffer.Buffer; | |
// prototype class for hash functions | |
function Hash (blockSize, finalSize) { | |
this._block = Buffer.alloc(blockSize); | |
this._finalSize = finalSize; | |
this._blockSize = blockSize; | |
this._len = 0; | |
} | |
Hash.prototype.update = function (data, enc) { | |
if (typeof data === 'string') { | |
enc = enc || 'utf8'; | |
data = Buffer.from(data, enc); | |
} | |
var block = this._block; | |
var blockSize = this._blockSize; | |
var length = data.length; | |
var accum = this._len; | |
for (var offset = 0; offset < length;) { | |
var assigned = accum % blockSize; | |
var remainder = Math.min(length - offset, blockSize - assigned); | |
for (var i = 0; i < remainder; i++) { | |
block[assigned + i] = data[offset + i]; | |
} | |
accum += remainder; | |
offset += remainder; | |
if ((accum % blockSize) === 0) { | |
this._update(block); | |
} | |
} | |
this._len += length; | |
return this | |
}; | |
Hash.prototype.digest = function (enc) { | |
var rem = this._len % this._blockSize; | |
this._block[rem] = 0x80; | |
// zero (rem + 1) trailing bits, where (rem + 1) is the smallest | |
// non-negative solution to the equation (length + 1 + (rem + 1)) === finalSize mod blockSize | |
this._block.fill(0, rem + 1); | |
if (rem >= this._finalSize) { | |
this._update(this._block); | |
this._block.fill(0); | |
} | |
var bits = this._len * 8; | |
// uint32 | |
if (bits <= 0xffffffff) { | |
this._block.writeUInt32BE(bits, this._blockSize - 4); | |
// uint64 | |
} else { | |
var lowBits = (bits & 0xffffffff) >>> 0; | |
var highBits = (bits - lowBits) / 0x100000000; | |
this._block.writeUInt32BE(highBits, this._blockSize - 8); | |
this._block.writeUInt32BE(lowBits, this._blockSize - 4); | |
} | |
this._update(this._block); | |
var hash = this._hash(); | |
return enc ? hash.toString(enc) : hash | |
}; | |
Hash.prototype._update = function () { | |
throw new Error('_update must be implemented by subclass') | |
}; | |
var hash = Hash; | |
/* | |
* A JavaScript implementation of the Secure Hash Algorithm, SHA-0, as defined | |
* in FIPS PUB 180-1 | |
* This source code is derived from sha1.js of the same repository. | |
* The difference between SHA-0 and SHA-1 is just a bitwise rotate left | |
* operation was added. | |
*/ | |
var Buffer$1 = safeBuffer.Buffer; | |
var K = [ | |
0x5a827999, 0x6ed9eba1, 0x8f1bbcdc | 0, 0xca62c1d6 | 0 | |
]; | |
var W = new Array(80); | |
function Sha () { | |
this.init(); | |
this._w = W; | |
hash.call(this, 64, 56); | |
} | |
inherits(Sha, hash); | |
Sha.prototype.init = function () { | |
this._a = 0x67452301; | |
this._b = 0xefcdab89; | |
this._c = 0x98badcfe; | |
this._d = 0x10325476; | |
this._e = 0xc3d2e1f0; | |
return this | |
}; | |
function rotl5 (num) { | |
return (num << 5) | (num >>> 27) | |
} | |
function rotl30 (num) { | |
return (num << 30) | (num >>> 2) | |
} | |
function ft (s, b, c, d) { | |
if (s === 0) return (b & c) | ((~b) & d) | |
if (s === 2) return (b & c) | (b & d) | (c & d) | |
return b ^ c ^ d | |
} | |
Sha.prototype._update = function (M) { | |
var W = this._w; | |
var a = this._a | 0; | |
var b = this._b | 0; | |
var c = this._c | 0; | |
var d = this._d | 0; | |
var e = this._e | 0; | |
for (var i = 0; i < 16; ++i) W[i] = M.readInt32BE(i * 4); | |
for (; i < 80; ++i) W[i] = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16]; | |
for (var j = 0; j < 80; ++j) { | |
var s = ~~(j / 20); | |
var t = (rotl5(a) + ft(s, b, c, d) + e + W[j] + K[s]) | 0; | |
e = d; | |
d = c; | |
c = rotl30(b); | |
b = a; | |
a = t; | |
} | |
this._a = (a + this._a) | 0; | |
this._b = (b + this._b) | 0; | |
this._c = (c + this._c) | 0; | |
this._d = (d + this._d) | 0; | |
this._e = (e + this._e) | 0; | |
}; | |
Sha.prototype._hash = function () { | |
var H = Buffer$1.allocUnsafe(20); | |
H.writeInt32BE(this._a | 0, 0); | |
H.writeInt32BE(this._b | 0, 4); | |
H.writeInt32BE(this._c | 0, 8); | |
H.writeInt32BE(this._d | 0, 12); | |
H.writeInt32BE(this._e | 0, 16); | |
return H | |
}; | |
var sha = Sha; | |
/* | |
* A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined | |
* in FIPS PUB 180-1 | |
* Version 2.1a Copyright Paul Johnston 2000 - 2002. | |
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet | |
* Distributed under the BSD License | |
* See http://pajhome.org.uk/crypt/md5 for details. | |
*/ | |
var Buffer$2 = safeBuffer.Buffer; | |
var K$1 = [ | |
0x5a827999, 0x6ed9eba1, 0x8f1bbcdc | 0, 0xca62c1d6 | 0 | |
]; | |
var W$1 = new Array(80); | |
function Sha1 () { | |
this.init(); | |
this._w = W$1; | |
hash.call(this, 64, 56); | |
} | |
inherits(Sha1, hash); | |
Sha1.prototype.init = function () { | |
this._a = 0x67452301; | |
this._b = 0xefcdab89; | |
this._c = 0x98badcfe; | |
this._d = 0x10325476; | |
this._e = 0xc3d2e1f0; | |
return this | |
}; | |
function rotl1 (num) { | |
return (num << 1) | (num >>> 31) | |
} | |
function rotl5$1 (num) { | |
return (num << 5) | (num >>> 27) | |
} | |
function rotl30$1 (num) { | |
return (num << 30) | (num >>> 2) | |
} | |
function ft$1 (s, b, c, d) { | |
if (s === 0) return (b & c) | ((~b) & d) | |
if (s === 2) return (b & c) | (b & d) | (c & d) | |
return b ^ c ^ d | |
} | |
Sha1.prototype._update = function (M) { | |
var W = this._w; | |
var a = this._a | 0; | |
var b = this._b | 0; | |
var c = this._c | 0; | |
var d = this._d | 0; | |
var e = this._e | 0; | |
for (var i = 0; i < 16; ++i) W[i] = M.readInt32BE(i * 4); | |
for (; i < 80; ++i) W[i] = rotl1(W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16]); | |
for (var j = 0; j < 80; ++j) { | |
var s = ~~(j / 20); | |
var t = (rotl5$1(a) + ft$1(s, b, c, d) + e + W[j] + K$1[s]) | 0; | |
e = d; | |
d = c; | |
c = rotl30$1(b); | |
b = a; | |
a = t; | |
} | |
this._a = (a + this._a) | 0; | |
this._b = (b + this._b) | 0; | |
this._c = (c + this._c) | 0; | |
this._d = (d + this._d) | 0; | |
this._e = (e + this._e) | 0; | |
}; | |
Sha1.prototype._hash = function () { | |
var H = Buffer$2.allocUnsafe(20); | |
H.writeInt32BE(this._a | 0, 0); | |
H.writeInt32BE(this._b | 0, 4); | |
H.writeInt32BE(this._c | 0, 8); | |
H.writeInt32BE(this._d | 0, 12); | |
H.writeInt32BE(this._e | 0, 16); | |
return H | |
}; | |
var sha1 = Sha1; | |
/** | |
* A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined | |
* in FIPS 180-2 | |
* Version 2.2-beta Copyright Angel Marin, Paul Johnston 2000 - 2009. | |
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet | |
* | |
*/ | |
var Buffer$3 = safeBuffer.Buffer; | |
var K$2 = [ | |
0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, | |
0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, | |
0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, | |
0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, | |
0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, | |
0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, | |
0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, | |
0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, | |
0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, | |
0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, | |
0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, | |
0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, | |
0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, | |
0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, | |
0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, | |
0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2 | |
]; | |
var W$2 = new Array(64); | |
function Sha256 () { | |
this.init(); | |
this._w = W$2; // new Array(64) | |
hash.call(this, 64, 56); | |
} | |
inherits(Sha256, hash); | |
Sha256.prototype.init = function () { | |
this._a = 0x6a09e667; | |
this._b = 0xbb67ae85; | |
this._c = 0x3c6ef372; | |
this._d = 0xa54ff53a; | |
this._e = 0x510e527f; | |
this._f = 0x9b05688c; | |
this._g = 0x1f83d9ab; | |
this._h = 0x5be0cd19; | |
return this | |
}; | |
function ch (x, y, z) { | |
return z ^ (x & (y ^ z)) | |
} | |
function maj (x, y, z) { | |
return (x & y) | (z & (x | y)) | |
} | |
function sigma0 (x) { | |
return (x >>> 2 | x << 30) ^ (x >>> 13 | x << 19) ^ (x >>> 22 | x << 10) | |
} | |
function sigma1 (x) { | |
return (x >>> 6 | x << 26) ^ (x >>> 11 | x << 21) ^ (x >>> 25 | x << 7) | |
} | |
function gamma0 (x) { | |
return (x >>> 7 | x << 25) ^ (x >>> 18 | x << 14) ^ (x >>> 3) | |
} | |
function gamma1 (x) { | |
return (x >>> 17 | x << 15) ^ (x >>> 19 | x << 13) ^ (x >>> 10) | |
} | |
Sha256.prototype._update = function (M) { | |
var W = this._w; | |
var a = this._a | 0; | |
var b = this._b | 0; | |
var c = this._c | 0; | |
var d = this._d | 0; | |
var e = this._e | 0; | |
var f = this._f | 0; | |
var g = this._g | 0; | |
var h = this._h | 0; | |
for (var i = 0; i < 16; ++i) W[i] = M.readInt32BE(i * 4); | |
for (; i < 64; ++i) W[i] = (gamma1(W[i - 2]) + W[i - 7] + gamma0(W[i - 15]) + W[i - 16]) | 0; | |
for (var j = 0; j < 64; ++j) { | |
var T1 = (h + sigma1(e) + ch(e, f, g) + K$2[j] + W[j]) | 0; | |
var T2 = (sigma0(a) + maj(a, b, c)) | 0; | |
h = g; | |
g = f; | |
f = e; | |
e = (d + T1) | 0; | |
d = c; | |
c = b; | |
b = a; | |
a = (T1 + T2) | 0; | |
} | |
this._a = (a + this._a) | 0; | |
this._b = (b + this._b) | 0; | |
this._c = (c + this._c) | 0; | |
this._d = (d + this._d) | 0; | |
this._e = (e + this._e) | 0; | |
this._f = (f + this._f) | 0; | |
this._g = (g + this._g) | 0; | |
this._h = (h + this._h) | 0; | |
}; | |
Sha256.prototype._hash = function () { | |
var H = Buffer$3.allocUnsafe(32); | |
H.writeInt32BE(this._a, 0); | |
H.writeInt32BE(this._b, 4); | |
H.writeInt32BE(this._c, 8); | |
H.writeInt32BE(this._d, 12); | |
H.writeInt32BE(this._e, 16); | |
H.writeInt32BE(this._f, 20); | |
H.writeInt32BE(this._g, 24); | |
H.writeInt32BE(this._h, 28); | |
return H | |
}; | |
var sha256 = Sha256; | |
/** | |
* A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined | |
* in FIPS 180-2 | |
* Version 2.2-beta Copyright Angel Marin, Paul Johnston 2000 - 2009. | |
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet | |
* | |
*/ | |
var Buffer$4 = safeBuffer.Buffer; | |
var W$3 = new Array(64); | |
function Sha224 () { | |
this.init(); | |
this._w = W$3; // new Array(64) | |
hash.call(this, 64, 56); | |
} | |
inherits(Sha224, sha256); | |
Sha224.prototype.init = function () { | |
this._a = 0xc1059ed8; | |
this._b = 0x367cd507; | |
this._c = 0x3070dd17; | |
this._d = 0xf70e5939; | |
this._e = 0xffc00b31; | |
this._f = 0x68581511; | |
this._g = 0x64f98fa7; | |
this._h = 0xbefa4fa4; | |
return this | |
}; | |
Sha224.prototype._hash = function () { | |
var H = Buffer$4.allocUnsafe(28); | |
H.writeInt32BE(this._a, 0); | |
H.writeInt32BE(this._b, 4); | |
H.writeInt32BE(this._c, 8); | |
H.writeInt32BE(this._d, 12); | |
H.writeInt32BE(this._e, 16); | |
H.writeInt32BE(this._f, 20); | |
H.writeInt32BE(this._g, 24); | |
return H | |
}; | |
var sha224 = Sha224; | |
var Buffer$5 = safeBuffer.Buffer; | |
var K$3 = [ | |
0x428a2f98, 0xd728ae22, 0x71374491, 0x23ef65cd, | |
0xb5c0fbcf, 0xec4d3b2f, 0xe9b5dba5, 0x8189dbbc, | |
0x3956c25b, 0xf348b538, 0x59f111f1, 0xb605d019, | |
0x923f82a4, 0xaf194f9b, 0xab1c5ed5, 0xda6d8118, | |
0xd807aa98, 0xa3030242, 0x12835b01, 0x45706fbe, | |
0x243185be, 0x4ee4b28c, 0x550c7dc3, 0xd5ffb4e2, | |
0x72be5d74, 0xf27b896f, 0x80deb1fe, 0x3b1696b1, | |
0x9bdc06a7, 0x25c71235, 0xc19bf174, 0xcf692694, | |
0xe49b69c1, 0x9ef14ad2, 0xefbe4786, 0x384f25e3, | |
0x0fc19dc6, 0x8b8cd5b5, 0x240ca1cc, 0x77ac9c65, | |
0x2de92c6f, 0x592b0275, 0x4a7484aa, 0x6ea6e483, | |
0x5cb0a9dc, 0xbd41fbd4, 0x76f988da, 0x831153b5, | |
0x983e5152, 0xee66dfab, 0xa831c66d, 0x2db43210, | |
0xb00327c8, 0x98fb213f, 0xbf597fc7, 0xbeef0ee4, | |
0xc6e00bf3, 0x3da88fc2, 0xd5a79147, 0x930aa725, | |
0x06ca6351, 0xe003826f, 0x14292967, 0x0a0e6e70, | |
0x27b70a85, 0x46d22ffc, 0x2e1b2138, 0x5c26c926, | |
0x4d2c6dfc, 0x5ac42aed, 0x53380d13, 0x9d95b3df, | |
0x650a7354, 0x8baf63de, 0x766a0abb, 0x3c77b2a8, | |
0x81c2c92e, 0x47edaee6, 0x92722c85, 0x1482353b, | |
0xa2bfe8a1, 0x4cf10364, 0xa81a664b, 0xbc423001, | |
0xc24b8b70, 0xd0f89791, 0xc76c51a3, 0x0654be30, | |
0xd192e819, 0xd6ef5218, 0xd6990624, 0x5565a910, | |
0xf40e3585, 0x5771202a, 0x106aa070, 0x32bbd1b8, | |
0x19a4c116, 0xb8d2d0c8, 0x1e376c08, 0x5141ab53, | |
0x2748774c, 0xdf8eeb99, 0x34b0bcb5, 0xe19b48a8, | |
0x391c0cb3, 0xc5c95a63, 0x4ed8aa4a, 0xe3418acb, | |
0x5b9cca4f, 0x7763e373, 0x682e6ff3, 0xd6b2b8a3, | |
0x748f82ee, 0x5defb2fc, 0x78a5636f, 0x43172f60, | |
0x84c87814, 0xa1f0ab72, 0x8cc70208, 0x1a6439ec, | |
0x90befffa, 0x23631e28, 0xa4506ceb, 0xde82bde9, | |
0xbef9a3f7, 0xb2c67915, 0xc67178f2, 0xe372532b, | |
0xca273ece, 0xea26619c, 0xd186b8c7, 0x21c0c207, | |
0xeada7dd6, 0xcde0eb1e, 0xf57d4f7f, 0xee6ed178, | |
0x06f067aa, 0x72176fba, 0x0a637dc5, 0xa2c898a6, | |
0x113f9804, 0xbef90dae, 0x1b710b35, 0x131c471b, | |
0x28db77f5, 0x23047d84, 0x32caab7b, 0x40c72493, | |
0x3c9ebe0a, 0x15c9bebc, 0x431d67c4, 0x9c100d4c, | |
0x4cc5d4be, 0xcb3e42b6, 0x597f299c, 0xfc657e2a, | |
0x5fcb6fab, 0x3ad6faec, 0x6c44198c, 0x4a475817 | |
]; | |
var W$4 = new Array(160); | |
function Sha512 () { | |
this.init(); | |
this._w = W$4; | |
hash.call(this, 128, 112); | |
} | |
inherits(Sha512, hash); | |
Sha512.prototype.init = function () { | |
this._ah = 0x6a09e667; | |
this._bh = 0xbb67ae85; | |
this._ch = 0x3c6ef372; | |
this._dh = 0xa54ff53a; | |
this._eh = 0x510e527f; | |
this._fh = 0x9b05688c; | |
this._gh = 0x1f83d9ab; | |
this._hh = 0x5be0cd19; | |
this._al = 0xf3bcc908; | |
this._bl = 0x84caa73b; | |
this._cl = 0xfe94f82b; | |
this._dl = 0x5f1d36f1; | |
this._el = 0xade682d1; | |
this._fl = 0x2b3e6c1f; | |
this._gl = 0xfb41bd6b; | |
this._hl = 0x137e2179; | |
return this | |
}; | |
function Ch (x, y, z) { | |
return z ^ (x & (y ^ z)) | |
} | |
function maj$1 (x, y, z) { | |
return (x & y) | (z & (x | y)) | |
} | |
function sigma0$1 (x, xl) { | |
return (x >>> 28 | xl << 4) ^ (xl >>> 2 | x << 30) ^ (xl >>> 7 | x << 25) | |
} | |
function sigma1$1 (x, xl) { | |
return (x >>> 14 | xl << 18) ^ (x >>> 18 | xl << 14) ^ (xl >>> 9 | x << 23) | |
} | |
function Gamma0 (x, xl) { | |
return (x >>> 1 | xl << 31) ^ (x >>> 8 | xl << 24) ^ (x >>> 7) | |
} | |
function Gamma0l (x, xl) { | |
return (x >>> 1 | xl << 31) ^ (x >>> 8 | xl << 24) ^ (x >>> 7 | xl << 25) | |
} | |
function Gamma1 (x, xl) { | |
return (x >>> 19 | xl << 13) ^ (xl >>> 29 | x << 3) ^ (x >>> 6) | |
} | |
function Gamma1l (x, xl) { | |
return (x >>> 19 | xl << 13) ^ (xl >>> 29 | x << 3) ^ (x >>> 6 | xl << 26) | |
} | |
function getCarry (a, b) { | |
return (a >>> 0) < (b >>> 0) ? 1 : 0 | |
} | |
Sha512.prototype._update = function (M) { | |
var W = this._w; | |
var ah = this._ah | 0; | |
var bh = this._bh | 0; | |
var ch = this._ch | 0; | |
var dh = this._dh | 0; | |
var eh = this._eh | 0; | |
var fh = this._fh | 0; | |
var gh = this._gh | 0; | |
var hh = this._hh | 0; | |
var al = this._al | 0; | |
var bl = this._bl | 0; | |
var cl = this._cl | 0; | |
var dl = this._dl | 0; | |
var el = this._el | 0; | |
var fl = this._fl | 0; | |
var gl = this._gl | 0; | |
var hl = this._hl | 0; | |
for (var i = 0; i < 32; i += 2) { | |
W[i] = M.readInt32BE(i * 4); | |
W[i + 1] = M.readInt32BE(i * 4 + 4); | |
} | |
for (; i < 160; i += 2) { | |
var xh = W[i - 15 * 2]; | |
var xl = W[i - 15 * 2 + 1]; | |
var gamma0 = Gamma0(xh, xl); | |
var gamma0l = Gamma0l(xl, xh); | |
xh = W[i - 2 * 2]; | |
xl = W[i - 2 * 2 + 1]; | |
var gamma1 = Gamma1(xh, xl); | |
var gamma1l = Gamma1l(xl, xh); | |
// W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16] | |
var Wi7h = W[i - 7 * 2]; | |
var Wi7l = W[i - 7 * 2 + 1]; | |
var Wi16h = W[i - 16 * 2]; | |
var Wi16l = W[i - 16 * 2 + 1]; | |
var Wil = (gamma0l + Wi7l) | 0; | |
var Wih = (gamma0 + Wi7h + getCarry(Wil, gamma0l)) | 0; | |
Wil = (Wil + gamma1l) | 0; | |
Wih = (Wih + gamma1 + getCarry(Wil, gamma1l)) | 0; | |
Wil = (Wil + Wi16l) | 0; | |
Wih = (Wih + Wi16h + getCarry(Wil, Wi16l)) | 0; | |
W[i] = Wih; | |
W[i + 1] = Wil; | |
} | |
for (var j = 0; j < 160; j += 2) { | |
Wih = W[j]; | |
Wil = W[j + 1]; | |
var majh = maj$1(ah, bh, ch); | |
var majl = maj$1(al, bl, cl); | |
var sigma0h = sigma0$1(ah, al); | |
var sigma0l = sigma0$1(al, ah); | |
var sigma1h = sigma1$1(eh, el); | |
var sigma1l = sigma1$1(el, eh); | |
// t1 = h + sigma1 + ch + K[j] + W[j] | |
var Kih = K$3[j]; | |
var Kil = K$3[j + 1]; | |
var chh = Ch(eh, fh, gh); | |
var chl = Ch(el, fl, gl); | |
var t1l = (hl + sigma1l) | 0; | |
var t1h = (hh + sigma1h + getCarry(t1l, hl)) | 0; | |
t1l = (t1l + chl) | 0; | |
t1h = (t1h + chh + getCarry(t1l, chl)) | 0; | |
t1l = (t1l + Kil) | 0; | |
t1h = (t1h + Kih + getCarry(t1l, Kil)) | 0; | |
t1l = (t1l + Wil) | 0; | |
t1h = (t1h + Wih + getCarry(t1l, Wil)) | 0; | |
// t2 = sigma0 + maj | |
var t2l = (sigma0l + majl) | 0; | |
var t2h = (sigma0h + majh + getCarry(t2l, sigma0l)) | 0; | |
hh = gh; | |
hl = gl; | |
gh = fh; | |
gl = fl; | |
fh = eh; | |
fl = el; | |
el = (dl + t1l) | 0; | |
eh = (dh + t1h + getCarry(el, dl)) | 0; | |
dh = ch; | |
dl = cl; | |
ch = bh; | |
cl = bl; | |
bh = ah; | |
bl = al; | |
al = (t1l + t2l) | 0; | |
ah = (t1h + t2h + getCarry(al, t1l)) | 0; | |
} | |
this._al = (this._al + al) | 0; | |
this._bl = (this._bl + bl) | 0; | |
this._cl = (this._cl + cl) | 0; | |
this._dl = (this._dl + dl) | 0; | |
this._el = (this._el + el) | 0; | |
this._fl = (this._fl + fl) | 0; | |
this._gl = (this._gl + gl) | 0; | |
this._hl = (this._hl + hl) | 0; | |
this._ah = (this._ah + ah + getCarry(this._al, al)) | 0; | |
this._bh = (this._bh + bh + getCarry(this._bl, bl)) | 0; | |
this._ch = (this._ch + ch + getCarry(this._cl, cl)) | 0; | |
this._dh = (this._dh + dh + getCarry(this._dl, dl)) | 0; | |
this._eh = (this._eh + eh + getCarry(this._el, el)) | 0; | |
this._fh = (this._fh + fh + getCarry(this._fl, fl)) | 0; | |
this._gh = (this._gh + gh + getCarry(this._gl, gl)) | 0; | |
this._hh = (this._hh + hh + getCarry(this._hl, hl)) | 0; | |
}; | |
Sha512.prototype._hash = function () { | |
var H = Buffer$5.allocUnsafe(64); | |
function writeInt64BE (h, l, offset) { | |
H.writeInt32BE(h, offset); | |
H.writeInt32BE(l, offset + 4); | |
} | |
writeInt64BE(this._ah, this._al, 0); | |
writeInt64BE(this._bh, this._bl, 8); | |
writeInt64BE(this._ch, this._cl, 16); | |
writeInt64BE(this._dh, this._dl, 24); | |
writeInt64BE(this._eh, this._el, 32); | |
writeInt64BE(this._fh, this._fl, 40); | |
writeInt64BE(this._gh, this._gl, 48); | |
writeInt64BE(this._hh, this._hl, 56); | |
return H | |
}; | |
var sha512 = Sha512; | |
var Buffer$6 = safeBuffer.Buffer; | |
var W$5 = new Array(160); | |
function Sha384 () { | |
this.init(); | |
this._w = W$5; | |
hash.call(this, 128, 112); | |
} | |
inherits(Sha384, sha512); | |
Sha384.prototype.init = function () { | |
this._ah = 0xcbbb9d5d; | |
this._bh = 0x629a292a; | |
this._ch = 0x9159015a; | |
this._dh = 0x152fecd8; | |
this._eh = 0x67332667; | |
this._fh = 0x8eb44a87; | |
this._gh = 0xdb0c2e0d; | |
this._hh = 0x47b5481d; | |
this._al = 0xc1059ed8; | |
this._bl = 0x367cd507; | |
this._cl = 0x3070dd17; | |
this._dl = 0xf70e5939; | |
this._el = 0xffc00b31; | |
this._fl = 0x68581511; | |
this._gl = 0x64f98fa7; | |
this._hl = 0xbefa4fa4; | |
return this | |
}; | |
Sha384.prototype._hash = function () { | |
var H = Buffer$6.allocUnsafe(48); | |
function writeInt64BE (h, l, offset) { | |
H.writeInt32BE(h, offset); | |
H.writeInt32BE(l, offset + 4); | |
} | |
writeInt64BE(this._ah, this._al, 0); | |
writeInt64BE(this._bh, this._bl, 8); | |
writeInt64BE(this._ch, this._cl, 16); | |
writeInt64BE(this._dh, this._dl, 24); | |
writeInt64BE(this._eh, this._el, 32); | |
writeInt64BE(this._fh, this._fl, 40); | |
return H | |
}; | |
var sha384 = Sha384; | |
var sha_js = createCommonjsModule(function (module) { | |
var exports = module.exports = function SHA (algorithm) { | |
algorithm = algorithm.toLowerCase(); | |
var Algorithm = exports[algorithm]; | |
if (!Algorithm) throw new Error(algorithm + ' is not supported (we accept pull requests)') | |
return new Algorithm() | |
}; | |
exports.sha = sha; | |
exports.sha1 = sha1; | |
exports.sha224 = sha224; | |
exports.sha256 = sha256; | |
exports.sha384 = sha384; | |
exports.sha512 = sha512; | |
}); | |
var authHelpers = createCommonjsModule(function (module, exports) { | |
// Generated by LiveScript 1.6.0 | |
var createHash, hashPasswd, AuthError, out$ = exports || commonjsGlobal; | |
createHash = sha_js; | |
out$.hashPasswd = hashPasswd = function(passwd){ | |
var sha512; | |
sha512 = createHash('sha512'); | |
return sha512.update(passwd, 'utf-8').digest('hex'); | |
}; | |
out$.AuthError = AuthError = (function(superclass){ | |
var prototype = extend$((import$(AuthError, superclass).displayName = 'AuthError', AuthError), superclass).prototype; | |
function AuthError(message){ | |
this.message = message; | |
AuthError.superclass.apply(this, arguments); | |
Error.captureStackTrace(this, AuthError); | |
this.type = 'AuthError'; | |
} | |
return AuthError; | |
}(Error)); | |
function extend$(sub, sup){ | |
function fun(){} fun.prototype = (sub.superclass = sup).prototype; | |
(sub.prototype = new fun).constructor = sub; | |
if (typeof sup.extended == 'function') sup.extended(sub); | |
return sub; | |
} | |
function import$(obj, src){ | |
var own = {}.hasOwnProperty; | |
for (var key in src) if (own.call(src, key)) obj[key] = src[key]; | |
return obj; | |
} | |
}); | |
var authRequest = createCommonjsModule(function (module, exports) { | |
// Generated by LiveScript 1.6.0 | |
var Signal, ref$, sleep, pack, clone, EventEmitter, Logger, red, green, yellow, bgRed, bgYellow, hashPasswd, topicMatch, keys, join, AuthRequest, out$ = exports || commonjsGlobal; | |
Signal = signal$1.Signal; | |
ref$ = lib$2, sleep = ref$.sleep, pack = ref$.pack, clone = ref$.clone, EventEmitter = ref$.EventEmitter, Logger = ref$.Logger; | |
ref$ = lib, red = ref$.red, green = ref$.green, yellow = ref$.yellow, bgRed = ref$.bgRed, bgYellow = ref$.bgYellow; | |
hashPasswd = authHelpers.hashPasswd; | |
topicMatch = topicMatch_1.topicMatch; | |
ref$ = lib$1, keys = ref$.keys, join = ref$.join; | |
out$.AuthRequest = AuthRequest = (function(){ | |
AuthRequest.displayName = 'AuthRequest'; | |
var constructor = AuthRequest; | |
AuthRequest.i = 0; | |
function AuthRequest(name){ | |
this.log = new Logger(name || "AuthRequest." + (constructor.i++)); | |
this.replySignal = new Signal(); | |
} | |
AuthRequest.prototype.inbox = function(msg){ | |
return this.replySignal.go(null, msg); | |
}; | |
AuthRequest.prototype.login = function(_credentials, callback){ | |
var credentials, err, this$ = this; | |
_credentials == null && (_credentials = {}); | |
credentials = clone(_credentials); | |
if (credentials.password) { | |
credentials.password = hashPasswd(credentials.password); | |
} else if (credentials.token != null) { | |
this.log.info("token is: ", credentials); | |
if (credentials.token.length < 10) { | |
err = "Token seems empty, not attempting to login."; | |
this.log.log(err); | |
callback(err = "Not a valid token", null); | |
return; | |
} | |
} | |
this.log.log("Trying to authenticate with", keys(credentials).join(', ')); | |
if (keys(credentials).length === 0) { | |
this.log.warn("Credentials empty! (why? is server restarted?)"); | |
callback(err = "EMPTY_CREDENTIALS"); | |
return; | |
} | |
this.write({ | |
auth: credentials | |
}); | |
this.replySignal.clear(); | |
return this.replySignal.wait(3000, function(err, res){ | |
var that, ref$, ref1$, ref2$; | |
if (that = res != null ? (ref$ = res.auth) != null ? (ref1$ = ref$.session) != null ? ref1$.token : void 8 : void 8 : void 8) { | |
this$.token = that; | |
} | |
return callback(err || (res != null ? (ref2$ = res.auth) != null ? ref2$.error : void 8 : void 8), res); | |
}); | |
}; | |
AuthRequest.prototype.logout = function(callback){ | |
var this$ = this; | |
this.write(this.addToken({ | |
auth: { | |
logout: true | |
} | |
})); | |
return this.replySignal.wait(3000, function(err, msg){ | |
if (!err && msg.auth.logout === 'ok') { | |
this$.log.log("clearing token from AuthRequest cache"); | |
this$.token = null; | |
} | |
return callback(err, msg); | |
}); | |
}; | |
AuthRequest.prototype.addToken = function(msg){ | |
return msg.token = this.token, msg; | |
}; | |
return AuthRequest; | |
}()); | |
}); | |
var uuid4 = createCommonjsModule(function (module, exports) { | |
var uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/; | |
exports = module.exports = genUUID; | |
exports.valid = isUUID; | |
function genUUID(callback) { | |
if (typeof callback !== "function") { | |
var rnd = crypto__default['default'].randomBytes(16); | |
rnd[6] = (rnd[6] & 0x0f) | 0x40; | |
rnd[8] = (rnd[8] & 0x3f) | 0x80; | |
rnd = rnd.toString("hex").match(/(.{8})(.{4})(.{4})(.{4})(.{12})/); | |
rnd.shift(); | |
return rnd.join("-"); | |
} | |
crypto__default['default'].randomBytes(16, function(err, rnd) { | |
if (err) return callback(err); | |
try { | |
rnd[6] = (rnd[6] & 0x0f) | 0x40; | |
rnd[8] = (rnd[8] & 0x3f) | 0x80; | |
rnd = rnd.toString("hex").match(/(.{8})(.{4})(.{4})(.{4})(.{12})/); | |
rnd.shift(); | |
return callback(null, rnd.join("-")); | |
} catch (err2) { | |
return callback(err2); | |
} | |
}); | |
} | |
function isUUID(uuid) { | |
return uuidPattern.test(uuid); | |
} | |
}); | |
var errors = createCommonjsModule(function (module, exports) { | |
// Generated by LiveScript 1.6.0 | |
var CodingError, out$ = exports || commonjsGlobal; | |
out$.CodingError = CodingError = (function(superclass){ | |
var prototype = extend$((import$(CodingError, superclass).displayName = 'CodingError', CodingError), superclass).prototype; | |
function CodingError(message){ | |
this.message = message; | |
CodingError.superclass.apply(this, arguments); | |
Error.captureStackTrace(this, CodingError); | |
this.type = 'CodingError'; | |
} | |
return CodingError; | |
}(Error)); | |
function extend$(sub, sup){ | |
function fun(){} fun.prototype = (sub.superclass = sup).prototype; | |
(sub.prototype = new fun).constructor = sub; | |
if (typeof sup.extended == 'function') sup.extended(sub); | |
return sub; | |
} | |
function import$(obj, src){ | |
var own = {}.hasOwnProperty; | |
for (var key in src) if (own.call(src, key)) obj[key] = src[key]; | |
return obj; | |
} | |
}); | |
var authHandler = createCommonjsModule(function (module, exports) { | |
// Generated by LiveScript 1.6.0 | |
var ref$, sleep, Logger, pack, EventEmitter, uuid4$1, red, green, yellow, bgRed, bgYellow, bgGreen, bgCyan, hashPasswd, AuthError, topicMatch, CodingError, SessionCache, AuthHandler, out$ = exports || commonjsGlobal; | |
ref$ = lib$2, sleep = ref$.sleep, Logger = ref$.Logger, pack = ref$.pack, EventEmitter = ref$.EventEmitter; | |
uuid4$1 = uuid4; | |
ref$ = lib, red = ref$.red, green = ref$.green, yellow = ref$.yellow, bgRed = ref$.bgRed, bgYellow = ref$.bgYellow, bgGreen = ref$.bgGreen, bgCyan = ref$.bgCyan; | |
ref$ = authHelpers, hashPasswd = ref$.hashPasswd, AuthError = ref$.AuthError; | |
topicMatch = topicMatch_1.topicMatch; | |
CodingError = errors.CodingError; | |
SessionCache = (function(){ | |
SessionCache.displayName = 'SessionCache'; | |
var constructor = SessionCache; | |
SessionCache.cache = {}; | |
SessionCache.instance = null; | |
function SessionCache(){ | |
if (constructor.instance) { | |
return constructor.instance; | |
} | |
constructor.instance = this; | |
this.log = new Logger('SessionCache'); | |
this.log.log(green("SessionCache is initialized", pack(constructor.cache))); | |
} | |
SessionCache.prototype.add = function(session){ | |
this.log.log(green("Adding session for " + session.user, yellow(session.token))); | |
return constructor.cache[session.token] = session; | |
}; | |
SessionCache.prototype.get = function(token){ | |
return constructor.cache[token]; | |
}; | |
SessionCache.prototype.drop = function(token){ | |
var ref$, ref1$; | |
this.log.log(yellow("Dropping session for user: " + constructor.cache[token].user + " token: " + token)); | |
return ref1$ = (ref$ = constructor.cache)[token], delete ref$[token], ref1$; | |
}; | |
return SessionCache; | |
}()); | |
out$.AuthHandler = AuthHandler = (function(superclass){ | |
var prototype = extend$((import$(AuthHandler, superclass).displayName = 'AuthHandler', AuthHandler), superclass).prototype, constructor = AuthHandler; | |
AuthHandler.loginDelay = 10; | |
AuthHandler.i = 0; | |
function AuthHandler(db, name){ | |
var this$ = this; | |
db != null || (function(){ | |
throw new CodingError("AuthDB instance is required."); | |
}()); | |
AuthHandler.superclass.call(this); | |
this.log = new Logger(name || "AuthHandler." + (constructor.i++)); | |
this.sessionCache = new SessionCache(); | |
this.on('check-auth', function(msg){ | |
var user, e, ref$, foundSession; | |
if (msg.debug) { | |
this$.log.log("Processing authentication message", msg); | |
} | |
if ('user' in msg.auth) { | |
try { | |
user = db.get(msg.auth.user); | |
if (user.passwdHash === msg.auth.password) { | |
this$.session = { | |
token: uuid4$1(), | |
user: msg.auth.user, | |
date: Date.now(), | |
routes: user.routes, | |
permissions: user.permissions | |
}; | |
this$.sessionCache.add(this$.session); | |
this$.log.log(bgGreen("new Login: " + msg.auth.user + " (" + this$.session.token + ")")); | |
this$.log.log("(...sending with " + constructor.loginDelay + "ms delay)"); | |
this$.trigger('login', this$.session); | |
return sleep(constructor.loginDelay, function(){ | |
return this$.trigger('to-client', { | |
auth: { | |
session: this$.session | |
} | |
}); | |
}); | |
} else { | |
this$.log.err("wrong password, tried:" + msg.auth.user + ", " + msg.auth.password); | |
return this$.trigger('to-client', { | |
auth: { | |
error: "wrong password" | |
} | |
}); | |
} | |
} catch (e$) { | |
e = e$; | |
this$.log.err("user \"" + msg.auth.user + "\" is not found. err: ", e); | |
return this$.trigger('to-client', { | |
auth: { | |
error: e | |
} | |
}); | |
} | |
} else if ('logout' in msg.auth) { | |
if (!this$.sessionCache.get(msg.token)) { | |
this$.log.log(bgYellow("No user found with the following token: " + msg.token + " ")); | |
this$.trigger('to-client', { | |
auth: { | |
logout: 'ok', | |
error: "no such user found" | |
} | |
}); | |
return this$.trigger('logout'); | |
} else { | |
this$.log.log("logging out for " + pack(this$.sessionCache.get(msg.token))); | |
this$.sessionCache.drop(msg.token); | |
this$.trigger('to-client', { | |
auth: { | |
logout: 'ok' | |
} | |
}); | |
return this$.trigger('logout'); | |
} | |
} else if ('token' in msg.auth) { | |
this$.log.log("Attempting to login with token: ", pack(msg.auth)); | |
if (((ref$ = this$.sessionCache.get(msg.auth.token)) != null ? ref$.token : void 8) === msg.auth.token) { | |
foundSession = this$.sessionCache.get(msg.auth.token); | |
this$.log.log(bgCyan("User \"" + foundSession.user + "\" has been logged in with token.")); | |
this$.trigger('login', foundSession); | |
return sleep(constructor.loginDelay, function(){ | |
return this$.trigger('to-client', { | |
auth: { | |
session: foundSession | |
} | |
}); | |
}); | |
} else { | |
this$.log.log(bgYellow("client doesn't seem to be logged in yet.")); | |
return sleep(constructor.loginDelay, function(){ | |
return this$.trigger('to-client', { | |
auth: { | |
session: { | |
logout: 'yes' | |
} | |
} | |
}); | |
}); | |
} | |
} else { | |
return this$.log.err(yellow("Can not determine which auth request this was: ", pack(msg))); | |
} | |
}); | |
} | |
AuthHandler.prototype.checkRoutes = function(msg){ | |
var session, i$, x$, ref$, len$; | |
session = this.sessionCache.get(msg.token); | |
if (session) { | |
for (i$ = 0, len$ = (ref$ = session.routes).length; i$ < len$; ++i$) { | |
x$ = ref$[i$]; | |
if (topicMatch(x$, msg.to)) { | |
delete msg.token; | |
return msg; | |
} | |
} | |
if (msg.re != null) { | |
delete msg.token; | |
return msg; | |
} | |
} | |
return this.log.err(bgRed("filter-incoming dropping unauthorized message!"), (function(){ | |
throw new AuthError('unauthorized message route'); | |
}())); | |
}; | |
AuthHandler.prototype.modifySender = function(msg){ | |
var session; | |
session = this.sessionCache.get(msg.token); | |
if (!session) { | |
throw new AuthError("No appropriate session is found."); | |
} | |
msg.from = "@" + session.user + "." + msg.from; | |
return msg; | |
}; | |
AuthHandler.prototype.addCtx = function(msg){ | |
var session; | |
session = this.sessionCache.get(msg.token); | |
msg.permissions = session.permissions; | |
msg.user = session.user; | |
return msg; | |
}; | |
return AuthHandler; | |
}(EventEmitter)); | |
function extend$(sub, sup){ | |
function fun(){} fun.prototype = (sub.superclass = sup).prototype; | |
(sub.prototype = new fun).constructor = sub; | |
if (typeof sup.extended == 'function') sup.extended(sub); | |
return sub; | |
} | |
function import$(obj, src){ | |
var own = {}.hasOwnProperty; | |
for (var key in src) if (own.call(src, key)) obj[key] = src[key]; | |
return obj; | |
} | |
}); | |
// Generated by LiveScript 1.6.0 | |
var ref$$2, sleep$2, pack$1, unpack$1, Logger$2, clone$2, brief$1, AuthRequest, Signal$2, Actor, topicMatch, AuthHandler; | |
ref$$2 = lib$2, sleep$2 = ref$$2.sleep, pack$1 = ref$$2.pack, unpack$1 = ref$$2.unpack, Logger$2 = ref$$2.Logger, clone$2 = ref$$2.clone; | |
brief$1 = debugTools.brief; | |
AuthRequest = authRequest.AuthRequest; | |
Signal$2 = signal$1.Signal; | |
Actor = actor.Actor; | |
topicMatch = topicMatch_1.topicMatch; | |
AuthHandler = authHandler.AuthHandler; | |
var deps$1 = { | |
sleep: sleep$2, | |
pack: pack$1, | |
unpack: unpack$1, | |
clone: clone$2, | |
Logger: Logger$2, | |
AuthRequest: AuthRequest, | |
AuthHandler: AuthHandler, | |
topicMatch: topicMatch, | |
Actor: Actor, | |
Signal: Signal$2, | |
brief: brief$1 | |
}; | |
var helpers = createCommonjsModule(function (module, exports) { | |
// Generated by LiveScript 1.6.0 | |
var ref$, sleep, pack, unpack, Logger, clone, split, flatten, splitAt, compact, MessageBinder, out$ = exports || commonjsGlobal, toString$ = {}.toString; | |
ref$ = lib$2, sleep = ref$.sleep, pack = ref$.pack, unpack = ref$.unpack, Logger = ref$.Logger, clone = ref$.clone; | |
ref$ = lib$1, split = ref$.split, flatten = ref$.flatten, splitAt = ref$.splitAt, compact = ref$.compact; | |
function unpackTelegrams(data){ | |
"Search for valid JSON telegrams recursively"; | |
var boundary, ref$, _first, _rest, nextSize, _firstTelegram, that, restTelegram, restStr, a, packets; | |
boundary = data.indexOf('}{'); | |
ref$ = compact(splitAt(boundary + 1, data)), _first = ref$[0], _rest = ref$[1]; | |
nextSize = 0; | |
try { | |
_firstTelegram = unpack(_first); | |
} catch (e$) { | |
return [[], data, nextSize]; | |
} | |
if (that = _firstTelegram != null ? _firstTelegram.size : void 8) { | |
nextSize = that; | |
_firstTelegram = null; | |
} | |
restTelegram = []; | |
restStr = ''; | |
if (_rest) { | |
ref$ = unpackTelegrams(_rest), restTelegram = ref$[0], restStr = ref$[1], a = ref$[2]; | |
if (nextSize > 0 && restTelegram.length > 0) { | |
nextSize = 0; | |
} | |
} | |
packets = compact(flatten([_firstTelegram, restTelegram])); | |
return [packets, restStr, nextSize]; | |
} | |
out$.MessageBinder = MessageBinder = (function(){ | |
MessageBinder.displayName = 'MessageBinder'; | |
function MessageBinder(){ | |
this.log = new Logger('MessageBinder'); | |
this.i = 0; | |
this.cache = ""; | |
this.heartbeat = 0; | |
this.timeout = 1400; | |
this.maxTry = 1200; | |
this.nextSize = 0; | |
} | |
MessageBinder.prototype.append = function(data){ | |
var ref$, res, y, size; | |
if (toString$.call(data).slice(8, -1) === 'Uint8Array') { | |
data = data.toString(); | |
} | |
if (this.heartbeat < Date.now() - this.timeout) { | |
this.cache = ''; | |
this.i = 0; | |
this.nextSize = 0; | |
} | |
this.cache += data; | |
if (this.nextSize > 0) { | |
if (this.cache.length < this.nextSize) { | |
return []; | |
} else { | |
this.nextSize = 0; | |
} | |
} | |
this.i++; | |
if (this.i > this.maxTry) { | |
this.log.err("Caching isn't enough, giving up."); | |
this.i = 0; | |
this.cache = data; | |
this.nextSize = 0; | |
} | |
this.heartbeat = Date.now(); | |
ref$ = unpackTelegrams(this.cache), res = ref$[0], y = ref$[1], size = ref$[2]; | |
if (size > 0) { | |
this.nextSize = size; | |
} | |
this.cache = y; | |
this.i = 0; | |
return res; | |
}; | |
return MessageBinder; | |
}()); | |
}); | |
var client = createCommonjsModule(function (module, exports) { | |
// Generated by LiveScript 1.6.0 | |
var ref$, AuthRequest, sleep, pack, unpack, Signal, Actor, topicMatch, clone, brief, split, flatten, splitAt, empty, reject, MessageBinder, ProxyClient, out$ = exports || commonjsGlobal, toString$ = {}.toString; | |
ref$ = deps$1, AuthRequest = ref$.AuthRequest, sleep = ref$.sleep, pack = ref$.pack, unpack = ref$.unpack, Signal = ref$.Signal, Actor = ref$.Actor, topicMatch = ref$.topicMatch, clone = ref$.clone, brief = ref$.brief; | |
ref$ = lib$1, split = ref$.split, flatten = ref$.flatten, splitAt = ref$.splitAt, empty = ref$.empty, reject = ref$.reject; | |
MessageBinder = helpers.MessageBinder; | |
out$.ProxyClient = ProxyClient = (function(superclass){ | |
var prototype = extend$((import$(ProxyClient, superclass).displayName = 'ProxyClient', ProxyClient), superclass).prototype; | |
function ProxyClient(transport, opts){ | |
this.transport = transport; | |
this.opts = opts; | |
ProxyClient.superclass.call(this, this.opts.name || 'ProxyClient'); | |
} | |
ProxyClient.prototype.action = function(){ | |
var x$, totalDelay, y$, this$ = this; | |
this.role = 'client'; | |
this.connected = false; | |
this.session = null; | |
this._transport_busy = false; | |
x$ = this.auth = new AuthRequest(this.name); | |
x$.write = function(msg){ | |
return this$.transport.write(pack(msg)); | |
}; | |
this.onTopic('app.dcs.update', function(msg){ | |
var debug; | |
debug = false; | |
if (debug) { | |
this$.log.debug("Received connection status update: ", msg); | |
} | |
return this$.sendResponse(msg, { | |
debug: debug | |
}, this$.session); | |
}); | |
this.on('disconnect', function(){ | |
this$.subscriptions = reject(function(it){ | |
var ref$; | |
return topicMatch(it, (ref$ = this$.session) != null ? ref$.routes : void 8); | |
}, this$.subscriptions); | |
this$.session = null; | |
return this$.send('app.dcs.disconnect'); | |
}); | |
this.on('connect', function(){ | |
return this$.trigger('_login'); | |
}); | |
this.on('receive', function(msg){ | |
if (!topicMatch(msg.to, "app.**")) { | |
if (!topicMatch(msg.to, this$.subscriptions)) { | |
this$.log.err("Possible coding error: We don't have a route for: ", msg); | |
this$.log.info("Our subscriptions: ", this$.subscriptions); | |
this$.sendResponse(msg, { | |
err: "How come the ProxyClient is subscribed a topicthat it has no rights to send? This is a DCS malfunction." | |
}); | |
return; | |
} | |
if (this$._transport_busy) { | |
this$.log.err("Transport was busy, we shouldn't try to send ", msg); | |
this$.log.info("...will retry to write to transport in 500ms."); | |
debugger; | |
sleep(500, function(){ | |
return this$.trigger('receive', msg); | |
}); | |
return; | |
} | |
this$._transport_busy = true; | |
this$.transport.write( | |
function(s){ | |
if (msg.debug) { | |
this$.log.debug("Sending " + msg.seq + "->" + msg.to + " size: " + s.length); | |
} | |
return pack({ | |
size: s.length | |
}) + s; | |
}( | |
pack( | |
this$.auth.addToken( | |
function(m){ | |
var responseId; | |
if (m.debug) { | |
this$.log.debug("Forwarding DCS to transport: ", brief(m)); | |
} | |
if (m.re != null) { | |
responseId = m.to + ""; | |
if (m.part == null || m.part === -1) { | |
this$.unsubscribe(responseId); | |
} | |
} | |
return m; | |
}( | |
msg))))); | |
if (msg.debug) { | |
this$.log.debug("Data is sent."); | |
} | |
return this$._transport_busy = false; | |
} | |
}); | |
this.m = new MessageBinder(); | |
totalDelay = 0; | |
y$ = this.transport; | |
y$.on('connect', function(){ | |
this$.connected = true; | |
return this$.log.success("My transport is connected, re-logging-in."); | |
}); | |
y$.on('disconnect', function(){ | |
this$.connected = false; | |
return this$.log.warn("My transport is disconnected."); | |
}); | |
y$.on("data", function(data){ | |
var t0, x, i$, len$, msg, responseRoute, that, msg2; | |
t0 = Date.now(); | |
x = this$.m.append(data); | |
totalDelay = totalDelay + (Date.now() - t0); | |
for (i$ = 0, len$ = x.length; i$ < len$; ++i$) { | |
msg = x[i$]; | |
if (totalDelay > 100) { | |
this$.log.debug("....time spent for concatenating: " + totalDelay + "ms"); | |
} | |
totalDelay = 0; | |
if ('auth' in msg) { | |
this$.auth.inbox(msg); | |
} else { | |
if (msg.debug) { | |
this$.log.debug("Forwarding Transport to DCS:", brief(msg)); | |
} | |
if (msg.req) { | |
responseRoute = msg.from + ""; | |
if (msg.debug) { | |
this$.log.debug("Transient subscription to response route: " + responseRoute); | |
} | |
this$.subscribe(responseRoute); | |
} | |
if (msg.re != null) { | |
msg.to = msg.to.replace("@" + this$.session.user + ".", ''); | |
if (that = this$.mgr.findActor(msg.to)) { | |
that._inbox(msg); | |
} | |
if (msg.cc) { | |
msg2 = clone(msg); | |
msg2.to = msg.cc; | |
msg2._exclude = msg.to; | |
this$.sendEnveloped(msg2); | |
} | |
return; | |
} | |
this$.sendEnveloped(msg); | |
} | |
} | |
}); | |
return y$; | |
}; | |
Object.defineProperty(ProxyClient.prototype, 'connected', { | |
get: function(){ | |
return this._connected; | |
}, | |
set: function(curr){ | |
var prev; | |
prev = this._connected; | |
this._connected = curr; | |
if (curr && !prev) { | |
this.trigger('connect'); | |
} | |
if (!curr && prev) { | |
this.trigger('disconnect'); | |
} | |
}, | |
configurable: true, | |
enumerable: true | |
}); | |
ProxyClient.prototype.login = function(credentials, callback){ | |
var this$ = this; | |
if (toString$.call(credentials).slice(8, -1) === 'Function') { | |
callback = credentials; | |
credentials = null; | |
} else if (!callback) { | |
callback = function(err, res){ | |
var ref$; | |
if (err) { | |
return this$.log.err("Something went wrong while login: ", pack(err)); | |
} else if ((ref$ = res.auth) != null && ref$.error) { | |
return this$.log.err("Wrong credentials?"); | |
} else { | |
return this$.log.success("Logged in into the DCS network."); | |
} | |
}; | |
} | |
this.off('_login'); | |
this.on('_login', function(opts){ | |
this$.log.log("sending credentials..."); | |
return this$.auth.login(credentials, function(err, res){ | |
var error, ref$, ref1$, ref2$, i$, x$, ref3$, len$, ref4$; | |
error = err || (res != null ? (ref$ = res.auth) != null ? ref$.error : void 8 : void 8) || (res != null ? (ref1$ = res.auth) != null ? (ref2$ = ref1$.session) != null ? ref2$.logout : void 8 : void 8 : void 8) === 'yes'; | |
if (!error) { | |
this$.session = (function(){ | |
try { | |
return res.auth.session; | |
} catch (e$) { | |
this.log.error("FIXME: We have empty session: ", res); | |
return {}; | |
} | |
}.call(this$)); | |
this$.subscriptions = this$.subscriptions.concat(this$.session.routes); | |
this$.log.info("Remote route subscriptions: "); | |
for (i$ = 0, len$ = (ref3$ = flatten([this$.subscriptions])).length; i$ < len$; ++i$) { | |
x$ = ref3$[i$]; | |
this$.log.info("-> " + x$); | |
} | |
this$.log.info("Emitting app.dcs.connect"); | |
this$.send('app.dcs.connect', this$.session); | |
this$.trigger('logged-in', this$.session, function(){ | |
var ref$; | |
return credentials = { | |
token: (ref$ = this$.session) != null ? ref$.token : void 8 | |
}; | |
}); | |
} else { | |
this$.connected = false; | |
} | |
if ((res != null ? (ref3$ = res.auth) != null ? (ref4$ = ref3$.session) != null ? ref4$.logout : void 8 : void 8 : void 8) === 'yes') { | |
this$.trigger('kicked-out'); | |
} | |
return callback(error, res); | |
}); | |
}); | |
if (this.connected) { | |
return this.trigger('_login'); | |
} | |
}; | |
ProxyClient.prototype.logout = function(callback){ | |
var this$ = this; | |
return this.auth.logout(function(err, res){ | |
var reason, ref$; | |
this$.log.info("Logged out; err, res: ", err, res); | |
reason = res != null ? (ref$ = res.auth) != null ? ref$.error : void 8 : void 8; | |
this$.trigger('logged-out', reason); | |
return callback(err, res); | |
}); | |
}; | |
return ProxyClient; | |
}(Actor)); | |
function extend$(sub, sup){ | |
function fun(){} fun.prototype = (sub.superclass = sup).prototype; | |
(sub.prototype = new fun).constructor = sub; | |
if (typeof sup.extended == 'function') sup.extended(sub); | |
return sub; | |
} | |
function import$(obj, src){ | |
var own = {}.hasOwnProperty; | |
for (var key in src) if (own.call(src, key)) obj[key] = src[key]; | |
return obj; | |
} | |
}); | |
/** | |
* Helpers. | |
*/ | |
var s = 1000; | |
var m = s * 60; | |
var h = m * 60; | |
var d = h * 24; | |
var w = d * 7; | |
var y = d * 365.25; | |
/** | |
* Parse or format the given `val`. | |
* | |
* Options: | |
* | |
* - `long` verbose formatting [false] | |
* | |
* @param {String|Number} val | |
* @param {Object} [options] | |
* @throws {Error} throw an error if val is not a non-empty string or a number | |
* @return {String|Number} | |
* @api public | |
*/ | |
var ms = function(val, options) { | |
options = options || {}; | |
var type = typeof val; | |
if (type === 'string' && val.length > 0) { | |
return parse(val); | |
} else if (type === 'number' && isFinite(val)) { | |
return options.long ? fmtLong(val) : fmtShort(val); | |
} | |
throw new Error( | |
'val is not a non-empty string or a valid number. val=' + | |
JSON.stringify(val) | |
); | |
}; | |
/** | |
* Parse the given `str` and return milliseconds. | |
* | |
* @param {String} str | |
* @return {Number} | |
* @api private | |
*/ | |
function parse(str) { | |
str = String(str); | |
if (str.length > 100) { | |
return; | |
} | |
var match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec( | |
str | |
); | |
if (!match) { | |
return; | |
} | |
var n = parseFloat(match[1]); | |
var type = (match[2] || 'ms').toLowerCase(); | |
switch (type) { | |
case 'years': | |
case 'year': | |
case 'yrs': | |
case 'yr': | |
case 'y': | |
return n * y; | |
case 'weeks': | |
case 'week': | |
case 'w': | |
return n * w; | |
case 'days': | |
case 'day': | |
case 'd': | |
return n * d; | |
case 'hours': | |
case 'hour': | |
case 'hrs': | |
case 'hr': | |
case 'h': | |
return n * h; | |
case 'minutes': | |
case 'minute': | |
case 'mins': | |
case 'min': | |
case 'm': | |
return n * m; | |
case 'seconds': | |
case 'second': | |
case 'secs': | |
case 'sec': | |
case 's': | |
return n * s; | |
case 'milliseconds': | |
case 'millisecond': | |
case 'msecs': | |
case 'msec': | |
case 'ms': | |
return n; | |
default: | |
return undefined; | |
} | |
} | |
/** | |
* Short format for `ms`. | |
* | |
* @param {Number} ms | |
* @return {String} | |
* @api private | |
*/ | |
function fmtShort(ms) { | |
var msAbs = Math.abs(ms); | |
if (msAbs >= d) { | |
return Math.round(ms / d) + 'd'; | |
} | |
if (msAbs >= h) { | |
return Math.round(ms / h) + 'h'; | |
} | |
if (msAbs >= m) { | |
return Math.round(ms / m) + 'm'; | |
} | |
if (msAbs >= s) { | |
return Math.round(ms / s) + 's'; | |
} | |
return ms + 'ms'; | |
} | |
/** | |
* Long format for `ms`. | |
* | |
* @param {Number} ms | |
* @return {String} | |
* @api private | |
*/ | |
function fmtLong(ms) { | |
var msAbs = Math.abs(ms); | |
if (msAbs >= d) { | |
return plural(ms, msAbs, d, 'day'); | |
} | |
if (msAbs >= h) { | |
return plural(ms, msAbs, h, 'hour'); | |
} | |
if (msAbs >= m) { | |
return plural(ms, msAbs, m, 'minute'); | |
} | |
if (msAbs >= s) { | |
return plural(ms, msAbs, s, 'second'); | |
} | |
return ms + ' ms'; | |
} | |
/** | |
* Pluralization helper. | |
*/ | |
function plural(ms, msAbs, n, name) { | |
var isPlural = msAbs >= n * 1.5; | |
return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : ''); | |
} | |
var debug = createCommonjsModule(function (module, exports) { | |
/** | |
* This is the common logic for both the Node.js and web browser | |
* implementations of `debug()`. | |
* | |
* Expose `debug()` as the module. | |
*/ | |
exports = module.exports = createDebug.debug = createDebug['default'] = createDebug; | |
exports.coerce = coerce; | |
exports.disable = disable; | |
exports.enable = enable; | |
exports.enabled = enabled; | |
exports.humanize = ms; | |
/** | |
* The currently active debug mode names, and names to skip. | |
*/ | |
exports.names = []; | |
exports.skips = []; | |
/** | |
* Map of special "%n" handling functions, for the debug "format" argument. | |
* | |
* Valid key names are a single, lower or upper-case letter, i.e. "n" and "N". | |
*/ | |
exports.formatters = {}; | |
/** | |
* Previous log timestamp. | |
*/ | |
var prevTime; | |
/** | |
* Select a color. | |
* @param {String} namespace | |
* @return {Number} | |
* @api private | |
*/ | |
function selectColor(namespace) { | |
var hash = 0, i; | |
for (i in namespace) { | |
hash = ((hash << 5) - hash) + namespace.charCodeAt(i); | |
hash |= 0; // Convert to 32bit integer | |
} | |
return exports.colors[Math.abs(hash) % exports.colors.length]; | |
} | |
/** | |
* Create a debugger with the given `namespace`. | |
* | |
* @param {String} namespace | |
* @return {Function} | |
* @api public | |
*/ | |
function createDebug(namespace) { | |
function debug() { | |
// disabled? | |
if (!debug.enabled) return; | |
var self = debug; | |
// set `diff` timestamp | |
var curr = +new Date(); | |
var ms = curr - (prevTime || curr); | |
self.diff = ms; | |
self.prev = prevTime; | |
self.curr = curr; | |
prevTime = curr; | |
// turn the `arguments` into a proper Array | |
var args = new Array(arguments.length); | |
for (var i = 0; i < args.length; i++) { | |
args[i] = arguments[i]; | |
} | |
args[0] = exports.coerce(args[0]); | |
if ('string' !== typeof args[0]) { | |
// anything else let's inspect with %O | |
args.unshift('%O'); | |
} | |
// apply any `formatters` transformations | |
var index = 0; | |
args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) { | |
// if we encounter an escaped % then don't increase the array index | |
if (match === '%%') return match; | |
index++; | |
var formatter = exports.formatters[format]; | |
if ('function' === typeof formatter) { | |
var val = args[index]; | |
match = formatter.call(self, val); | |
// now we need to remove `args[index]` since it's inlined in the `format` | |
args.splice(index, 1); | |
index--; | |
} | |
return match; | |
}); | |
// apply env-specific formatting (colors, etc.) | |
exports.formatArgs.call(self, args); | |
var logFn = debug.log || exports.log || console.log.bind(console); | |
logFn.apply(self, args); | |
} | |
debug.namespace = namespace; | |
debug.enabled = exports.enabled(namespace); | |
debug.useColors = exports.useColors(); | |
debug.color = selectColor(namespace); | |
// env-specific initialization logic for debug instances | |
if ('function' === typeof exports.init) { | |
exports.init(debug); | |
} | |
return debug; | |
} | |
/** | |
* Enables a debug mode by namespaces. This can include modes | |
* separated by a colon and wildcards. | |
* | |
* @param {String} namespaces | |
* @api public | |
*/ | |
function enable(namespaces) { | |
exports.save(namespaces); | |
exports.names = []; | |
exports.skips = []; | |
var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/); | |
var len = split.length; | |
for (var i = 0; i < len; i++) { | |
if (!split[i]) continue; // ignore empty strings | |
namespaces = split[i].replace(/\*/g, '.*?'); | |
if (namespaces[0] === '-') { | |
exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$')); | |
} else { | |
exports.names.push(new RegExp('^' + namespaces + '$')); | |
} | |
} | |
} | |
/** | |
* Disable debug output. | |
* | |
* @api public | |
*/ | |
function disable() { | |
exports.enable(''); | |
} | |
/** | |
* Returns true if the given mode name is enabled, false otherwise. | |
* | |
* @param {String} name | |
* @return {Boolean} | |
* @api public | |
*/ | |
function enabled(name) { | |
var i, len; | |
for (i = 0, len = exports.skips.length; i < len; i++) { | |
if (exports.skips[i].test(name)) { | |
return false; | |
} | |
} | |
for (i = 0, len = exports.names.length; i < len; i++) { | |
if (exports.names[i].test(name)) { | |
return true; | |
} | |
} | |
return false; | |
} | |
/** | |
* Coerce `val`. | |
* | |
* @param {Mixed} val | |
* @return {Mixed} | |
* @api private | |
*/ | |
function coerce(val) { | |
if (val instanceof Error) return val.stack || val.message; | |
return val; | |
} | |
}); | |
var browser = createCommonjsModule(function (module, exports) { | |
/** | |
* This is the web browser implementation of `debug()`. | |
* | |
* Expose `debug()` as the module. | |
*/ | |
exports = module.exports = debug; | |
exports.log = log; | |
exports.formatArgs = formatArgs; | |
exports.save = save; | |
exports.load = load; | |
exports.useColors = useColors; | |
exports.storage = 'undefined' != typeof chrome | |
&& 'undefined' != typeof chrome.storage | |
? chrome.storage.local | |
: localstorage(); | |
/** | |
* Colors. | |
*/ | |
exports.colors = [ | |
'lightseagreen', | |
'forestgreen', | |
'goldenrod', | |
'dodgerblue', | |
'darkorchid', | |
'crimson' | |
]; | |
/** | |
* Currently only WebKit-based Web Inspectors, Firefox >= v31, | |
* and the Firebug extension (any Firefox version) are known | |
* to support "%c" CSS customizations. | |
* | |
* TODO: add a `localStorage` variable to explicitly enable/disable colors | |
*/ | |
function useColors() { | |
// NB: In an Electron preload script, document will be defined but not fully | |
// initialized. Since we know we're in Chrome, we'll just detect this case | |
// explicitly | |
if (typeof window !== 'undefined' && window.process && window.process.type === 'renderer') { | |
return true; | |
} | |
// is webkit? http://stackoverflow.com/a/16459606/376773 | |
// document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 | |
return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) || | |
// is firebug? http://stackoverflow.com/a/398120/376773 | |
(typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) || | |
// is firefox >= v31? | |
// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages | |
(typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) || | |
// double check webkit in userAgent just in case we are in a worker | |
(typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)); | |
} | |
/** | |
* Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. | |
*/ | |
exports.formatters.j = function(v) { | |
try { | |
return JSON.stringify(v); | |
} catch (err) { | |
return '[UnexpectedJSONParseError]: ' + err.message; | |
} | |
}; | |
/** | |
* Colorize log arguments if enabled. | |
* | |
* @api public | |
*/ | |
function formatArgs(args) { | |
var useColors = this.useColors; | |
args[0] = (useColors ? '%c' : '') | |
+ this.namespace | |
+ (useColors ? ' %c' : ' ') | |
+ args[0] | |
+ (useColors ? '%c ' : ' ') | |
+ '+' + exports.humanize(this.diff); | |
if (!useColors) return; | |
var c = 'color: ' + this.color; | |
args.splice(1, 0, c, 'color: inherit'); | |
// the final "%c" is somewhat tricky, because there could be other | |
// arguments passed either before or after the %c, so we need to | |
// figure out the correct index to insert the CSS into | |
var index = 0; | |
var lastC = 0; | |
args[0].replace(/%[a-zA-Z%]/g, function(match) { | |
if ('%%' === match) return; | |
index++; | |
if ('%c' === match) { | |
// we only are interested in the *last* %c | |
// (the user may have provided their own) | |
lastC = index; | |
} | |
}); | |
args.splice(lastC, 0, c); | |
} | |
/** | |
* Invokes `console.log()` when available. | |
* No-op when `console.log` is not a "function". | |
* | |
* @api public | |
*/ | |
function log() { | |
// this hackery is required for IE8/9, where | |
// the `console.log` function doesn't have 'apply' | |
return 'object' === typeof console | |
&& console.log | |
&& Function.prototype.apply.call(console.log, console, arguments); | |
} | |
/** | |
* Save `namespaces`. | |
* | |
* @param {String} namespaces | |
* @api private | |
*/ | |
function save(namespaces) { | |
try { | |
if (null == namespaces) { | |
exports.storage.removeItem('debug'); | |
} else { | |
exports.storage.debug = namespaces; | |
} | |
} catch(e) {} | |
} | |
/** | |
* Load `namespaces`. | |
* | |
* @return {String} returns the previously persisted debug modes | |
* @api private | |
*/ | |
function load() { | |
var r; | |
try { | |
r = exports.storage.debug; | |
} catch(e) {} | |
// If debug isn't set in LS, and we're in Electron, try to load $DEBUG | |
if (!r && typeof process !== 'undefined' && 'env' in process) { | |
r = process.env.DEBUG; | |
} | |
return r; | |
} | |
/** | |
* Enable namespaces listed in `localStorage.debug` initially. | |
*/ | |
exports.enable(load()); | |
/** | |
* Localstorage attempts to return the localstorage. | |
* | |
* This is necessary because safari throws | |
* when a user disables cookies/localstorage | |
* and you attempt to access it. | |
* | |
* @return {LocalStorage} | |
* @api private | |
*/ | |
function localstorage() { | |
try { | |
return window.localStorage; | |
} catch (e) {} | |
} | |
}); | |
var node = createCommonjsModule(function (module, exports) { | |
/** | |
* Module dependencies. | |
*/ | |
/** | |
* This is the Node.js implementation of `debug()`. | |
* | |
* Expose `debug()` as the module. | |
*/ | |
exports = module.exports = debug; | |
exports.init = init; | |
exports.log = log; | |
exports.formatArgs = formatArgs; | |
exports.save = save; | |
exports.load = load; | |
exports.useColors = useColors; | |
/** | |
* Colors. | |
*/ | |
exports.colors = [6, 2, 3, 4, 5, 1]; | |
/** | |
* Build up the default `inspectOpts` object from the environment variables. | |
* | |
* $ DEBUG_COLORS=no DEBUG_DEPTH=10 DEBUG_SHOW_HIDDEN=enabled node script.js | |
*/ | |
exports.inspectOpts = Object.keys(process.env).filter(function (key) { | |
return /^debug_/i.test(key); | |
}).reduce(function (obj, key) { | |
// camel-case | |
var prop = key | |
.substring(6) | |
.toLowerCase() | |
.replace(/_([a-z])/g, function (_, k) { return k.toUpperCase() }); | |
// coerce string value into JS value | |
var val = process.env[key]; | |
if (/^(yes|on|true|enabled)$/i.test(val)) val = true; | |
else if (/^(no|off|false|disabled)$/i.test(val)) val = false; | |
else if (val === 'null') val = null; | |
else val = Number(val); | |
obj[prop] = val; | |
return obj; | |
}, {}); | |
/** | |
* The file descriptor to write the `debug()` calls to. | |
* Set the `DEBUG_FD` env variable to override with another value. i.e.: | |
* | |
* $ DEBUG_FD=3 node script.js 3>debug.log | |
*/ | |
var fd = parseInt(process.env.DEBUG_FD, 10) || 2; | |
if (1 !== fd && 2 !== fd) { | |
util__default['default'].deprecate(function(){}, 'except for stderr(2) and stdout(1), any other usage of DEBUG_FD is deprecated. Override debug.log if you want to use a different log function (https://git.io/debug_fd)')(); | |
} | |
var stream = 1 === fd ? process.stdout : | |
2 === fd ? process.stderr : | |
createWritableStdioStream(fd); | |
/** | |
* Is stdout a TTY? Colored output is enabled when `true`. | |
*/ | |
function useColors() { | |
return 'colors' in exports.inspectOpts | |
? Boolean(exports.inspectOpts.colors) | |
: tty__default['default'].isatty(fd); | |
} | |
/** | |
* Map %o to `util.inspect()`, all on a single line. | |
*/ | |
exports.formatters.o = function(v) { | |
this.inspectOpts.colors = this.useColors; | |
return util__default['default'].inspect(v, this.inspectOpts) | |
.split('\n').map(function(str) { | |
return str.trim() | |
}).join(' '); | |
}; | |
/** | |
* Map %o to `util.inspect()`, allowing multiple lines if needed. | |
*/ | |
exports.formatters.O = function(v) { | |
this.inspectOpts.colors = this.useColors; | |
return util__default['default'].inspect(v, this.inspectOpts); | |
}; | |
/** | |
* Adds ANSI color escape codes if enabled. | |
* | |
* @api public | |
*/ | |
function formatArgs(args) { | |
var name = this.namespace; | |
var useColors = this.useColors; | |
if (useColors) { | |
var c = this.color; | |
var prefix = ' \u001b[3' + c + ';1m' + name + ' ' + '\u001b[0m'; | |
args[0] = prefix + args[0].split('\n').join('\n' + prefix); | |
args.push('\u001b[3' + c + 'm+' + exports.humanize(this.diff) + '\u001b[0m'); | |
} else { | |
args[0] = new Date().toUTCString() | |
+ ' ' + name + ' ' + args[0]; | |
} | |
} | |
/** | |
* Invokes `util.format()` with the specified arguments and writes to `stream`. | |
*/ | |
function log() { | |
return stream.write(util__default['default'].format.apply(util__default['default'], arguments) + '\n'); | |
} | |
/** | |
* Save `namespaces`. | |
* | |
* @param {String} namespaces | |
* @api private | |
*/ | |
function save(namespaces) { | |
if (null == namespaces) { | |
// If you set a process.env field to null or undefined, it gets cast to the | |
// string 'null' or 'undefined'. Just delete instead. | |
delete process.env.DEBUG; | |
} else { | |
process.env.DEBUG = namespaces; | |
} | |
} | |
/** | |
* Load `namespaces`. | |
* | |
* @return {String} returns the previously persisted debug modes | |
* @api private | |
*/ | |
function load() { | |
return process.env.DEBUG; | |
} | |
/** | |
* Copied from `node/src/node.js`. | |
* | |
* XXX: It's lame that node doesn't expose this API out-of-the-box. It also | |
* relies on the undocumented `tty_wrap.guessHandleType()` which is also lame. | |
*/ | |
function createWritableStdioStream (fd) { | |
var stream; | |
var tty_wrap = process.binding('tty_wrap'); | |
// Note stream._type is used for test-module-load-list.js | |
switch (tty_wrap.guessHandleType(fd)) { | |
case 'TTY': | |
stream = new tty__default['default'].WriteStream(fd); | |
stream._type = 'tty'; | |
// Hack to have stream not keep the event loop alive. | |
// See https://github.com/joyent/node/issues/1726 | |
if (stream._handle && stream._handle.unref) { | |
stream._handle.unref(); | |
} | |
break; | |
case 'FILE': | |
var fs = fs__default['default']; | |
stream = new fs.SyncWriteStream(fd, { autoClose: false }); | |
stream._type = 'fs'; | |
break; | |
case 'PIPE': | |
case 'TCP': | |
var net = net__default['default']; | |
stream = new net.Socket({ | |
fd: fd, | |
readable: false, | |
writable: true | |
}); | |
// FIXME Should probably have an option in net.Socket to create a | |
// stream from an existing fd which is writable only. But for now | |
// we'll just add this hack and set the `readable` member to false. | |
// Test: ./node test/fixtures/echo.js < /etc/passwd | |
stream.readable = false; | |
stream.read = null; | |
stream._type = 'pipe'; | |
// FIXME Hack to have stream not keep the event loop alive. | |
// See https://github.com/joyent/node/issues/1726 | |
if (stream._handle && stream._handle.unref) { | |
stream._handle.unref(); | |
} | |
break; | |
default: | |
// Probably an error on in uv_guess_handle() | |
throw new Error('Implement me. Unknown stream file type!'); | |
} | |
// For supporting legacy API we put the FD here. | |
stream.fd = fd; | |
stream._isStdio = true; | |
return stream; | |
} | |
/** | |
* Init logic for `debug` instances. | |
* | |
* Create a new `inspectOpts` object in case `useColors` is set | |
* differently for a particular `debug` instance. | |
*/ | |
function init (debug) { | |
debug.inspectOpts = {}; | |
var keys = Object.keys(exports.inspectOpts); | |
for (var i = 0; i < keys.length; i++) { | |
debug.inspectOpts[keys[i]] = exports.inspectOpts[keys[i]]; | |
} | |
} | |
/** | |
* Enable namespaces listed in `process.env.DEBUG` initially. | |
*/ | |
exports.enable(load()); | |
}); | |
var src = createCommonjsModule(function (module) { | |
/** | |
* Detect Electron renderer process, which is node, but we should | |
* treat as a browser. | |
*/ | |
if (typeof process !== 'undefined' && process.type === 'renderer') { | |
module.exports = browser; | |
} else { | |
module.exports = node; | |
} | |
}); | |
let debug$1 = src('net-reconnect'); | |
class NetReconnect { | |
constructor (socket, options) { | |
this._socket = socket; | |
this._options = options; | |
this._retryTime = options.retryTime || 1000; | |
this._retryAlways = options.retryAlways || false; | |
this._keepAliveDelay = Math.max(options.keepAliveDelay, 1000) || 1000; | |
this._keepAliveInterval = Math.max(options.keepAliveInterval, 1000) || 1000; | |
this._keepAliveProbes = Math.max(Math.min(options.keepAliveProbes, 1), 20) || 1; | |
this._closing = false; | |
this._socket.on('connect', this._onConnect.bind(this)); | |
this._socket.on('close', this._onClose.bind(this)); | |
this._socket.on('error', this._onError.bind(this)); | |
} | |
static apply (socket, options) { | |
return new NetReconnect(socket, options) | |
} | |
_reconnect () { | |
debug$1('reconnecting in %d', this._retryTime); | |
setTimeout(function () { | |
this._socket.connect(this._options); | |
}.bind(this), this._retryTime); | |
} | |
_onConnect () { | |
if (this._closing) { | |
return | |
} | |
this._socket.setKeepAlive(true, this._keepAliveDelay); | |
debug$1('online'); | |
} | |
_onClose (hadError) { | |
if (this._closing) { | |
return | |
} | |
debug$1('offline'); | |
this._state = 'offline'; | |
if (!hadError) { | |
debug$1('connection closed on purpose'); | |
if (this._retryAlways) { | |
debug$1('retryAlways flag active, reconnecting'); | |
this._reconnect(); | |
return | |
} else { | |
debug$1('not reconnecting'); | |
return | |
} | |
} | |
debug$1('connection closed with errors, reconnecting'); | |
this._reconnect(); | |
} | |
_onError () { | |
if (this._closing) { | |
return | |
} | |
debug$1('error'); | |
} | |
end () { | |
debug$1('closing socket permanently'); | |
this._closing = true; | |
this._socket.removeListener('connect', this._onConnect); | |
this._socket.removeListener('close', this._onClose); | |
this._socket.removeListener('error', this._onError); | |
return this._socket.end.apply(this._socket, arguments) | |
} | |
} | |
var src$1 = NetReconnect; | |
var tcp = createCommonjsModule(function (module, exports) { | |
// Generated by LiveScript 1.6.0 | |
var Reconnect, net, ref$, yellow, green, red, blue, bgGreen, bgRed, sleep, Logger, EventEmitter, TcpHandlerTransport, TcpTransport, logger, x$, transport, i, out$ = exports || commonjsGlobal, toString$ = {}.toString; | |
Reconnect = src$1; | |
net = net__default['default']; | |
ref$ = lib, yellow = ref$.yellow, green = ref$.green, red = ref$.red, blue = ref$.blue, bgGreen = ref$.bgGreen, bgRed = ref$.bgRed; | |
ref$ = lib$2, sleep = ref$.sleep, Logger = ref$.Logger, EventEmitter = ref$.EventEmitter; | |
out$.TcpHandlerTransport = TcpHandlerTransport = (function(superclass){ | |
var prototype = extend$((import$(TcpHandlerTransport, superclass).displayName = 'TcpHandlerTransport', TcpHandlerTransport), superclass).prototype; | |
function TcpHandlerTransport(orig){ | |
var x$, this$ = this; | |
this.orig = orig; | |
TcpHandlerTransport.superclass.call(this); | |
x$ = this.orig; | |
x$.on('end', function(){ | |
return this$.trigger('disconnect'); | |
}); | |
x$.on('error', function(){ | |
return this$.trigger('disconnect'); | |
}); | |
x$.on('data', function(data){ | |
return this$.trigger('data', data); | |
}); | |
} | |
TcpHandlerTransport.prototype.write = function(data){ | |
return this.orig.write(data); | |
}; | |
return TcpHandlerTransport; | |
}(EventEmitter)); | |
out$.TcpTransport = TcpTransport = (function(superclass){ | |
var prototype = extend$((import$(TcpTransport, superclass).displayName = 'TcpTransport', TcpTransport), superclass).prototype; | |
function TcpTransport(opts){ | |
var x$, this$ = this; | |
opts == null && (opts = {}); | |
TcpTransport.superclass.call(this); | |
this.opts = { | |
host: opts.host || "localhost", | |
port: opts.port || 5523, | |
retryAlways: true | |
}; | |
this.log = new Logger('TCP_Transport'); | |
this.socket = new net.Socket(); | |
Reconnect.apply(this.socket, this.opts); | |
this.connected = false; | |
x$ = this.socket; | |
x$.setKeepAlive(true, 1000); | |
x$.setTimeout(1000); | |
x$.on('connect', function(){ | |
return this$.connected = true; | |
}); | |
x$.on('close', function(){ | |
return this$.connected = false; | |
}); | |
x$.on('data', function(data){ | |
return this$.trigger('data', data); | |
}); | |
x$.on('end', function(){ | |
return this$.connected = false; | |
}); | |
x$.on('error', function(err){ | |
return this$.connected = false; | |
}); | |
if (!opts.manualStart) { | |
this.start(); | |
} | |
} | |
Object.defineProperty(TcpTransport.prototype, 'connected', { | |
get: function(){ | |
return this._connected; | |
}, | |
set: function(val){ | |
var prev; | |
prev = this._connected; | |
this._connected = val; | |
if (!val && prev) { | |
this.trigger('disconnect'); | |
} | |
if (val && !prev) { | |
this.trigger('connect'); | |
} | |
}, | |
configurable: true, | |
enumerable: true | |
}); | |
TcpTransport.prototype.start = function(){ | |
return this.socket.connect(this.opts); | |
}; | |
TcpTransport.prototype.write = function(data, callback){ | |
var e; | |
if (toString$.call(callback).slice(8, -1) !== 'Function') { | |
callback = function(){}; | |
} | |
if (this.connected) { | |
try { | |
return this.socket.write(data, function(){ | |
var err; | |
return callback(err = null); | |
}); | |
} catch (e$) { | |
e = e$; | |
console.log("there is error again: ", e); | |
throw null; | |
} | |
} else { | |
return callback({ | |
message: 'not connected' | |
/* disabling, because this will likely cause memory leak | |
* for long disconnections | |
resolved: (callback) ~> | |
@once \connect, callback | |
*/ | |
}); | |
} | |
}; | |
return TcpTransport; | |
}(EventEmitter)); | |
if (commonjsRequire.main === module) { | |
logger = new Logger('APP'); | |
x$ = transport = new TcpTransport({ | |
host: 'localhost', | |
port: 1234 | |
}); | |
x$.on('connect', function(){ | |
return logger.log("transport connected"); | |
}); | |
x$.on('data', function(frame){ | |
return logger.log("frame received:", frame.toString()); | |
}); | |
x$.on('disconnect', function(){ | |
return logger.log("transport disconnected "); | |
}); | |
i = 0; | |
(function lo(op){ | |
var payload; | |
payload = "sending incremental data: " + i; | |
logger.log(payload); | |
return transport.write(payload + "\n", function(err){ | |
if (err) { | |
logger.err("something went wrong while writing"); | |
return sleep(1000, function(){ | |
return lo(op); | |
}); | |
} else { | |
if (++i > 10) { | |
return op(); | |
} | |
return sleep(2000, function(){ | |
return lo(op); | |
}); | |
} | |
}); | |
})(function(){ | |
return logger.log("End of tests."); | |
}); | |
} | |
function extend$(sub, sup){ | |
function fun(){} fun.prototype = (sub.superclass = sup).prototype; | |
(sub.prototype = new fun).constructor = sub; | |
if (typeof sup.extended == 'function') sup.extended(sub); | |
return sub; | |
} | |
function import$(obj, src){ | |
var own = {}.hasOwnProperty; | |
for (var key in src) if (own.call(src, key)) obj[key] = src[key]; | |
return obj; | |
} | |
}); | |
var client$1 = createCommonjsModule(function (module, exports) { | |
// Generated by LiveScript 1.6.0 | |
var ProxyClient, TcpTransport, sleep, DcsTcpClient, out$ = exports || commonjsGlobal; | |
ProxyClient = client.ProxyClient; | |
TcpTransport = tcp.TcpTransport; | |
sleep = deps$1.sleep; | |
out$.DcsTcpClient = DcsTcpClient = (function(superclass){ | |
var prototype = extend$((import$(DcsTcpClient, superclass).displayName = 'DcsTcpClient', DcsTcpClient), superclass).prototype; | |
function DcsTcpClient(opts){ | |
var transport, this$ = this; | |
this.opts = opts != null | |
? opts | |
: {}; | |
this.opts.port || (function(){ | |
throw "DcsTcpClient: Port is required."; | |
}()); | |
transport = new TcpTransport({ | |
host: this.opts.host || '127.0.0.1', | |
port: this.opts.port | |
}); | |
DcsTcpClient.superclass.call(this, transport, { | |
name: 'TcpDcsClient', | |
forgetPassword: false | |
}); | |
this.on('connect', function(){ | |
return this$.log.info("Connected to server..."); | |
}); | |
this.onTopic('app.dcs.connect', function(msg){ | |
return this$.log.info("Tcp Client is logged in into the DCS network."); | |
}); | |
this.on('disconnect', function(){ | |
this$.log.info("Disconnected."); | |
this$.log.info("ProxyClient will try to reconnect."); | |
return sleep(3000, function(){ | |
return this$.trigger('_login'); | |
}); | |
}); | |
} | |
return DcsTcpClient; | |
}(ProxyClient)); | |
function extend$(sub, sup){ | |
function fun(){} fun.prototype = (sub.superclass = sup).prototype; | |
(sub.prototype = new fun).constructor = sub; | |
if (typeof sup.extended == 'function') sup.extended(sub); | |
return sub; | |
} | |
function import$(obj, src){ | |
var own = {}.hasOwnProperty; | |
for (var key in src) if (own.call(src, key)) obj[key] = src[key]; | |
return obj; | |
} | |
}); | |
var ioProxyClient = createCommonjsModule(function (module, exports) { | |
// Generated by LiveScript 1.6.0 | |
var Actor, sleep, FpsExec, topicMatch, _x, uuid4, IoProxyClient, out$ = exports || commonjsGlobal, toString$ = {}.toString; | |
Actor = actor.Actor; | |
sleep = sleep_1.sleep; | |
FpsExec = filters.FpsExec; | |
topicMatch = topicMatch_1.topicMatch; | |
_x = 0; | |
uuid4 = function(){ | |
return "some-random-" + (_x++); | |
}; | |
out$.IoProxyClient = IoProxyClient = (function(superclass){ | |
var prototype = extend$((import$(IoProxyClient, superclass).displayName = 'IoProxyClient', IoProxyClient), superclass).prototype; | |
function IoProxyClient(opts){ | |
var update, this$ = this; | |
opts == null && (opts = {}); | |
this.route = opts.route || (function(){ | |
throw "route is required."; | |
}()); | |
this.timeout = opts.timeout || 1000; | |
IoProxyClient.superclass.call(this, this.route); | |
this.fps = new FpsExec(opts.fps || 20, this); | |
this.value = undefined; | |
this.lastUpdate = 0; | |
this.debug = opts.debug; | |
this.onTopic(this.route + "", function(msg){ | |
var that, value; | |
if (that = msg.data.err) { | |
return this$.trigger('error', { | |
message: that | |
}); | |
} else { | |
value = msg.data.val; | |
if (JSON.stringify(value) !== JSON.stringify(this$.value)) { | |
this$.trigger('change', value); | |
if (toString$.call(value).slice(8, -1) === 'Boolean') { | |
if (this$.value === false && value === true) { | |
this$.trigger('r-edge'); | |
} | |
if (this$.value === true && value === false) { | |
this$.trigger('f-edge'); | |
} | |
} | |
} | |
this$.lastUpdate = Date.now(); | |
this$.value = value; | |
return this$.trigger('read', value, msg); | |
} | |
}); | |
update = function(callback){ | |
if (!callback) { | |
callback = function(){}; | |
} | |
return this$.sendRequest({ | |
route: this$.route + "", | |
timeout: this$.timeout | |
}, { | |
update: true | |
}, function(err, msg){ | |
if (err || msg.err) { | |
this$.trigger('error', { | |
message: err | |
}); | |
return callback(err); | |
} else { | |
this$.triggerTopic(this$.route + "", msg); | |
return callback(null); | |
} | |
}); | |
}; | |
this.onEveryLogin(function(msg){ | |
var retryLimit; | |
retryLimit = 3; | |
return function lo(op){ | |
return update(function(err){ | |
if (err) { | |
retryLimit--; | |
if (retryLimit === 0) { | |
return op(); | |
} | |
this$.log.warn("Update error, retrying... (left: " + retryLimit + ")"); | |
return sleep(1000, function(){ | |
return lo(op); | |
}); | |
} else { | |
return op(); | |
} | |
}); | |
}(function(){}); | |
}); | |
} | |
IoProxyClient.prototype.rEdge = function(callback){ | |
this.once('r-edge', callback); | |
}; | |
IoProxyClient.prototype.fEdge = function(callback){ | |
this.once('f-edge', callback); | |
}; | |
IoProxyClient.prototype.when = function(filterFunc, callback){ | |
var name, this$ = this; | |
name = uuid4(); | |
this.on('change', name, function(value){ | |
if (filterFunc(value)) { | |
return setImmediate(function(){ | |
callback(value); | |
return this$.cancel(name); | |
}); | |
} | |
}); | |
}; | |
IoProxyClient.prototype.write = function(value, callback){ | |
var this$ = this; | |
this.fps.exec(function(){ | |
this$.fps.pause(); | |
return this$.filteredWrite(value, function(){ | |
var args, res$, i$, to$, that; | |
res$ = []; | |
for (i$ = 0, to$ = arguments.length; i$ < to$; ++i$) { | |
res$.push(arguments[i$]); | |
} | |
args = res$; | |
this$.fps.resume(); | |
if ((that = callback) != null) { | |
return that.apply(null, args); | |
} | |
}); | |
}); | |
}; | |
IoProxyClient.prototype.read = function(callback){ | |
this.sendRequest({ | |
route: this.route, | |
timeout: this.timeout, | |
debug: this.debug | |
}, { | |
read: true | |
}, function(err, msg){ | |
return callback(err, msg); | |
}); | |
}; | |
IoProxyClient.prototype.filteredWrite = function(value, callback){ | |
var this$ = this; | |
this.sendRequest({ | |
route: this.route, | |
timeout: this.timeout, | |
debug: this.debug | |
}, { | |
val: value | |
}, function(err, msg){ | |
var error; | |
error = err || (msg != null ? msg.data.err : void 8); | |
if (!err) { | |
this$.value = msg.data.res; | |
} | |
if (toString$.call(callback).slice(8, -1) === 'Function') { | |
return callback(error); | |
} | |
}); | |
}; | |
return IoProxyClient; | |
}(Actor)); | |
function extend$(sub, sup){ | |
function fun(){} fun.prototype = (sub.superclass = sup).prototype; | |
(sub.prototype = new fun).constructor = sub; | |
if (typeof sup.extended == 'function') sup.extended(sub); | |
return sub; | |
} | |
function import$(obj, src){ | |
var own = {}.hasOwnProperty; | |
for (var key in src) if (own.call(src, key)) obj[key] = src[key]; | |
return obj; | |
} | |
}); | |
var keypath = createCommonjsModule(function (module, exports) { | |
// Generated by LiveScript 1.6.0 | |
var getKeypath, setKeypath, deleteKeypath, out$ = exports || commonjsGlobal; | |
out$.getKeypath = getKeypath = function(obj, keypath){ | |
var res, i$, ref$, len$, k; | |
res = obj; | |
if (keypath) { | |
for (i$ = 0, len$ = (ref$ = keypath.split('.')).length; i$ < len$; ++i$) { | |
k = ref$[i$]; | |
res = (fn$()); | |
} | |
} | |
return res; | |
function fn$(){ | |
try { | |
return res[k]; | |
} catch (e$) { | |
return null; | |
} | |
} | |
}; | |
out$.setKeypath = setKeypath = function(obj, keypath, value){ | |
var _set, path; | |
_set = function(_obj, _keypath){ | |
var k; | |
if (_keypath.length === 0) { | |
return _obj; | |
} | |
k = _keypath.shift(); | |
if (_keypath.length === 0) { | |
return _obj[k] = value; | |
} else { | |
if (!_obj[k]) { | |
_obj[k] = {}; | |
} | |
_set(_obj[k], _keypath); | |
} | |
return _obj; | |
}; | |
path = (keypath != null ? keypath.split('.') : void 8) || []; | |
return _set(obj, path); | |
}; | |
out$.deleteKeypath = deleteKeypath = function(obj, keypath){ | |
var _keypath, firstProp, lastProp, tmp, i$, x$, len$, ref$, key, results$ = []; | |
if (keypath) { | |
_keypath = keypath.split('.'); | |
firstProp = _keypath.shift(); | |
lastProp = _keypath.pop(); | |
tmp = obj[firstProp]; | |
for (i$ = 0, len$ = _keypath.length; i$ < len$; ++i$) { | |
x$ = _keypath[i$]; | |
tmp = tmp[x$]; | |
} | |
if (lastProp in tmp) { | |
return ref$ = tmp[lastProp], delete tmp[lastProp], ref$; | |
} else { | |
throw "no such key"; | |
} | |
} else { | |
for (key in obj) { | |
results$.push((ref$ = obj[key], delete obj[key], ref$)); | |
} | |
return results$; | |
} | |
}; | |
}); | |
var memoryMap = createCommonjsModule(function (module, exports) { | |
// Generated by LiveScript 1.6.0 | |
var ref$, split, keys, map, getKeypath, CodingError, bitTest, bitWrite, dec2bin, splitBits, dataTypes, IoHandle, parseIoAddr, makeIoAddr, BlockRead, out$ = exports || commonjsGlobal, toString$ = {}.toString; | |
ref$ = lib$1, split = ref$.split, keys = ref$.keys, map = ref$.map; | |
getKeypath = keypath.getKeypath; | |
CodingError = errors.CodingError; | |
function hex2float (a) {return (a & 0x7fffff | 0x800000) * 1.0 / Math.pow(2,23) * Math.pow(2, ((a>>23 & 0xff) - 127))} | |
function bit_test(num, bit){ | |
return ((num>>bit) % 2 != 0) | |
} | |
function bit_set(num, bit){ | |
return num | 1<<bit; | |
} | |
function bit_clear(num, bit){ | |
return num & ~(1<<bit); | |
} | |
out$.bitTest = bitTest = bit_test; | |
out$.bitWrite = bitWrite = function(source, bitNum, value){ | |
if (value) { | |
return bit_set(source, bitNum); | |
} else { | |
return bit_clear(source, bitNum); | |
} | |
}; | |
out$.dec2bin = dec2bin = function(dec){ | |
'dec2bin(1); // 1\ndec2bin(-1); // 11111111111111111111111111111111\ndec2bin(256); // 100000000\ndec2bin(-256); // 11111111111111111111111100000000'; | |
return dec >>> 0 .toString(2); | |
}; | |
// taken from https://stackoverflow.com/a/1268377/1952991 | |
function zeroPad(num, numZeros) { | |
var n = Math.abs(num); | |
var zeros = Math.max(0, numZeros - Math.floor(n).toString().length ); | |
var zeroString = Math.pow(10,zeros).toString().substr(1); | |
if( num < 0 ) { | |
zeroString = '-' + zeroString; | |
} | |
return zeroString+n; | |
} | |
out$.zeroPad = zeroPad; | |
out$.splitBits = splitBits = function(input){ | |
var bin, zpad8; | |
bin = (+input).toString(2); | |
zpad8 = function(it){ | |
return ("00000000" + it).slice(-8); | |
}; | |
return function(it){ | |
return it.split("").reverse().map(function(it){ | |
return parseInt( | |
it.trim()); | |
}); | |
}( | |
zpad8( | |
bin)); | |
}; | |
dataTypes = { | |
int: function(x){ | |
return parseInt(x); | |
}, | |
hex: function(x){ | |
return x.toString(16).toUpperCase(); | |
}, | |
hexf: hex2float, | |
mili: (function(it){ | |
return it / 1000; | |
}), | |
bool: Boolean | |
}; | |
out$.IoHandle = IoHandle = (function(){ | |
'This class adds some useful methods to an IO object, such as: \n\n .get-meaningful(raw-value): Returns meaningful value\n regarding to the @type. '; | |
IoHandle.displayName = 'IoHandle'; | |
function IoHandle(opts, route){ | |
var k, v; | |
opts == null && (opts = {}); | |
for (k in opts) { | |
v = opts[k]; | |
this[k] = v; | |
} | |
this.route = route; | |
this.id = this.route; | |
} | |
IoHandle.prototype.getMeaningful = function(value){ | |
if (toString$.call(this.converter).slice(8, -1)) { | |
return this.converter(value); | |
} else { | |
if (!this.type) { | |
throw Error('unimplemented'); | |
} | |
return dataTypes[this.type](value); | |
} | |
}; | |
IoHandle.prototype.registerConverter = function(converter){ | |
return this.converter = converter; | |
}; | |
return IoHandle; | |
}()); | |
out$.parseIoAddr = parseIoAddr = function(fullName){ | |
var ref$, prefix, byte, bitSep, bit, parsed; | |
ref$ = fullName.split(/(\d+)/), prefix = ref$[0], byte = ref$[1], bitSep = ref$[2], bit = ref$[3]; | |
parsed = { | |
prefix: prefix, | |
byte: parseInt(byte), | |
bit: bitSep ? parseInt(bit) : null, | |
bool: bitSep ? true : false | |
}; | |
return parsed; | |
}; | |
out$.makeIoAddr = makeIoAddr = function(prefix, byte, bit){ | |
return prefix + "" + byte + (bit ? "." + bit : void 8); | |
}; | |
out$.BlockRead = BlockRead = (function(){ | |
BlockRead.displayName = 'BlockRead'; | |
function BlockRead(opts){ | |
this.prefix = opts.prefix; | |
this.from = opts.from; | |
this.count = opts.count; | |
this.bits0 = []; | |
this.bits = []; | |
this.handlers = {}; | |
} | |
Object.defineProperty(BlockRead.prototype, 'readParams', { | |
get: function(){ | |
return [this.prefix, this.from, this.count]; | |
}, | |
configurable: true, | |
enumerable: true | |
}); | |
BlockRead.prototype.addHandler = function(name, handler){ | |
if (name in this.handlers) { | |
return console.error(name + " is already registered, not registering again."); | |
} else { | |
return this.handlers[name] = handler; | |
} | |
}; | |
BlockRead.prototype.distribute = function(arr){ | |
var i$, x$, len$, i, j, ref$, addr, ref1$, err; | |
this.bits.length = 0; | |
for (i$ = 0, len$ = arr.length; i$ < len$; ++i$) { | |
x$ = arr[i$]; | |
this.bits.push(splitBits(x$)); | |
} | |
for (i in this.bits) { | |
for (j in this.bits[i]) { | |
if (this.bits[i][j] !== ((ref$ = this.bits0[i]) != null ? ref$[j] : void 8)) { | |
addr = makeIoAddr(this.prefix, i, j); | |
if (typeof (ref1$ = this.handlers)[addr] == 'function') { | |
ref1$[addr](err = null, this.bits[i][j]); | |
} | |
} | |
} | |
} | |
this.bits0 = JSON.parse(JSON.stringify(this.bits)); | |
}; | |
return BlockRead; | |
}()); | |
}); | |
var ioProxyHandler = createCommonjsModule(function (module, exports) { | |
// Generated by LiveScript 1.6.0 | |
var Actor, EventEmitter, sleep, Logger, CodingError, IoHandle, IoProxyHandler, out$ = exports || commonjsGlobal; | |
Actor = actor.Actor; | |
EventEmitter = eventEmitter.EventEmitter; | |
sleep = sleep_1.sleep; | |
Logger = logger.Logger; | |
CodingError = errors.CodingError; | |
IoHandle = memoryMap.IoHandle; | |
out$.IoProxyHandler = IoProxyHandler = (function(superclass){ | |
var prototype = extend$((import$(IoProxyHandler, superclass).displayName = 'IoProxyHandler', IoProxyHandler), superclass).prototype; | |
function IoProxyHandler(handle, _route, driver){ | |
var ref$, route, prev, age, broadcastValue, responseValue, this$ = this; | |
if (!driver) { | |
driver = _route; | |
_route = null; | |
if ((handle != null ? (ref$ = handle.constructor) != null ? ref$.name : void 8 : void 8) !== 'IoHandle') { | |
throw new CodingError("handle should be an instance of IoHandle class"); | |
} | |
} else { | |
handle = new IoHandle(handle, _route); | |
} | |
if (!driver) { | |
throw new CodingError("Driver must be provided"); | |
} | |
if (!(route = handle.route)) { | |
throw new CodingError("A route MUST be provided to IoProxyHandler."); | |
} | |
IoProxyHandler.superclass.call(this, route); | |
prev = null; | |
age = 0; | |
broadcastValue = function(err, value){ | |
this$.send(this$.name + "", { | |
err: err, | |
val: value | |
}); | |
if (!err && value !== prev) { | |
prev = value; | |
return age = Date.now(); | |
} | |
}; | |
responseValue = function(msg){ | |
return function(err, value){ | |
this$.sendResponse(msg, { | |
err: err, | |
val: value | |
}); | |
if (!err && value !== prev) { | |
prev = value; | |
return age = Date.now(); | |
} | |
}; | |
}; | |
this.on('read', function(handle, respond){ | |
return driver.read(handle, function(err, value){ | |
return respond(err, value); | |
}); | |
}); | |
this.on('write', function(handle, value, respond){ | |
return driver.write(handle, value, function(err){ | |
return respond(err); | |
}); | |
}); | |
driver.initHandle(handle, broadcastValue); | |
this.onTopic(route, function(msg){ | |
var newValue, maxAge, err, value; | |
if ('val' in msg.data) { | |
newValue = msg.data.val; | |
return this$.trigger('write', handle, newValue, function(err){ | |
var meta, data; | |
meta = { | |
cc: this$.name + "" | |
}; | |
data = { | |
err: err | |
}; | |
if (!err) { | |
data.val = newValue; | |
prev = newValue; | |
} | |
return this$.sendResponse(msg, meta, data); | |
}); | |
} else if ('update' in msg.data) { | |
maxAge = 10 * 60000; | |
if (maxAge + age < Date.now()) { | |
return this$.trigger('read', handle, responseValue(msg)); | |
} else { | |
return responseValue(msg)(err = null, value = prev); | |
} | |
} else { | |
return this$.trigger('read', handle, responseValue(msg)); | |
} | |
}); | |
this.onEveryLogin(function(msg){ | |
return this$.trigger('_try_broadcast_state'); | |
}); | |
driver.on('connect', function(){ | |
return this$.trigger('_try_broadcast_state'); | |
}); | |
driver.on('disconnect', function(){ | |
var err; | |
return broadcastValue(err = "Target is disconnected."); | |
}); | |
driver.on('data', function(table){ | |
var value, err; | |
if (handle.id in table) { | |
value = table[handle.id]; | |
if (value !== prev) { | |
return broadcastValue(err = null, value); | |
} | |
} | |
}); | |
this.on('_try_broadcast_state', function(){ | |
if (driver.connected) { | |
return this$.trigger('read', handle, broadcastValue); | |
} else { | |
return this$.log.info("Driver is not connected, skipping broadcasting."); | |
} | |
}); | |
if (!driver.starting || !driver.started) { | |
driver.start(); | |
} | |
} | |
return IoProxyHandler; | |
}(Actor)); | |
function extend$(sub, sup){ | |
function fun(){} fun.prototype = (sub.superclass = sup).prototype; | |
(sub.prototype = new fun).constructor = sub; | |
if (typeof sup.extended == 'function') sup.extended(sub); | |
return sub; | |
} | |
function import$(obj, src){ | |
var own = {}.hasOwnProperty; | |
for (var key in src) if (own.call(src, key)) obj[key] = src[key]; | |
return obj; | |
} | |
}); | |
var driverAbstract = createCommonjsModule(function (module, exports) { | |
// Generated by LiveScript 1.6.0 | |
var EventEmitter, Logger, DriverAbstract, out$ = exports || commonjsGlobal; | |
EventEmitter = eventEmitter.EventEmitter; | |
Logger = logger.Logger; | |
out$.DriverAbstract = DriverAbstract = (function(superclass){ | |
var prototype = extend$((import$(DriverAbstract, superclass).displayName = 'DriverAbstract', DriverAbstract), superclass).prototype; | |
function DriverAbstract(){ | |
var implementedBy; | |
DriverAbstract.superclass.call(this); | |
this._queue = []; | |
this.io = {}; | |
this.logger = new Logger(implementedBy = this.constructor.name); | |
} | |
DriverAbstract.prototype.initHandle = function(handle, broadcast){ | |
throw Error('unimplemented'); | |
}; | |
DriverAbstract.prototype.write = function(handle, value, respond){ | |
throw Error('unimplemented'); | |
}; | |
DriverAbstract.prototype._exec_sequential = function(func){ | |
var i$, res$, j$; | |
res$ = []; | |
for (j$ = 1 < (i$ = arguments.length - 1) ? 1 : (i$ = 1); j$ < i$; ++j$) { | |
res$.push(arguments[j$]); | |
} | |
this._queue.push(arguments); | |
throw Error('unimplemented'); | |
}; | |
DriverAbstract.prototype.read = function(handle, respond){ | |
throw Error('unimplemented'); | |
}; | |
DriverAbstract.prototype.start = function(){ | |
this.starting = true; | |
this.logger.log("Driver immediately started."); | |
return this.connected = true; | |
}; | |
Object.defineProperty(DriverAbstract.prototype, 'connected', { | |
get: function(){ | |
return this._connected; | |
}, | |
set: function(val){ | |
if (val === true) { | |
this._connected = true; | |
this.started = true; | |
this.trigger('connect'); | |
} else { | |
this._connected = false; | |
this.started = false; | |
this.starting = false; | |
this.trigger('disconnect'); | |
} | |
}, | |
configurable: true, | |
enumerable: true | |
}); | |
return DriverAbstract; | |
}(EventEmitter)); | |
function extend$(sub, sup){ | |
function fun(){} fun.prototype = (sub.superclass = sup).prototype; | |
(sub.prototype = new fun).constructor = sub; | |
if (typeof sup.extended == 'function') sup.extended(sub); | |
return sub; | |
} | |
function import$(obj, src){ | |
var own = {}.hasOwnProperty; | |
for (var key in src) if (own.call(src, key)) obj[key] = src[key]; | |
return obj; | |
} | |
}); | |
// Generated by LiveScript 1.6.0 | |
var Actor$1, FpsExec, ref$$3, Signal$3, SignalBranch$1, DcsTcpClient, EventEmitter$1, Logger$3, sleep$3, merge$1, pack$2, unpack$2, clone$3, diff$2, topicMatch$1, IoProxyClient, IoProxyHandler, DriverAbstract; | |
Actor$1 = actor.Actor; | |
FpsExec = filters.FpsExec; | |
ref$$3 = signal$1, Signal$3 = ref$$3.Signal, SignalBranch$1 = ref$$3.SignalBranch; | |
/* if dependencies of the followings are optionally installed, | |
then they shouldn't be included by default. | |
require! './services/couch-dcs/client': {CouchDcsClient} | |
require! './services/couch-dcs/server': {CouchDcsServer} | |
*/ | |
DcsTcpClient = client$1.DcsTcpClient; | |
ref$$3 = lib$2, EventEmitter$1 = ref$$3.EventEmitter, Logger$3 = ref$$3.Logger, sleep$3 = ref$$3.sleep, merge$1 = ref$$3.merge, pack$2 = ref$$3.pack, unpack$2 = ref$$3.unpack, clone$3 = ref$$3.clone, diff$2 = ref$$3.diff; | |
topicMatch$1 = topicMatch_1.topicMatch; | |
IoProxyClient = ioProxyClient.IoProxyClient; | |
IoProxyHandler = ioProxyHandler.IoProxyHandler; | |
DriverAbstract = driverAbstract.DriverAbstract; | |
var dcs = { | |
Actor: Actor$1, | |
FpsExec: FpsExec, | |
Signal: Signal$3, | |
SignalBranch: SignalBranch$1, | |
DcsTcpClient: DcsTcpClient, | |
EventEmitter: EventEmitter$1, | |
Logger: Logger$3, | |
sleep: sleep$3, | |
merge: merge$1, | |
pack: pack$2, | |
unpack: unpack$2, | |
clone: clone$3, | |
diff: diff$2, | |
IoProxyClient: IoProxyClient, | |
IoProxyHandler: IoProxyHandler, | |
DriverAbstract: DriverAbstract, | |
topicMatch: topicMatch$1 | |
}; | |
var config = createCommonjsModule(function (module, exports) { | |
// Generated by LiveScript 1.6.0 | |
var webserverPort, dcsPort, defaultPassword, out$ = exports || commonjsGlobal; | |
out$.webserverPort = webserverPort = 4013; | |
out$.dcsPort = dcsPort = 4014; | |
out$.defaultPassword = defaultPassword = "nCEqCyoyreg05ts4WmsVrPmPpw0dwt93"; | |
}); | |
var ractiveTemplate = createCommonjsModule(function (module, exports) { | |
// Generated by LiveScript 1.6.0 | |
var Ractive, compile, ractiveCompile, out$ = exports || commonjsGlobal; | |
Ractive = ractive__default['default']; | |
Ractive.DEBUG = false; | |
compile = function(template, data){ | |
var instance; | |
template == null && (template = ""); | |
data == null && (data = {}); | |
instance = new Ractive({ | |
template: Ractive.parse(template, { | |
textOnlyMode: true, | |
preserveWhitespace: true | |
}), | |
data: data | |
}); | |
return instance.toHTML(); | |
}; | |
/* | |
compile2 = (template="", data={}) -> | |
[prefix, postfix] = <[ <pre> </pre> ]> | |
instance = new Ractive do | |
template: prefix + template + postfix | |
data: data | |
return instance.toHTML!.slice(prefix.length, -postfix.length) | |
*/ | |
out$.ractiveCompile = ractiveCompile = compile; | |
}); | |
var readdirSyncRecursive_1 = createCommonjsModule(function (module, exports) { | |
// Generated by LiveScript 1.6.0 | |
var fs, path, out$ = exports || commonjsGlobal; | |
fs = fs__default['default']; | |
path = path__default['default']; | |
out$.readdirSyncRecursive = readdirSyncRecursive; | |
function readdirSyncRecursive(dir, files, arg$){ | |
var sub, f, i$, len$, file; | |
files == null && (files = []); | |
sub = (arg$ != null | |
? arg$ | |
: {}).sub; | |
f = fs.readdirSync(dir); | |
for (i$ = 0, len$ = f.length; i$ < len$; ++i$) { | |
file = f[i$]; | |
if (fs.statSync(dir + "/" + file).isDirectory()) { | |
files = readdirSyncRecursive(dir + "/" + file, files, { | |
sub: path.join(sub || '', file) | |
}); | |
} else { | |
files.push(path.join(sub || '', file)); | |
} | |
} | |
return files; | |
} | |
}); | |
var supportedMcus = [ | |
{ | |
chibiDef: "STM32F030x6", | |
mcuCode: "STM32F030C6Tx", | |
stmGlob: "STM32F030C6Tx" | |
}, | |
{ | |
chibiDef: "STM32F030x8", | |
mcuCode: "STM32F030C8Tx", | |
stmGlob: "STM32F030C8Tx" | |
}, | |
{ | |
chibiDef: "STM32F030xC", | |
mcuCode: "STM32F030CCTx", | |
stmGlob: "STM32F030CCTx" | |
}, | |
{ | |
chibiDef: "STM32F030x4", | |
mcuCode: "STM32F030F4Px", | |
stmGlob: "STM32F030F4Px" | |
}, | |
{ | |
chibiDef: "STM32F030x6", | |
mcuCode: "STM32F030K6Tx", | |
stmGlob: "STM32F030K6Tx" | |
}, | |
{ | |
chibiDef: "STM32F030x8", | |
mcuCode: "STM32F030R8Tx", | |
stmGlob: "STM32F030R8Tx" | |
}, | |
{ | |
chibiDef: "STM32F030xC", | |
mcuCode: "STM32F030RCTx", | |
stmGlob: "STM32F030RCTx" | |
}, | |
{ | |
chibiDef: "STM32F031x6", | |
mcuCode: "STM32F031C6Tx", | |
stmGlob: "STM32F031C(4-6)Tx" | |
}, | |
{ | |
chibiDef: "STM32F031x6", | |
mcuCode: "STM32F031E6Yx", | |
stmGlob: "STM32F031E6Yx" | |
}, | |
{ | |
chibiDef: "STM32F031x6", | |
mcuCode: "STM32F031F6Px", | |
stmGlob: "STM32F031F(4-6)Px" | |
}, | |
{ | |
chibiDef: "STM32F031x6", | |
mcuCode: "STM32F031G6Ux", | |
stmGlob: "STM32F031G(4-6)Ux" | |
}, | |
{ | |
chibiDef: "STM32F031x6", | |
mcuCode: "STM32F031K6Ux", | |
stmGlob: "STM32F031K(4-6)Ux" | |
}, | |
{ | |
chibiDef: "STM32F031x6", | |
mcuCode: "STM32F031K6Tx", | |
stmGlob: "STM32F031K6Tx" | |
}, | |
{ | |
chibiDef: "STM32F038xx", | |
mcuCode: "STM32F038C6Tx", | |
stmGlob: "STM32F038C6Tx" | |
}, | |
{ | |
chibiDef: "STM32F038xx", | |
mcuCode: "STM32F038E6Yx", | |
stmGlob: "STM32F038E6Yx" | |
}, | |
{ | |
chibiDef: "STM32F038xx", | |
mcuCode: "STM32F038F6Px", | |
stmGlob: "STM32F038F6Px" | |
}, | |
{ | |
chibiDef: "STM32F038xx", | |
mcuCode: "STM32F038G6Ux", | |
stmGlob: "STM32F038G6Ux" | |
}, | |
{ | |
chibiDef: "STM32F038xx", | |
mcuCode: "STM32F038K6Ux", | |
stmGlob: "STM32F038K6Ux" | |
}, | |
{ | |
chibiDef: "STM32F042x6", | |
mcuCode: "STM32F042C6Tx", | |
stmGlob: "STM32F042C(4-6)Tx" | |
}, | |
{ | |
chibiDef: "STM32F042x6", | |
mcuCode: "STM32F042C6Ux", | |
stmGlob: "STM32F042C(4-6)Ux" | |
}, | |
{ | |
chibiDef: "STM32F042x6", | |
mcuCode: "STM32F042F6Px", | |
stmGlob: "STM32F042F6Px" | |
}, | |
{ | |
chibiDef: "STM32F042x6", | |
mcuCode: "STM32F042G6Ux", | |
stmGlob: "STM32F042G(4-6)Ux" | |
}, | |
{ | |
chibiDef: "STM32F042x6", | |
mcuCode: "STM32F042K6Tx", | |
stmGlob: "STM32F042K(4-6)Tx" | |
}, | |
{ | |
chibiDef: "STM32F042x6", | |
mcuCode: "STM32F042K6Ux", | |
stmGlob: "STM32F042K(4-6)Ux" | |
}, | |
{ | |
chibiDef: "STM32F042x6", | |
mcuCode: "STM32F042T6Yx", | |
stmGlob: "STM32F042T6Yx" | |
}, | |
{ | |
chibiDef: "STM32F048xx", | |
mcuCode: "STM32F048C6Ux", | |
stmGlob: "STM32F048C6Ux" | |
}, | |
{ | |
chibiDef: "STM32F048xx", | |
mcuCode: "STM32F048G6Ux", | |
stmGlob: "STM32F048G6Ux" | |
}, | |
{ | |
chibiDef: "STM32F048xx", | |
mcuCode: "STM32F048T6Yx", | |
stmGlob: "STM32F048T6Yx" | |
}, | |
{ | |
chibiDef: "STM32F051x8", | |
mcuCode: "STM32F051C8Tx", | |
stmGlob: "STM32F051C8Tx" | |
}, | |
{ | |
chibiDef: "STM32F051x8", | |
mcuCode: "STM32F051C8Ux", | |
stmGlob: "STM32F051C8Ux" | |
}, | |
{ | |
chibiDef: "STM32F051x8", | |
mcuCode: "STM32F051K8Tx", | |
stmGlob: "STM32F051K8Tx" | |
}, | |
{ | |
chibiDef: "STM32F051x8", | |
mcuCode: "STM32F051K8Ux", | |
stmGlob: "STM32F051K8Ux" | |
}, | |
{ | |
chibiDef: "STM32F051x8", | |
mcuCode: "STM32F051R8Hx", | |
stmGlob: "STM32F051R8Hx" | |
}, | |
{ | |
chibiDef: "STM32F051x8", | |
mcuCode: "STM32F051R8Tx", | |
stmGlob: "STM32F051R8Tx" | |
}, | |
{ | |
chibiDef: "STM32F051x8", | |
mcuCode: "STM32F051T8Yx", | |
stmGlob: "STM32F051T8Yx" | |
}, | |
{ | |
chibiDef: "STM32F058xx", | |
mcuCode: "STM32F058C8Ux", | |
stmGlob: "STM32F058C8Ux" | |
}, | |
{ | |
chibiDef: "STM32F058xx", | |
mcuCode: "STM32F058R8Hx", | |
stmGlob: "STM32F058R8Hx" | |
}, | |
{ | |
chibiDef: "STM32F058xx", | |
mcuCode: "STM32F058R8Tx", | |
stmGlob: "STM32F058R8Tx" | |
}, | |
{ | |
chibiDef: "STM32F058xx", | |
mcuCode: "STM32F058T8Yx", | |
stmGlob: "STM32F058T8Yx" | |
}, | |
{ | |
chibiDef: "STM32F070x6", | |
mcuCode: "STM32F070C6Tx", | |
stmGlob: "STM32F070C6Tx" | |
}, | |
{ | |
chibiDef: "STM32F070xB", | |
mcuCode: "STM32F070CBTx", | |
stmGlob: "STM32F070CBTx" | |
}, | |
{ | |
chibiDef: "STM32F070x6", | |
mcuCode: "STM32F070F6Px", | |
stmGlob: "STM32F070F6Px" | |
}, | |
{ | |
chibiDef: "STM32F070xB", | |
mcuCode: "STM32F070RBTx", | |
stmGlob: "STM32F070RBTx" | |
}, | |
{ | |
chibiDef: "STM32F071xB", | |
mcuCode: "STM32F071CBTx", | |
stmGlob: "STM32F071C(8-B)Tx" | |
}, | |
{ | |
chibiDef: "STM32F071xB", | |
mcuCode: "STM32F071CBUx", | |
stmGlob: "STM32F071C(8-B)Ux" | |
}, | |
{ | |
chibiDef: "STM32F071xB", | |
mcuCode: "STM32F071CBYx", | |
stmGlob: "STM32F071CBYx" | |
}, | |
{ | |
chibiDef: "STM32F071xB", | |
mcuCode: "STM32F071RBTx", | |
stmGlob: "STM32F071RBTx" | |
}, | |
{ | |
chibiDef: "STM32F071xB", | |
mcuCode: "STM32F071VBHx", | |
stmGlob: "STM32F071V(8-B)Hx" | |
}, | |
{ | |
chibiDef: "STM32F071xB", | |
mcuCode: "STM32F071VBTx", | |
stmGlob: "STM32F071V(8-B)Tx" | |
}, | |
{ | |
chibiDef: "STM32F072xB", | |
mcuCode: "STM32F072CBTx", | |
stmGlob: "STM32F072C(8-B)Tx" | |
}, | |
{ | |
chibiDef: "STM32F072xB", | |
mcuCode: "STM32F072CBUx", | |
stmGlob: "STM32F072C(8-B)Ux" | |
}, | |
{ | |
chibiDef: "STM32F072xB", | |
mcuCode: "STM32F072CBYx", | |
stmGlob: "STM32F072CBYx" | |
}, | |
{ | |
chibiDef: "STM32F072xB", | |
mcuCode: "STM32F072RBTx", | |
stmGlob: "STM32F072R(8-B)Tx" | |
}, | |
{ | |
chibiDef: "STM32F072xB", | |
mcuCode: "STM32F072RBHx", | |
stmGlob: "STM32F072RBHx" | |
}, | |
{ | |
chibiDef: "STM32F072xB", | |
mcuCode: "STM32F072RBIx", | |
stmGlob: "STM32F072RBIx" | |
}, | |
{ | |
chibiDef: "STM32F072xB", | |
mcuCode: "STM32F072VBHx", | |
stmGlob: "STM32F072V(8-B)Hx" | |
}, | |
{ | |
chibiDef: "STM32F072xB", | |
mcuCode: "STM32F072VBTx", | |
stmGlob: "STM32F072V(8-B)Tx" | |
}, | |
{ | |
chibiDef: "STM32F078xx", | |
mcuCode: "STM32F078CBTx", | |
stmGlob: "STM32F078CBTx" | |
}, | |
{ | |
chibiDef: "STM32F078xx", | |
mcuCode: "STM32F078CBUx", | |
stmGlob: "STM32F078CBUx" | |
}, | |
{ | |
chibiDef: "STM32F078xx", | |
mcuCode: "STM32F078CBYx", | |
stmGlob: "STM32F078CBYx" | |
}, | |
{ | |
chibiDef: "STM32F078xx", | |
mcuCode: "STM32F078RBHx", | |
stmGlob: "STM32F078RBHx" | |
}, | |
{ | |
chibiDef: "STM32F078xx", | |
mcuCode: "STM32F078RBTx", | |
stmGlob: "STM32F078RBTx" | |
}, | |
{ | |
chibiDef: "STM32F078xx", | |
mcuCode: "STM32F078VBHx", | |
stmGlob: "STM32F078VBHx" | |
}, | |
{ | |
chibiDef: "STM32F078xx", | |
mcuCode: "STM32F078VBTx", | |
stmGlob: "STM32F078VBTx" | |
}, | |
{ | |
chibiDef: "STM32F091xC", | |
mcuCode: "STM32F091CCTx", | |
stmGlob: "STM32F091C(B-C)Tx" | |
}, | |
{ | |
chibiDef: "STM32F091xC", | |
mcuCode: "STM32F091CCUx", | |
stmGlob: "STM32F091C(B-C)Ux" | |
}, | |
{ | |
chibiDef: "STM32F091xC", | |
mcuCode: "STM32F091RCTx", | |
stmGlob: "STM32F091R(B-C)Tx" | |
}, | |
{ | |
chibiDef: "STM32F091xC", | |
mcuCode: "STM32F091RCHx", | |
stmGlob: "STM32F091RCHx" | |
}, | |
{ | |
chibiDef: "STM32F091xC", | |
mcuCode: "STM32F091RCYx", | |
stmGlob: "STM32F091RCYx" | |
}, | |
{ | |
chibiDef: "STM32F091xC", | |
mcuCode: "STM32F091VCTx", | |
stmGlob: "STM32F091V(B-C)Tx" | |
}, | |
{ | |
chibiDef: "STM32F091xC", | |
mcuCode: "STM32F091VCHx", | |
stmGlob: "STM32F091VCHx" | |
}, | |
{ | |
chibiDef: "STM32F098xx", | |
mcuCode: "STM32F098CCTx", | |
stmGlob: "STM32F098CCTx" | |
}, | |
{ | |
chibiDef: "STM32F098xx", | |
mcuCode: "STM32F098CCUx", | |
stmGlob: "STM32F098CCUx" | |
}, | |
{ | |
chibiDef: "STM32F098xx", | |
mcuCode: "STM32F098RCHx", | |
stmGlob: "STM32F098RCHx" | |
}, | |
{ | |
chibiDef: "STM32F098xx", | |
mcuCode: "STM32F098RCTx", | |
stmGlob: "STM32F098RCTx" | |
}, | |
{ | |
chibiDef: "STM32F098xx", | |
mcuCode: "STM32F098RCYx", | |
stmGlob: "STM32F098RCYx" | |
}, | |
{ | |
chibiDef: "STM32F098xx", | |
mcuCode: "STM32F098VCHx", | |
stmGlob: "STM32F098VCHx" | |
}, | |
{ | |
chibiDef: "STM32F098xx", | |
mcuCode: "STM32F098VCTx", | |
stmGlob: "STM32F098VCTx" | |
}, | |
{ | |
chibiDef: "STM32F100xB", | |
mcuCode: "STM32F100CBTx", | |
stmGlob: "STM32F100C(8-B)Tx" | |
}, | |
{ | |
chibiDef: "STM32F100xB", | |
mcuCode: "STM32F100RBHx", | |
stmGlob: "STM32F100R(8-B)Hx" | |
}, | |
{ | |
chibiDef: "STM32F100xB", | |
mcuCode: "STM32F100RBTx", | |
stmGlob: "STM32F100R(8-B)Tx" | |
}, | |
{ | |
chibiDef: "STM32F100xE", | |
mcuCode: "STM32F100RETx", | |
stmGlob: "STM32F100R(C-D-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F100xB", | |
mcuCode: "STM32F100VBTx", | |
stmGlob: "STM32F100V(8-B)Tx" | |
}, | |
{ | |
chibiDef: "STM32F100xE", | |
mcuCode: "STM32F100VETx", | |
stmGlob: "STM32F100V(C-D-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F100xE", | |
mcuCode: "STM32F100ZETx", | |
stmGlob: "STM32F100Z(C-D-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F101x6", | |
mcuCode: "STM32F101C6Tx", | |
stmGlob: "STM32F101C(4-6)Tx" | |
}, | |
{ | |
chibiDef: "STM32F101xB", | |
mcuCode: "STM32F101CBTx", | |
stmGlob: "STM32F101C(8-B)Tx" | |
}, | |
{ | |
chibiDef: "STM32F101xB", | |
mcuCode: "STM32F101CBUx", | |
stmGlob: "STM32F101C(8-B)Ux" | |
}, | |
{ | |
chibiDef: "STM32F101x6", | |
mcuCode: "STM32F101R6Tx", | |
stmGlob: "STM32F101R(4-6)Tx" | |
}, | |
{ | |
chibiDef: "STM32F101xB", | |
mcuCode: "STM32F101RBTx", | |
stmGlob: "STM32F101R(8-B)Tx" | |
}, | |
{ | |
chibiDef: "STM32F101xB", | |
mcuCode: "STM32F101RBHx", | |
stmGlob: "STM32F101RBHx" | |
}, | |
{ | |
chibiDef: "STM32F101xE", | |
mcuCode: "STM32F101RETx", | |
stmGlob: "STM32F101R(C-D-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F101xG", | |
mcuCode: "STM32F101RGTx", | |
stmGlob: "STM32F101R(F-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F101x6", | |
mcuCode: "STM32F101T6Ux", | |
stmGlob: "STM32F101T(4-6)Ux" | |
}, | |
{ | |
chibiDef: "STM32F101xB", | |
mcuCode: "STM32F101TBUx", | |
stmGlob: "STM32F101T(8-B)Ux" | |
}, | |
{ | |
chibiDef: "STM32F101xB", | |
mcuCode: "STM32F101VBTx", | |
stmGlob: "STM32F101V(8-B)Tx" | |
}, | |
{ | |
chibiDef: "STM32F101xE", | |
mcuCode: "STM32F101VETx", | |
stmGlob: "STM32F101V(C-D-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F101xG", | |
mcuCode: "STM32F101VGTx", | |
stmGlob: "STM32F101V(F-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F101xE", | |
mcuCode: "STM32F101ZETx", | |
stmGlob: "STM32F101Z(C-D-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F101xG", | |
mcuCode: "STM32F101ZGTx", | |
stmGlob: "STM32F101Z(F-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F102x6", | |
mcuCode: "STM32F102C6Tx", | |
stmGlob: "STM32F102C(4-6)Tx" | |
}, | |
{ | |
chibiDef: "STM32F102xB", | |
mcuCode: "STM32F102CBTx", | |
stmGlob: "STM32F102C(8-B)Tx" | |
}, | |
{ | |
chibiDef: "STM32F102x6", | |
mcuCode: "STM32F102R6Tx", | |
stmGlob: "STM32F102R(4-6)Tx" | |
}, | |
{ | |
chibiDef: "STM32F102xB", | |
mcuCode: "STM32F102RBTx", | |
stmGlob: "STM32F102R(8-B)Tx" | |
}, | |
{ | |
chibiDef: "STM32F103x6", | |
mcuCode: "STM32F103C6Tx", | |
stmGlob: "STM32F103C(4-6)Tx" | |
}, | |
{ | |
chibiDef: "STM32F103x6", | |
mcuCode: "STM32F103C6Ux", | |
stmGlob: "STM32F103C6Ux" | |
}, | |
{ | |
chibiDef: "STM32F103xB", | |
mcuCode: "STM32F103CBTx", | |
stmGlob: "STM32F103C(8-B)Tx" | |
}, | |
{ | |
chibiDef: "STM32F103xB", | |
mcuCode: "STM32F103CBUx", | |
stmGlob: "STM32F103CBUx" | |
}, | |
{ | |
chibiDef: "STM32F103x6", | |
mcuCode: "STM32F103R6Hx", | |
stmGlob: "STM32F103R(4-6)Hx" | |
}, | |
{ | |
chibiDef: "STM32F103x6", | |
mcuCode: "STM32F103R6Tx", | |
stmGlob: "STM32F103R(4-6)Tx" | |
}, | |
{ | |
chibiDef: "STM32F103xB", | |
mcuCode: "STM32F103RBHx", | |
stmGlob: "STM32F103R(8-B)Hx" | |
}, | |
{ | |
chibiDef: "STM32F103xB", | |
mcuCode: "STM32F103RBTx", | |
stmGlob: "STM32F103R(8-B)Tx" | |
}, | |
{ | |
chibiDef: "STM32F103xE", | |
mcuCode: "STM32F103RETx", | |
stmGlob: "STM32F103R(C-D-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F103xE", | |
mcuCode: "STM32F103REYx", | |
stmGlob: "STM32F103R(C-D-E)Yx" | |
}, | |
{ | |
chibiDef: "STM32F103xG", | |
mcuCode: "STM32F103RGTx", | |
stmGlob: "STM32F103R(F-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F103x6", | |
mcuCode: "STM32F103T6Ux", | |
stmGlob: "STM32F103T(4-6)Ux" | |
}, | |
{ | |
chibiDef: "STM32F103xB", | |
mcuCode: "STM32F103TBUx", | |
stmGlob: "STM32F103T(8-B)Ux" | |
}, | |
{ | |
chibiDef: "STM32F103xB", | |
mcuCode: "STM32F103VBHx", | |
stmGlob: "STM32F103V(8-B)Hx" | |
}, | |
{ | |
chibiDef: "STM32F103xB", | |
mcuCode: "STM32F103VBTx", | |
stmGlob: "STM32F103V(8-B)Tx" | |
}, | |
{ | |
chibiDef: "STM32F103xB", | |
mcuCode: "STM32F103VBIx", | |
stmGlob: "STM32F103VBIx" | |
}, | |
{ | |
chibiDef: "STM32F103xE", | |
mcuCode: "STM32F103VEHx", | |
stmGlob: "STM32F103V(C-D-E)Hx" | |
}, | |
{ | |
chibiDef: "STM32F103xE", | |
mcuCode: "STM32F103VETx", | |
stmGlob: "STM32F103V(C-D-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F103xG", | |
mcuCode: "STM32F103VGTx", | |
stmGlob: "STM32F103V(F-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F103xE", | |
mcuCode: "STM32F103ZEHx", | |
stmGlob: "STM32F103Z(C-D-E)Hx" | |
}, | |
{ | |
chibiDef: "STM32F103xE", | |
mcuCode: "STM32F103ZETx", | |
stmGlob: "STM32F103Z(C-D-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F103xG", | |
mcuCode: "STM32F103ZGHx", | |
stmGlob: "STM32F103Z(F-G)Hx" | |
}, | |
{ | |
chibiDef: "STM32F103xG", | |
mcuCode: "STM32F103ZGTx", | |
stmGlob: "STM32F103Z(F-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F105xC", | |
mcuCode: "STM32F105RCTx", | |
stmGlob: "STM32F105R(8-B-C)Tx" | |
}, | |
{ | |
chibiDef: "STM32F105xC", | |
mcuCode: "STM32F105VCTx", | |
stmGlob: "STM32F105V(8-B-C)Tx" | |
}, | |
{ | |
chibiDef: "STM32F107xC", | |
mcuCode: "STM32F107RCTx", | |
stmGlob: "STM32F107R(B-C)Tx" | |
}, | |
{ | |
chibiDef: "STM32F107xC", | |
mcuCode: "STM32F107VCTx", | |
stmGlob: "STM32F107V(B-C)Tx" | |
}, | |
{ | |
chibiDef: "STM32F107xC", | |
mcuCode: "STM32F107VCHx", | |
stmGlob: "STM32F107VCHx" | |
}, | |
{ | |
chibiDef: "STM32F205xx", | |
mcuCode: "STM32F205RBTx", | |
stmGlob: "STM32F205R(B-C-E-F-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F205xx", | |
mcuCode: "STM32F205RCTx", | |
stmGlob: "STM32F205R(B-C-E-F-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F205xx", | |
mcuCode: "STM32F205RETx", | |
stmGlob: "STM32F205R(B-C-E-F-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F205xx", | |
mcuCode: "STM32F205RFTx", | |
stmGlob: "STM32F205R(B-C-E-F-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F205xx", | |
mcuCode: "STM32F205RGTx", | |
stmGlob: "STM32F205R(B-C-E-F-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F205xx", | |
mcuCode: "STM32F205REYx", | |
stmGlob: "STM32F205R(E-G)Yx" | |
}, | |
{ | |
chibiDef: "STM32F205xx", | |
mcuCode: "STM32F205RGYx", | |
stmGlob: "STM32F205R(E-G)Yx" | |
}, | |
{ | |
chibiDef: "STM32F205xx", | |
mcuCode: "STM32F205RGEx", | |
stmGlob: "STM32F205RGEx" | |
}, | |
{ | |
chibiDef: "STM32F205xx", | |
mcuCode: "STM32F205VBTx", | |
stmGlob: "STM32F205V(B-C-E-F-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F205xx", | |
mcuCode: "STM32F205VCTx", | |
stmGlob: "STM32F205V(B-C-E-F-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F205xx", | |
mcuCode: "STM32F205VETx", | |
stmGlob: "STM32F205V(B-C-E-F-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F205xx", | |
mcuCode: "STM32F205VFTx", | |
stmGlob: "STM32F205V(B-C-E-F-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F205xx", | |
mcuCode: "STM32F205VGTx", | |
stmGlob: "STM32F205V(B-C-E-F-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F205xx", | |
mcuCode: "STM32F205ZCTx", | |
stmGlob: "STM32F205Z(C-E-F-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F205xx", | |
mcuCode: "STM32F205ZETx", | |
stmGlob: "STM32F205Z(C-E-F-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F205xx", | |
mcuCode: "STM32F205ZFTx", | |
stmGlob: "STM32F205Z(C-E-F-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F205xx", | |
mcuCode: "STM32F205ZGTx", | |
stmGlob: "STM32F205Z(C-E-F-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F207xx", | |
mcuCode: "STM32F207ICHx", | |
stmGlob: "STM32F207I(C-E-F-G)Hx" | |
}, | |
{ | |
chibiDef: "STM32F207xx", | |
mcuCode: "STM32F207IEHx", | |
stmGlob: "STM32F207I(C-E-F-G)Hx" | |
}, | |
{ | |
chibiDef: "STM32F207xx", | |
mcuCode: "STM32F207IFHx", | |
stmGlob: "STM32F207I(C-E-F-G)Hx" | |
}, | |
{ | |
chibiDef: "STM32F207xx", | |
mcuCode: "STM32F207IGHx", | |
stmGlob: "STM32F207I(C-E-F-G)Hx" | |
}, | |
{ | |
chibiDef: "STM32F207xx", | |
mcuCode: "STM32F207ICTx", | |
stmGlob: "STM32F207I(C-E-F-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F207xx", | |
mcuCode: "STM32F207IETx", | |
stmGlob: "STM32F207I(C-E-F-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F207xx", | |
mcuCode: "STM32F207IFTx", | |
stmGlob: "STM32F207I(C-E-F-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F207xx", | |
mcuCode: "STM32F207IGTx", | |
stmGlob: "STM32F207I(C-E-F-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F207xx", | |
mcuCode: "STM32F207VCTx", | |
stmGlob: "STM32F207V(C-E-F-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F207xx", | |
mcuCode: "STM32F207VETx", | |
stmGlob: "STM32F207V(C-E-F-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F207xx", | |
mcuCode: "STM32F207VFTx", | |
stmGlob: "STM32F207V(C-E-F-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F207xx", | |
mcuCode: "STM32F207VGTx", | |
stmGlob: "STM32F207V(C-E-F-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F207xx", | |
mcuCode: "STM32F207ZCTx", | |
stmGlob: "STM32F207Z(C-E-F-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F207xx", | |
mcuCode: "STM32F207ZETx", | |
stmGlob: "STM32F207Z(C-E-F-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F207xx", | |
mcuCode: "STM32F207ZFTx", | |
stmGlob: "STM32F207Z(C-E-F-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F207xx", | |
mcuCode: "STM32F207ZGTx", | |
stmGlob: "STM32F207Z(C-E-F-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F215xx", | |
mcuCode: "STM32F215RETx", | |
stmGlob: "STM32F215R(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F215xx", | |
mcuCode: "STM32F215RGTx", | |
stmGlob: "STM32F215R(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F215xx", | |
mcuCode: "STM32F215VETx", | |
stmGlob: "STM32F215V(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F215xx", | |
mcuCode: "STM32F215VGTx", | |
stmGlob: "STM32F215V(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F215xx", | |
mcuCode: "STM32F215ZETx", | |
stmGlob: "STM32F215Z(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F215xx", | |
mcuCode: "STM32F215ZGTx", | |
stmGlob: "STM32F215Z(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F217xx", | |
mcuCode: "STM32F217IEHx", | |
stmGlob: "STM32F217I(E-G)Hx" | |
}, | |
{ | |
chibiDef: "STM32F217xx", | |
mcuCode: "STM32F217IGHx", | |
stmGlob: "STM32F217I(E-G)Hx" | |
}, | |
{ | |
chibiDef: "STM32F217xx", | |
mcuCode: "STM32F217IETx", | |
stmGlob: "STM32F217I(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F217xx", | |
mcuCode: "STM32F217IGTx", | |
stmGlob: "STM32F217I(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F217xx", | |
mcuCode: "STM32F217VETx", | |
stmGlob: "STM32F217V(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F217xx", | |
mcuCode: "STM32F217VGTx", | |
stmGlob: "STM32F217V(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F217xx", | |
mcuCode: "STM32F217ZETx", | |
stmGlob: "STM32F217Z(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F217xx", | |
mcuCode: "STM32F217ZGTx", | |
stmGlob: "STM32F217Z(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F301x8", | |
mcuCode: "STM32F301C8Tx", | |
stmGlob: "STM32F301C(6-8)Tx" | |
}, | |
{ | |
chibiDef: "STM32F301x8", | |
mcuCode: "STM32F301C8Yx", | |
stmGlob: "STM32F301C8Yx" | |
}, | |
{ | |
chibiDef: "STM32F301x8", | |
mcuCode: "STM32F301K8Tx", | |
stmGlob: "STM32F301K(6-8)Tx" | |
}, | |
{ | |
chibiDef: "STM32F301x8", | |
mcuCode: "STM32F301K8Ux", | |
stmGlob: "STM32F301K(6-8)Ux" | |
}, | |
{ | |
chibiDef: "STM32F301x8", | |
mcuCode: "STM32F301R8Tx", | |
stmGlob: "STM32F301R(6-8)Tx" | |
}, | |
{ | |
chibiDef: "STM32F302x8", | |
mcuCode: "STM32F302C8Tx", | |
stmGlob: "STM32F302C(6-8)Tx" | |
}, | |
{ | |
chibiDef: "STM32F302x8", | |
mcuCode: "STM32F302C8Yx", | |
stmGlob: "STM32F302C8Yx" | |
}, | |
{ | |
chibiDef: "STM32F302xC", | |
mcuCode: "STM32F302CCTx", | |
stmGlob: "STM32F302C(B-C)Tx" | |
}, | |
{ | |
chibiDef: "STM32F302x8", | |
mcuCode: "STM32F302K8Ux", | |
stmGlob: "STM32F302K(6-8)Ux" | |
}, | |
{ | |
chibiDef: "STM32F302x8", | |
mcuCode: "STM32F302R8Tx", | |
stmGlob: "STM32F302R(6-8)Tx" | |
}, | |
{ | |
chibiDef: "STM32F302xC", | |
mcuCode: "STM32F302RCTx", | |
stmGlob: "STM32F302R(B-C)Tx" | |
}, | |
{ | |
chibiDef: "STM32F302xE", | |
mcuCode: "STM32F302RETx", | |
stmGlob: "STM32F302R(D-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F302xC", | |
mcuCode: "STM32F302VCTx", | |
stmGlob: "STM32F302V(B-C)Tx" | |
}, | |
{ | |
chibiDef: "STM32F302xC", | |
mcuCode: "STM32F302VCYx", | |
stmGlob: "STM32F302VCYx" | |
}, | |
{ | |
chibiDef: "STM32F302xE", | |
mcuCode: "STM32F302VEHx", | |
stmGlob: "STM32F302V(D-E)Hx" | |
}, | |
{ | |
chibiDef: "STM32F302xE", | |
mcuCode: "STM32F302VETx", | |
stmGlob: "STM32F302V(D-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F302xE", | |
mcuCode: "STM32F302ZETx", | |
stmGlob: "STM32F302Z(D-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F303x8", | |
mcuCode: "STM32F303C8Tx", | |
stmGlob: "STM32F303C(6-8)Tx" | |
}, | |
{ | |
chibiDef: "STM32F303x8", | |
mcuCode: "STM32F303C8Yx", | |
stmGlob: "STM32F303C8Yx" | |
}, | |
{ | |
chibiDef: "STM32F303xC", | |
mcuCode: "STM32F303CCTx", | |
stmGlob: "STM32F303C(B-C)Tx" | |
}, | |
{ | |
chibiDef: "STM32F303x8", | |
mcuCode: "STM32F303K8Tx", | |
stmGlob: "STM32F303K(6-8)Tx" | |
}, | |
{ | |
chibiDef: "STM32F303x8", | |
mcuCode: "STM32F303K8Ux", | |
stmGlob: "STM32F303K(6-8)Ux" | |
}, | |
{ | |
chibiDef: "STM32F303x8", | |
mcuCode: "STM32F303R8Tx", | |
stmGlob: "STM32F303R(6-8)Tx" | |
}, | |
{ | |
chibiDef: "STM32F303xC", | |
mcuCode: "STM32F303RCTx", | |
stmGlob: "STM32F303R(B-C)Tx" | |
}, | |
{ | |
chibiDef: "STM32F303xE", | |
mcuCode: "STM32F303RETx", | |
stmGlob: "STM32F303R(D-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F303xC", | |
mcuCode: "STM32F303VCTx", | |
stmGlob: "STM32F303V(B-C)Tx" | |
}, | |
{ | |
chibiDef: "STM32F303xC", | |
mcuCode: "STM32F303VCYx", | |
stmGlob: "STM32F303VCYx" | |
}, | |
{ | |
chibiDef: "STM32F303xE", | |
mcuCode: "STM32F303VEHx", | |
stmGlob: "STM32F303V(D-E)Hx" | |
}, | |
{ | |
chibiDef: "STM32F303xE", | |
mcuCode: "STM32F303VETx", | |
stmGlob: "STM32F303V(D-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F303xE", | |
mcuCode: "STM32F303VEYx", | |
stmGlob: "STM32F303VEYx" | |
}, | |
{ | |
chibiDef: "STM32F303xE", | |
mcuCode: "STM32F303ZETx", | |
stmGlob: "STM32F303Z(D-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F318x8", | |
mcuCode: "STM32F318C8Tx", | |
stmGlob: "STM32F318C8Tx" | |
}, | |
{ | |
chibiDef: "STM32F318x8", | |
mcuCode: "STM32F318C8Yx", | |
stmGlob: "STM32F318C8Yx" | |
}, | |
{ | |
chibiDef: "STM32F318x8", | |
mcuCode: "STM32F318K8Ux", | |
stmGlob: "STM32F318K8Ux" | |
}, | |
{ | |
chibiDef: "STM32F328x8", | |
mcuCode: "STM32F328C8Tx", | |
stmGlob: "STM32F328C8Tx" | |
}, | |
{ | |
chibiDef: "STM32F334x8", | |
mcuCode: "STM32F334C8Tx", | |
stmGlob: "STM32F334C(4-6-8)Tx" | |
}, | |
{ | |
chibiDef: "STM32F334x8", | |
mcuCode: "STM32F334C8Yx", | |
stmGlob: "STM32F334C8Yx" | |
}, | |
{ | |
chibiDef: "STM32F334x8", | |
mcuCode: "STM32F334K8Tx", | |
stmGlob: "STM32F334K(4-6-8)Tx" | |
}, | |
{ | |
chibiDef: "STM32F334x8", | |
mcuCode: "STM32F334K8Ux", | |
stmGlob: "STM32F334K(4-6-8)Ux" | |
}, | |
{ | |
chibiDef: "STM32F334x8", | |
mcuCode: "STM32F334R8Tx", | |
stmGlob: "STM32F334R(6-8)Tx" | |
}, | |
{ | |
chibiDef: "STM32F358xC", | |
mcuCode: "STM32F358CCTx", | |
stmGlob: "STM32F358CCTx" | |
}, | |
{ | |
chibiDef: "STM32F358xC", | |
mcuCode: "STM32F358RCTx", | |
stmGlob: "STM32F358RCTx" | |
}, | |
{ | |
chibiDef: "STM32F358xC", | |
mcuCode: "STM32F358VCTx", | |
stmGlob: "STM32F358VCTx" | |
}, | |
{ | |
chibiDef: "STM32F373xC", | |
mcuCode: "STM32F373CCTx", | |
stmGlob: "STM32F373C(8-B-C)Tx" | |
}, | |
{ | |
chibiDef: "STM32F373xC", | |
mcuCode: "STM32F373RCTx", | |
stmGlob: "STM32F373R(8-B-C)Tx" | |
}, | |
{ | |
chibiDef: "STM32F373xC", | |
mcuCode: "STM32F373VCHx", | |
stmGlob: "STM32F373V(8-B-C)Hx" | |
}, | |
{ | |
chibiDef: "STM32F373xC", | |
mcuCode: "STM32F373VCTx", | |
stmGlob: "STM32F373V(8-B-C)Tx" | |
}, | |
{ | |
chibiDef: "STM32F378xx", | |
mcuCode: "STM32F378CCTx", | |
stmGlob: "STM32F378CCTx" | |
}, | |
{ | |
chibiDef: "STM32F378xx", | |
mcuCode: "STM32F378RCTx", | |
stmGlob: "STM32F378RCTx" | |
}, | |
{ | |
chibiDef: "STM32F378xx", | |
mcuCode: "STM32F378RCYx", | |
stmGlob: "STM32F378RCYx" | |
}, | |
{ | |
chibiDef: "STM32F378xx", | |
mcuCode: "STM32F378VCHx", | |
stmGlob: "STM32F378VCHx" | |
}, | |
{ | |
chibiDef: "STM32F378xx", | |
mcuCode: "STM32F378VCTx", | |
stmGlob: "STM32F378VCTx" | |
}, | |
{ | |
chibiDef: "STM32F398xx", | |
mcuCode: "STM32F398VETx", | |
stmGlob: "STM32F398VETx" | |
}, | |
{ | |
chibiDef: "STM32F401xx", | |
mcuCode: "STM32F401CBUx", | |
stmGlob: "STM32F401C(B-C)Ux" | |
}, | |
{ | |
chibiDef: "STM32F401xC", | |
mcuCode: "STM32F401CCUx", | |
stmGlob: "STM32F401C(B-C)Ux" | |
}, | |
{ | |
chibiDef: "STM32F401xx", | |
mcuCode: "STM32F401CBYx", | |
stmGlob: "STM32F401C(B-C)Yx" | |
}, | |
{ | |
chibiDef: "STM32F401xC", | |
mcuCode: "STM32F401CCYx", | |
stmGlob: "STM32F401C(B-C)Yx" | |
}, | |
{ | |
chibiDef: "STM32F401xC", | |
mcuCode: "STM32F401CCFx", | |
stmGlob: "STM32F401CCFx" | |
}, | |
{ | |
chibiDef: "STM32F401xx", | |
mcuCode: "STM32F401CDUx", | |
stmGlob: "STM32F401C(D-E)Ux" | |
}, | |
{ | |
chibiDef: "STM32F401xE", | |
mcuCode: "STM32F401CEUx", | |
stmGlob: "STM32F401C(D-E)Ux" | |
}, | |
{ | |
chibiDef: "STM32F401xx", | |
mcuCode: "STM32F401CDYx", | |
stmGlob: "STM32F401C(D-E)Yx" | |
}, | |
{ | |
chibiDef: "STM32F401xE", | |
mcuCode: "STM32F401CEYx", | |
stmGlob: "STM32F401C(D-E)Yx" | |
}, | |
{ | |
chibiDef: "STM32F401xx", | |
mcuCode: "STM32F401RBTx", | |
stmGlob: "STM32F401R(B-C)Tx" | |
}, | |
{ | |
chibiDef: "STM32F401xC", | |
mcuCode: "STM32F401RCTx", | |
stmGlob: "STM32F401R(B-C)Tx" | |
}, | |
{ | |
chibiDef: "STM32F401xx", | |
mcuCode: "STM32F401RDTx", | |
stmGlob: "STM32F401R(D-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F401xE", | |
mcuCode: "STM32F401RETx", | |
stmGlob: "STM32F401R(D-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F401xx", | |
mcuCode: "STM32F401VBHx", | |
stmGlob: "STM32F401V(B-C)Hx" | |
}, | |
{ | |
chibiDef: "STM32F401xC", | |
mcuCode: "STM32F401VCHx", | |
stmGlob: "STM32F401V(B-C)Hx" | |
}, | |
{ | |
chibiDef: "STM32F401xx", | |
mcuCode: "STM32F401VBTx", | |
stmGlob: "STM32F401V(B-C)Tx" | |
}, | |
{ | |
chibiDef: "STM32F401xC", | |
mcuCode: "STM32F401VCTx", | |
stmGlob: "STM32F401V(B-C)Tx" | |
}, | |
{ | |
chibiDef: "STM32F401xx", | |
mcuCode: "STM32F401VDHx", | |
stmGlob: "STM32F401V(D-E)Hx" | |
}, | |
{ | |
chibiDef: "STM32F401xE", | |
mcuCode: "STM32F401VEHx", | |
stmGlob: "STM32F401V(D-E)Hx" | |
}, | |
{ | |
chibiDef: "STM32F401xx", | |
mcuCode: "STM32F401VDTx", | |
stmGlob: "STM32F401V(D-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F401xE", | |
mcuCode: "STM32F401VETx", | |
stmGlob: "STM32F401V(D-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F405xx", | |
mcuCode: "STM32F405OEYx", | |
stmGlob: "STM32F405O(E-G)Yx" | |
}, | |
{ | |
chibiDef: "STM32F405xx", | |
mcuCode: "STM32F405OGYx", | |
stmGlob: "STM32F405O(E-G)Yx" | |
}, | |
{ | |
chibiDef: "STM32F405xx", | |
mcuCode: "STM32F405RGTx", | |
stmGlob: "STM32F405RGTx" | |
}, | |
{ | |
chibiDef: "STM32F405xx", | |
mcuCode: "STM32F405VGTx", | |
stmGlob: "STM32F405VGTx" | |
}, | |
{ | |
chibiDef: "STM32F405xx", | |
mcuCode: "STM32F405ZGTx", | |
stmGlob: "STM32F405ZGTx" | |
}, | |
{ | |
chibiDef: "STM32F407xx", | |
mcuCode: "STM32F407IEHx", | |
stmGlob: "STM32F407I(E-G)Hx" | |
}, | |
{ | |
chibiDef: "STM32F407xx", | |
mcuCode: "STM32F407IGHx", | |
stmGlob: "STM32F407I(E-G)Hx" | |
}, | |
{ | |
chibiDef: "STM32F407xx", | |
mcuCode: "STM32F407IETx", | |
stmGlob: "STM32F407I(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F407xx", | |
mcuCode: "STM32F407IGTx", | |
stmGlob: "STM32F407I(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F407xx", | |
mcuCode: "STM32F407VETx", | |
stmGlob: "STM32F407V(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F407xx", | |
mcuCode: "STM32F407VGTx", | |
stmGlob: "STM32F407V(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F407xx", | |
mcuCode: "STM32F407ZETx", | |
stmGlob: "STM32F407Z(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F407xx", | |
mcuCode: "STM32F407ZGTx", | |
stmGlob: "STM32F407Z(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F410Cx", | |
mcuCode: "STM32F410C8Tx", | |
stmGlob: "STM32F410C(8-B)Tx" | |
}, | |
{ | |
chibiDef: "STM32F410Cx", | |
mcuCode: "STM32F410CBTx", | |
stmGlob: "STM32F410C(8-B)Tx" | |
}, | |
{ | |
chibiDef: "STM32F410Cx", | |
mcuCode: "STM32F410C8Ux", | |
stmGlob: "STM32F410C(8-B)Ux" | |
}, | |
{ | |
chibiDef: "STM32F410Cx", | |
mcuCode: "STM32F410CBUx", | |
stmGlob: "STM32F410C(8-B)Ux" | |
}, | |
{ | |
chibiDef: "STM32F410Rx", | |
mcuCode: "STM32F410R8Ix", | |
stmGlob: "STM32F410R(8-B)Ix" | |
}, | |
{ | |
chibiDef: "STM32F410Rx", | |
mcuCode: "STM32F410RBIx", | |
stmGlob: "STM32F410R(8-B)Ix" | |
}, | |
{ | |
chibiDef: "STM32F410Rx", | |
mcuCode: "STM32F410R8Tx", | |
stmGlob: "STM32F410R(8-B)Tx" | |
}, | |
{ | |
chibiDef: "STM32F410Rx", | |
mcuCode: "STM32F410RBTx", | |
stmGlob: "STM32F410R(8-B)Tx" | |
}, | |
{ | |
chibiDef: "STM32F410Tx", | |
mcuCode: "STM32F410T8Yx", | |
stmGlob: "STM32F410T(8-B)Yx" | |
}, | |
{ | |
chibiDef: "STM32F410Tx", | |
mcuCode: "STM32F410TBYx", | |
stmGlob: "STM32F410T(8-B)Yx" | |
}, | |
{ | |
chibiDef: "STM32F411xx", | |
mcuCode: "STM32F411CCUx", | |
stmGlob: "STM32F411C(C-E)Ux" | |
}, | |
{ | |
chibiDef: "STM32F411xE", | |
mcuCode: "STM32F411CEUx", | |
stmGlob: "STM32F411C(C-E)Ux" | |
}, | |
{ | |
chibiDef: "STM32F411xx", | |
mcuCode: "STM32F411CCYx", | |
stmGlob: "STM32F411C(C-E)Yx" | |
}, | |
{ | |
chibiDef: "STM32F411xE", | |
mcuCode: "STM32F411CEYx", | |
stmGlob: "STM32F411C(C-E)Yx" | |
}, | |
{ | |
chibiDef: "STM32F411xx", | |
mcuCode: "STM32F411RCTx", | |
stmGlob: "STM32F411R(C-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F411xE", | |
mcuCode: "STM32F411RETx", | |
stmGlob: "STM32F411R(C-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F411xx", | |
mcuCode: "STM32F411VCHx", | |
stmGlob: "STM32F411V(C-E)Hx" | |
}, | |
{ | |
chibiDef: "STM32F411xE", | |
mcuCode: "STM32F411VEHx", | |
stmGlob: "STM32F411V(C-E)Hx" | |
}, | |
{ | |
chibiDef: "STM32F411xx", | |
mcuCode: "STM32F411VCTx", | |
stmGlob: "STM32F411V(C-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F411xE", | |
mcuCode: "STM32F411VETx", | |
stmGlob: "STM32F411V(C-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F412Cx", | |
mcuCode: "STM32F412CEUx", | |
stmGlob: "STM32F412C(E-G)Ux" | |
}, | |
{ | |
chibiDef: "STM32F412Cx", | |
mcuCode: "STM32F412CGUx", | |
stmGlob: "STM32F412C(E-G)Ux" | |
}, | |
{ | |
chibiDef: "STM32F412Rx", | |
mcuCode: "STM32F412RETx", | |
stmGlob: "STM32F412R(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F412Rx", | |
mcuCode: "STM32F412RGTx", | |
stmGlob: "STM32F412R(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F412Rx", | |
mcuCode: "STM32F412REYxP", | |
stmGlob: "STM32F412R(E-G)YxP" | |
}, | |
{ | |
chibiDef: "STM32F412Rx", | |
mcuCode: "STM32F412RGYxP", | |
stmGlob: "STM32F412R(E-G)YxP" | |
}, | |
{ | |
chibiDef: "STM32F412Rx", | |
mcuCode: "STM32F412REYx", | |
stmGlob: "STM32F412R(E-G)Yx" | |
}, | |
{ | |
chibiDef: "STM32F412Rx", | |
mcuCode: "STM32F412RGYx", | |
stmGlob: "STM32F412R(E-G)Yx" | |
}, | |
{ | |
chibiDef: "STM32F412Vx", | |
mcuCode: "STM32F412VEHx", | |
stmGlob: "STM32F412V(E-G)Hx" | |
}, | |
{ | |
chibiDef: "STM32F412Vx", | |
mcuCode: "STM32F412VGHx", | |
stmGlob: "STM32F412V(E-G)Hx" | |
}, | |
{ | |
chibiDef: "STM32F412Vx", | |
mcuCode: "STM32F412VETx", | |
stmGlob: "STM32F412V(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F412Vx", | |
mcuCode: "STM32F412VGTx", | |
stmGlob: "STM32F412V(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F412Zx", | |
mcuCode: "STM32F412ZEJx", | |
stmGlob: "STM32F412Z(E-G)Jx" | |
}, | |
{ | |
chibiDef: "STM32F412Zx", | |
mcuCode: "STM32F412ZGJx", | |
stmGlob: "STM32F412Z(E-G)Jx" | |
}, | |
{ | |
chibiDef: "STM32F412Zx", | |
mcuCode: "STM32F412ZETx", | |
stmGlob: "STM32F412Z(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F412Zx", | |
mcuCode: "STM32F412ZGTx", | |
stmGlob: "STM32F412Z(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F40_41xxx", | |
mcuCode: "STM32F413CGUx", | |
stmGlob: "STM32F413C(G-H)Ux" | |
}, | |
{ | |
chibiDef: "STM32F40_41xxx", | |
mcuCode: "STM32F413CHUx", | |
stmGlob: "STM32F413C(G-H)Ux" | |
}, | |
{ | |
chibiDef: "STM32F40_41xxx", | |
mcuCode: "STM32F413MGYx", | |
stmGlob: "STM32F413M(G-H)Yx" | |
}, | |
{ | |
chibiDef: "STM32F40_41xxx", | |
mcuCode: "STM32F413MHYx", | |
stmGlob: "STM32F413M(G-H)Yx" | |
}, | |
{ | |
chibiDef: "STM32F40_41xxx", | |
mcuCode: "STM32F413RGTx", | |
stmGlob: "STM32F413R(G-H)Tx" | |
}, | |
{ | |
chibiDef: "STM32F40_41xxx", | |
mcuCode: "STM32F413RHTx", | |
stmGlob: "STM32F413R(G-H)Tx" | |
}, | |
{ | |
chibiDef: "STM32F40_41xxx", | |
mcuCode: "STM32F413VGHx", | |
stmGlob: "STM32F413V(G-H)Hx" | |
}, | |
{ | |
chibiDef: "STM32F40_41xxx", | |
mcuCode: "STM32F413VHHx", | |
stmGlob: "STM32F413V(G-H)Hx" | |
}, | |
{ | |
chibiDef: "STM32F40_41xxx", | |
mcuCode: "STM32F413VGTx", | |
stmGlob: "STM32F413V(G-H)Tx" | |
}, | |
{ | |
chibiDef: "STM32F40_41xxx", | |
mcuCode: "STM32F413VHTx", | |
stmGlob: "STM32F413V(G-H)Tx" | |
}, | |
{ | |
chibiDef: "STM32F40_41xxx", | |
mcuCode: "STM32F413ZGJx", | |
stmGlob: "STM32F413Z(G-H)Jx" | |
}, | |
{ | |
chibiDef: "STM32F40_41xxx", | |
mcuCode: "STM32F413ZHJx", | |
stmGlob: "STM32F413Z(G-H)Jx" | |
}, | |
{ | |
chibiDef: "STM32F40_41xxx", | |
mcuCode: "STM32F413ZGTx", | |
stmGlob: "STM32F413Z(G-H)Tx" | |
}, | |
{ | |
chibiDef: "STM32F40_41xxx", | |
mcuCode: "STM32F413ZHTx", | |
stmGlob: "STM32F413Z(G-H)Tx" | |
}, | |
{ | |
chibiDef: "STM32F415xx", | |
mcuCode: "STM32F415OGYx", | |
stmGlob: "STM32F415OGYx" | |
}, | |
{ | |
chibiDef: "STM32F415xx", | |
mcuCode: "STM32F415RGTx", | |
stmGlob: "STM32F415RGTx" | |
}, | |
{ | |
chibiDef: "STM32F415xx", | |
mcuCode: "STM32F415VGTx", | |
stmGlob: "STM32F415VGTx" | |
}, | |
{ | |
chibiDef: "STM32F415xx", | |
mcuCode: "STM32F415ZGTx", | |
stmGlob: "STM32F415ZGTx" | |
}, | |
{ | |
chibiDef: "STM32F417xx", | |
mcuCode: "STM32F417IEHx", | |
stmGlob: "STM32F417I(E-G)Hx" | |
}, | |
{ | |
chibiDef: "STM32F417xx", | |
mcuCode: "STM32F417IGHx", | |
stmGlob: "STM32F417I(E-G)Hx" | |
}, | |
{ | |
chibiDef: "STM32F417xx", | |
mcuCode: "STM32F417IETx", | |
stmGlob: "STM32F417I(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F417xx", | |
mcuCode: "STM32F417IGTx", | |
stmGlob: "STM32F417I(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F417xx", | |
mcuCode: "STM32F417VETx", | |
stmGlob: "STM32F417V(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F417xx", | |
mcuCode: "STM32F417VGTx", | |
stmGlob: "STM32F417V(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F417xx", | |
mcuCode: "STM32F417ZETx", | |
stmGlob: "STM32F417Z(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F417xx", | |
mcuCode: "STM32F417ZGTx", | |
stmGlob: "STM32F417Z(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F427xx", | |
mcuCode: "STM32F427AGHx", | |
stmGlob: "STM32F427A(G-I)Hx" | |
}, | |
{ | |
chibiDef: "STM32F427xx", | |
mcuCode: "STM32F427AIHx", | |
stmGlob: "STM32F427A(G-I)Hx" | |
}, | |
{ | |
chibiDef: "STM32F427xx", | |
mcuCode: "STM32F427IGHx", | |
stmGlob: "STM32F427I(G-I)Hx" | |
}, | |
{ | |
chibiDef: "STM32F427xx", | |
mcuCode: "STM32F427IIHx", | |
stmGlob: "STM32F427I(G-I)Hx" | |
}, | |
{ | |
chibiDef: "STM32F427xx", | |
mcuCode: "STM32F427IGTx", | |
stmGlob: "STM32F427I(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F427xx", | |
mcuCode: "STM32F427IITx", | |
stmGlob: "STM32F427I(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F427xx", | |
mcuCode: "STM32F427VGTx", | |
stmGlob: "STM32F427V(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F427xx", | |
mcuCode: "STM32F427VITx", | |
stmGlob: "STM32F427V(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F427xx", | |
mcuCode: "STM32F427ZGTx", | |
stmGlob: "STM32F427Z(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F427xx", | |
mcuCode: "STM32F427ZITx", | |
stmGlob: "STM32F427Z(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F429xx", | |
mcuCode: "STM32F429AGHx", | |
stmGlob: "STM32F429A(G-I)Hx" | |
}, | |
{ | |
chibiDef: "STM32F429xx", | |
mcuCode: "STM32F429AIHx", | |
stmGlob: "STM32F429A(G-I)Hx" | |
}, | |
{ | |
chibiDef: "STM32F429xx", | |
mcuCode: "STM32F429BETx", | |
stmGlob: "STM32F429B(E-G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F429xx", | |
mcuCode: "STM32F429BGTx", | |
stmGlob: "STM32F429B(E-G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F429xx", | |
mcuCode: "STM32F429BITx", | |
stmGlob: "STM32F429B(E-G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F429xx", | |
mcuCode: "STM32F429IEHx", | |
stmGlob: "STM32F429I(E-G-I)Hx" | |
}, | |
{ | |
chibiDef: "STM32F429xx", | |
mcuCode: "STM32F429IGHx", | |
stmGlob: "STM32F429I(E-G-I)Hx" | |
}, | |
{ | |
chibiDef: "STM32F429xx", | |
mcuCode: "STM32F429IIHx", | |
stmGlob: "STM32F429I(E-G-I)Hx" | |
}, | |
{ | |
chibiDef: "STM32F429xx", | |
mcuCode: "STM32F429IETx", | |
stmGlob: "STM32F429I(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F429xx", | |
mcuCode: "STM32F429IGTx", | |
stmGlob: "STM32F429I(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F429xx", | |
mcuCode: "STM32F429IITx", | |
stmGlob: "STM32F429IITx" | |
}, | |
{ | |
chibiDef: "STM32F429xx", | |
mcuCode: "STM32F429NEHx", | |
stmGlob: "STM32F429N(E-G)Hx" | |
}, | |
{ | |
chibiDef: "STM32F429xx", | |
mcuCode: "STM32F429NGHx", | |
stmGlob: "STM32F429N(E-G)Hx" | |
}, | |
{ | |
chibiDef: "STM32F429xx", | |
mcuCode: "STM32F429NIHx", | |
stmGlob: "STM32F429NIHx" | |
}, | |
{ | |
chibiDef: "STM32F429xx", | |
mcuCode: "STM32F429VETx", | |
stmGlob: "STM32F429V(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F429xx", | |
mcuCode: "STM32F429VGTx", | |
stmGlob: "STM32F429V(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F429xx", | |
mcuCode: "STM32F429VITx", | |
stmGlob: "STM32F429VITx" | |
}, | |
{ | |
chibiDef: "STM32F429xx", | |
mcuCode: "STM32F429ZETx", | |
stmGlob: "STM32F429Z(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F429xx", | |
mcuCode: "STM32F429ZGTx", | |
stmGlob: "STM32F429Z(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F429xx", | |
mcuCode: "STM32F429ZGYx", | |
stmGlob: "STM32F429ZGYx" | |
}, | |
{ | |
chibiDef: "STM32F429xx", | |
mcuCode: "STM32F429ZITx", | |
stmGlob: "STM32F429ZITx" | |
}, | |
{ | |
chibiDef: "STM32F429xx", | |
mcuCode: "STM32F429ZIYx", | |
stmGlob: "STM32F429ZIYx" | |
}, | |
{ | |
chibiDef: "STM32F437xx", | |
mcuCode: "STM32F437AIHx", | |
stmGlob: "STM32F437AIHx" | |
}, | |
{ | |
chibiDef: "STM32F437xx", | |
mcuCode: "STM32F437IGHx", | |
stmGlob: "STM32F437I(G-I)Hx" | |
}, | |
{ | |
chibiDef: "STM32F437xx", | |
mcuCode: "STM32F437IIHx", | |
stmGlob: "STM32F437I(G-I)Hx" | |
}, | |
{ | |
chibiDef: "STM32F437xx", | |
mcuCode: "STM32F437IGTx", | |
stmGlob: "STM32F437I(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F437xx", | |
mcuCode: "STM32F437IITx", | |
stmGlob: "STM32F437I(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F437xx", | |
mcuCode: "STM32F437VGTx", | |
stmGlob: "STM32F437V(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F437xx", | |
mcuCode: "STM32F437VITx", | |
stmGlob: "STM32F437V(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F437xx", | |
mcuCode: "STM32F437ZGTx", | |
stmGlob: "STM32F437Z(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F437xx", | |
mcuCode: "STM32F437ZITx", | |
stmGlob: "STM32F437Z(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F439xx", | |
mcuCode: "STM32F439AIHx", | |
stmGlob: "STM32F439AIHx" | |
}, | |
{ | |
chibiDef: "STM32F439xx", | |
mcuCode: "STM32F439BGTx", | |
stmGlob: "STM32F439B(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F439xx", | |
mcuCode: "STM32F439BITx", | |
stmGlob: "STM32F439B(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F439xx", | |
mcuCode: "STM32F439IGHx", | |
stmGlob: "STM32F439I(G-I)Hx" | |
}, | |
{ | |
chibiDef: "STM32F439xx", | |
mcuCode: "STM32F439IIHx", | |
stmGlob: "STM32F439I(G-I)Hx" | |
}, | |
{ | |
chibiDef: "STM32F439xx", | |
mcuCode: "STM32F439IGTx", | |
stmGlob: "STM32F439I(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F439xx", | |
mcuCode: "STM32F439IITx", | |
stmGlob: "STM32F439I(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F439xx", | |
mcuCode: "STM32F439NGHx", | |
stmGlob: "STM32F439N(G-I)Hx" | |
}, | |
{ | |
chibiDef: "STM32F439xx", | |
mcuCode: "STM32F439NIHx", | |
stmGlob: "STM32F439N(G-I)Hx" | |
}, | |
{ | |
chibiDef: "STM32F439xx", | |
mcuCode: "STM32F439VGTx", | |
stmGlob: "STM32F439V(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F439xx", | |
mcuCode: "STM32F439VITx", | |
stmGlob: "STM32F439V(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F439xx", | |
mcuCode: "STM32F439ZGTx", | |
stmGlob: "STM32F439Z(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F439xx", | |
mcuCode: "STM32F439ZITx", | |
stmGlob: "STM32F439Z(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F439xx", | |
mcuCode: "STM32F439ZGYx", | |
stmGlob: "STM32F439Z(G-I)Yx" | |
}, | |
{ | |
chibiDef: "STM32F439xx", | |
mcuCode: "STM32F439ZIYx", | |
stmGlob: "STM32F439Z(G-I)Yx" | |
}, | |
{ | |
chibiDef: "STM32F446xx", | |
mcuCode: "STM32F446MCYx", | |
stmGlob: "STM32F446M(C-E)Yx" | |
}, | |
{ | |
chibiDef: "STM32F446xx", | |
mcuCode: "STM32F446MEYx", | |
stmGlob: "STM32F446M(C-E)Yx" | |
}, | |
{ | |
chibiDef: "STM32F446xx", | |
mcuCode: "STM32F446RCTx", | |
stmGlob: "STM32F446R(C-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F446xx", | |
mcuCode: "STM32F446RETx", | |
stmGlob: "STM32F446R(C-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F446xx", | |
mcuCode: "STM32F446VCTx", | |
stmGlob: "STM32F446V(C-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F446xx", | |
mcuCode: "STM32F446VETx", | |
stmGlob: "STM32F446V(C-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F446xx", | |
mcuCode: "STM32F446ZCHx", | |
stmGlob: "STM32F446Z(C-E)Hx" | |
}, | |
{ | |
chibiDef: "STM32F446xx", | |
mcuCode: "STM32F446ZEHx", | |
stmGlob: "STM32F446Z(C-E)Hx" | |
}, | |
{ | |
chibiDef: "STM32F446xx", | |
mcuCode: "STM32F446ZCJx", | |
stmGlob: "STM32F446Z(C-E)Jx" | |
}, | |
{ | |
chibiDef: "STM32F446xx", | |
mcuCode: "STM32F446ZEJx", | |
stmGlob: "STM32F446Z(C-E)Jx" | |
}, | |
{ | |
chibiDef: "STM32F446xx", | |
mcuCode: "STM32F446ZCTx", | |
stmGlob: "STM32F446Z(C-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F446xx", | |
mcuCode: "STM32F446ZETx", | |
stmGlob: "STM32F446Z(C-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F469xx", | |
mcuCode: "STM32F469AEHx", | |
stmGlob: "STM32F469A(E-G-I)Hx" | |
}, | |
{ | |
chibiDef: "STM32F469xx", | |
mcuCode: "STM32F469AGHx", | |
stmGlob: "STM32F469A(E-G-I)Hx" | |
}, | |
{ | |
chibiDef: "STM32F469xx", | |
mcuCode: "STM32F469AIHx", | |
stmGlob: "STM32F469A(E-G-I)Hx" | |
}, | |
{ | |
chibiDef: "STM32F469xx", | |
mcuCode: "STM32F469AEYx", | |
stmGlob: "STM32F469A(E-G-I)Yx" | |
}, | |
{ | |
chibiDef: "STM32F469xx", | |
mcuCode: "STM32F469AGYx", | |
stmGlob: "STM32F469A(E-G-I)Yx" | |
}, | |
{ | |
chibiDef: "STM32F469xx", | |
mcuCode: "STM32F469AIYx", | |
stmGlob: "STM32F469A(E-G-I)Yx" | |
}, | |
{ | |
chibiDef: "STM32F469xx", | |
mcuCode: "STM32F469BETx", | |
stmGlob: "STM32F469B(E-G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F469xx", | |
mcuCode: "STM32F469BGTx", | |
stmGlob: "STM32F469B(E-G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F469xx", | |
mcuCode: "STM32F469BITx", | |
stmGlob: "STM32F469B(E-G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F469xx", | |
mcuCode: "STM32F469IEHx", | |
stmGlob: "STM32F469I(E-G-I)Hx" | |
}, | |
{ | |
chibiDef: "STM32F469xx", | |
mcuCode: "STM32F469IGHx", | |
stmGlob: "STM32F469I(E-G-I)Hx" | |
}, | |
{ | |
chibiDef: "STM32F469xx", | |
mcuCode: "STM32F469IIHx", | |
stmGlob: "STM32F469I(E-G-I)Hx" | |
}, | |
{ | |
chibiDef: "STM32F469xx", | |
mcuCode: "STM32F469IETx", | |
stmGlob: "STM32F469I(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F469xx", | |
mcuCode: "STM32F469IGTx", | |
stmGlob: "STM32F469I(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F469xx", | |
mcuCode: "STM32F469IITx", | |
stmGlob: "STM32F469IITx" | |
}, | |
{ | |
chibiDef: "STM32F469xx", | |
mcuCode: "STM32F469NEHx", | |
stmGlob: "STM32F469N(E-G)Hx" | |
}, | |
{ | |
chibiDef: "STM32F469xx", | |
mcuCode: "STM32F469NGHx", | |
stmGlob: "STM32F469N(E-G)Hx" | |
}, | |
{ | |
chibiDef: "STM32F469xx", | |
mcuCode: "STM32F469NIHx", | |
stmGlob: "STM32F469NIHx" | |
}, | |
{ | |
chibiDef: "STM32F469xx", | |
mcuCode: "STM32F469VETx", | |
stmGlob: "STM32F469V(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F469xx", | |
mcuCode: "STM32F469VGTx", | |
stmGlob: "STM32F469V(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F469xx", | |
mcuCode: "STM32F469VITx", | |
stmGlob: "STM32F469VITx" | |
}, | |
{ | |
chibiDef: "STM32F469xx", | |
mcuCode: "STM32F469ZETx", | |
stmGlob: "STM32F469Z(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F469xx", | |
mcuCode: "STM32F469ZGTx", | |
stmGlob: "STM32F469Z(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F469xx", | |
mcuCode: "STM32F469ZITx", | |
stmGlob: "STM32F469ZITx" | |
}, | |
{ | |
chibiDef: "STM32F479xx", | |
mcuCode: "STM32F479AGHx", | |
stmGlob: "STM32F479A(G-I)Hx" | |
}, | |
{ | |
chibiDef: "STM32F479xx", | |
mcuCode: "STM32F479AIHx", | |
stmGlob: "STM32F479A(G-I)Hx" | |
}, | |
{ | |
chibiDef: "STM32F479xx", | |
mcuCode: "STM32F479AGYx", | |
stmGlob: "STM32F479A(G-I)Yx" | |
}, | |
{ | |
chibiDef: "STM32F479xx", | |
mcuCode: "STM32F479AIYx", | |
stmGlob: "STM32F479A(G-I)Yx" | |
}, | |
{ | |
chibiDef: "STM32F479xx", | |
mcuCode: "STM32F479BGTx", | |
stmGlob: "STM32F479B(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F479xx", | |
mcuCode: "STM32F479BITx", | |
stmGlob: "STM32F479B(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F479xx", | |
mcuCode: "STM32F479IGHx", | |
stmGlob: "STM32F479I(G-I)Hx" | |
}, | |
{ | |
chibiDef: "STM32F479xx", | |
mcuCode: "STM32F479IIHx", | |
stmGlob: "STM32F479I(G-I)Hx" | |
}, | |
{ | |
chibiDef: "STM32F479xx", | |
mcuCode: "STM32F479IGTx", | |
stmGlob: "STM32F479I(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F479xx", | |
mcuCode: "STM32F479IITx", | |
stmGlob: "STM32F479I(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F479xx", | |
mcuCode: "STM32F479NGHx", | |
stmGlob: "STM32F479N(G-I)Hx" | |
}, | |
{ | |
chibiDef: "STM32F479xx", | |
mcuCode: "STM32F479NIHx", | |
stmGlob: "STM32F479N(G-I)Hx" | |
}, | |
{ | |
chibiDef: "STM32F479xx", | |
mcuCode: "STM32F479VGTx", | |
stmGlob: "STM32F479V(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F479xx", | |
mcuCode: "STM32F479VITx", | |
stmGlob: "STM32F479V(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F479xx", | |
mcuCode: "STM32F479ZGTx", | |
stmGlob: "STM32F479Z(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F479xx", | |
mcuCode: "STM32F479ZITx", | |
stmGlob: "STM32F479Z(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F722xx", | |
mcuCode: "STM32F722ICKx", | |
stmGlob: "STM32F722I(C-E)Kx" | |
}, | |
{ | |
chibiDef: "STM32F722xx", | |
mcuCode: "STM32F722IEKx", | |
stmGlob: "STM32F722I(C-E)Kx" | |
}, | |
{ | |
chibiDef: "STM32F722xx", | |
mcuCode: "STM32F722ICTx", | |
stmGlob: "STM32F722I(C-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F722xx", | |
mcuCode: "STM32F722IETx", | |
stmGlob: "STM32F722I(C-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F722xx", | |
mcuCode: "STM32F722RCTx", | |
stmGlob: "STM32F722R(C-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F722xx", | |
mcuCode: "STM32F722RETx", | |
stmGlob: "STM32F722R(C-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F722xx", | |
mcuCode: "STM32F722VCTx", | |
stmGlob: "STM32F722V(C-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F722xx", | |
mcuCode: "STM32F722VETx", | |
stmGlob: "STM32F722V(C-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F722xx", | |
mcuCode: "STM32F722ZCTx", | |
stmGlob: "STM32F722Z(C-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F722xx", | |
mcuCode: "STM32F722ZETx", | |
stmGlob: "STM32F722Z(C-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F723xx", | |
mcuCode: "STM32F723ICKx", | |
stmGlob: "STM32F723I(C-E)Kx" | |
}, | |
{ | |
chibiDef: "STM32F723xx", | |
mcuCode: "STM32F723IEKx", | |
stmGlob: "STM32F723I(C-E)Kx" | |
}, | |
{ | |
chibiDef: "STM32F723xx", | |
mcuCode: "STM32F723ICTx", | |
stmGlob: "STM32F723I(C-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F723xx", | |
mcuCode: "STM32F723IETx", | |
stmGlob: "STM32F723I(C-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F723xx", | |
mcuCode: "STM32F723VCTx", | |
stmGlob: "STM32F723V(C-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F723xx", | |
mcuCode: "STM32F723VETx", | |
stmGlob: "STM32F723V(C-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F723xx", | |
mcuCode: "STM32F723VCYx", | |
stmGlob: "STM32F723V(C-E)Yx" | |
}, | |
{ | |
chibiDef: "STM32F723xx", | |
mcuCode: "STM32F723VEYx", | |
stmGlob: "STM32F723V(C-E)Yx" | |
}, | |
{ | |
chibiDef: "STM32F723xx", | |
mcuCode: "STM32F723ZCIx", | |
stmGlob: "STM32F723Z(C-E)Ix" | |
}, | |
{ | |
chibiDef: "STM32F723xx", | |
mcuCode: "STM32F723ZEIx", | |
stmGlob: "STM32F723Z(C-E)Ix" | |
}, | |
{ | |
chibiDef: "STM32F723xx", | |
mcuCode: "STM32F723ZCTx", | |
stmGlob: "STM32F723Z(C-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F723xx", | |
mcuCode: "STM32F723ZETx", | |
stmGlob: "STM32F723Z(C-E)Tx" | |
}, | |
{ | |
chibiDef: "STM32F732xx", | |
mcuCode: "STM32F732IEKx", | |
stmGlob: "STM32F732IEKx" | |
}, | |
{ | |
chibiDef: "STM32F732xx", | |
mcuCode: "STM32F732IETx", | |
stmGlob: "STM32F732IETx" | |
}, | |
{ | |
chibiDef: "STM32F732xx", | |
mcuCode: "STM32F732RETx", | |
stmGlob: "STM32F732RETx" | |
}, | |
{ | |
chibiDef: "STM32F732xx", | |
mcuCode: "STM32F732VETx", | |
stmGlob: "STM32F732VETx" | |
}, | |
{ | |
chibiDef: "STM32F732xx", | |
mcuCode: "STM32F732ZETx", | |
stmGlob: "STM32F732ZETx" | |
}, | |
{ | |
chibiDef: "STM32F733xx", | |
mcuCode: "STM32F733IEKx", | |
stmGlob: "STM32F733IEKx" | |
}, | |
{ | |
chibiDef: "STM32F733xx", | |
mcuCode: "STM32F733IETx", | |
stmGlob: "STM32F733IETx" | |
}, | |
{ | |
chibiDef: "STM32F733xx", | |
mcuCode: "STM32F733VETx", | |
stmGlob: "STM32F733VETx" | |
}, | |
{ | |
chibiDef: "STM32F733xx", | |
mcuCode: "STM32F733VEYx", | |
stmGlob: "STM32F733VEYx" | |
}, | |
{ | |
chibiDef: "STM32F733xx", | |
mcuCode: "STM32F733ZEIx", | |
stmGlob: "STM32F733ZEIx" | |
}, | |
{ | |
chibiDef: "STM32F733xx", | |
mcuCode: "STM32F733ZETx", | |
stmGlob: "STM32F733ZETx" | |
}, | |
{ | |
chibiDef: "STM32F745xx", | |
mcuCode: "STM32F745IEKx", | |
stmGlob: "STM32F745I(E-G)Kx" | |
}, | |
{ | |
chibiDef: "STM32F745xx", | |
mcuCode: "STM32F745IGKx", | |
stmGlob: "STM32F745I(E-G)Kx" | |
}, | |
{ | |
chibiDef: "STM32F745xx", | |
mcuCode: "STM32F745IETx", | |
stmGlob: "STM32F745I(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F745xx", | |
mcuCode: "STM32F745IGTx", | |
stmGlob: "STM32F745I(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F745xx", | |
mcuCode: "STM32F745VEHx", | |
stmGlob: "STM32F745V(E-G)Hx" | |
}, | |
{ | |
chibiDef: "STM32F745xx", | |
mcuCode: "STM32F745VGHx", | |
stmGlob: "STM32F745V(E-G)Hx" | |
}, | |
{ | |
chibiDef: "STM32F745xx", | |
mcuCode: "STM32F745VETx", | |
stmGlob: "STM32F745V(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F745xx", | |
mcuCode: "STM32F745VGTx", | |
stmGlob: "STM32F745V(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F745xx", | |
mcuCode: "STM32F745ZETx", | |
stmGlob: "STM32F745Z(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F745xx", | |
mcuCode: "STM32F745ZGTx", | |
stmGlob: "STM32F745Z(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F746xx", | |
mcuCode: "STM32F746BETx", | |
stmGlob: "STM32F746B(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F746xx", | |
mcuCode: "STM32F746BGTx", | |
stmGlob: "STM32F746B(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32F746xx", | |
mcuCode: "STM32F746IEKx", | |
stmGlob: "STM32F746I(E-G)Kx" | |
}, | |
{ | |
chibiDef: "STM32F746xx", | |
mcuCode: "STM32F746IGKx", | |
stmGlob: "STM32F746I(E-G)Kx" | |
}, | |
{ | |
chibiDef: "STM32F746xx", | |
mcuCode: "STM32F746IETx", | |
stmGlob: "STM32F746IETx" | |
}, | |
{ | |
chibiDef: "STM32F746xx", | |
mcuCode: "STM32F746IGTx", | |
stmGlob: "STM32F746IGTx" | |
}, | |
{ | |
chibiDef: "STM32F746xx", | |
mcuCode: "STM32F746NEHx", | |
stmGlob: "STM32F746NEHx" | |
}, | |
{ | |
chibiDef: "STM32F746xx", | |
mcuCode: "STM32F746NGHx", | |
stmGlob: "STM32F746NGHx" | |
}, | |
{ | |
chibiDef: "STM32F746xx", | |
mcuCode: "STM32F746VEHx", | |
stmGlob: "STM32F746V(E-G)Hx" | |
}, | |
{ | |
chibiDef: "STM32F746xx", | |
mcuCode: "STM32F746VGHx", | |
stmGlob: "STM32F746V(E-G)Hx" | |
}, | |
{ | |
chibiDef: "STM32F746xx", | |
mcuCode: "STM32F746VETx", | |
stmGlob: "STM32F746VETx" | |
}, | |
{ | |
chibiDef: "STM32F746xx", | |
mcuCode: "STM32F746VGTx", | |
stmGlob: "STM32F746VGTx" | |
}, | |
{ | |
chibiDef: "STM32F746xx", | |
mcuCode: "STM32F746ZEYx", | |
stmGlob: "STM32F746Z(E-G)Yx" | |
}, | |
{ | |
chibiDef: "STM32F746xx", | |
mcuCode: "STM32F746ZGYx", | |
stmGlob: "STM32F746Z(E-G)Yx" | |
}, | |
{ | |
chibiDef: "STM32F746xx", | |
mcuCode: "STM32F746ZETx", | |
stmGlob: "STM32F746ZETx" | |
}, | |
{ | |
chibiDef: "STM32F746xx", | |
mcuCode: "STM32F746ZGTx", | |
stmGlob: "STM32F746ZGTx" | |
}, | |
{ | |
chibiDef: "STM32F756xx", | |
mcuCode: "STM32F756BGTx", | |
stmGlob: "STM32F756BGTx" | |
}, | |
{ | |
chibiDef: "STM32F756xx", | |
mcuCode: "STM32F756IGKx", | |
stmGlob: "STM32F756IGKx" | |
}, | |
{ | |
chibiDef: "STM32F756xx", | |
mcuCode: "STM32F756IGTx", | |
stmGlob: "STM32F756IGTx" | |
}, | |
{ | |
chibiDef: "STM32F756xx", | |
mcuCode: "STM32F756NGHx", | |
stmGlob: "STM32F756NGHx" | |
}, | |
{ | |
chibiDef: "STM32F756xx", | |
mcuCode: "STM32F756VGHx", | |
stmGlob: "STM32F756VGHx" | |
}, | |
{ | |
chibiDef: "STM32F756xx", | |
mcuCode: "STM32F756VGTx", | |
stmGlob: "STM32F756VGTx" | |
}, | |
{ | |
chibiDef: "STM32F756xx", | |
mcuCode: "STM32F756ZGTx", | |
stmGlob: "STM32F756ZGTx" | |
}, | |
{ | |
chibiDef: "STM32F756xx", | |
mcuCode: "STM32F756ZGYx", | |
stmGlob: "STM32F756ZGYx" | |
}, | |
{ | |
chibiDef: "STM32F767xx", | |
mcuCode: "STM32F767BGTx", | |
stmGlob: "STM32F767B(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F767xx", | |
mcuCode: "STM32F767BITx", | |
stmGlob: "STM32F767B(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F767xx", | |
mcuCode: "STM32F767IGKx", | |
stmGlob: "STM32F767I(G-I)Kx" | |
}, | |
{ | |
chibiDef: "STM32F767xx", | |
mcuCode: "STM32F767IIKx", | |
stmGlob: "STM32F767I(G-I)Kx" | |
}, | |
{ | |
chibiDef: "STM32F767xx", | |
mcuCode: "STM32F767IGTx", | |
stmGlob: "STM32F767I(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F767xx", | |
mcuCode: "STM32F767IITx", | |
stmGlob: "STM32F767I(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F767xx", | |
mcuCode: "STM32F767NGHx", | |
stmGlob: "STM32F767N(G-I)Hx" | |
}, | |
{ | |
chibiDef: "STM32F767xx", | |
mcuCode: "STM32F767NIHx", | |
stmGlob: "STM32F767N(G-I)Hx" | |
}, | |
{ | |
chibiDef: "STM32F767xx", | |
mcuCode: "STM32F767VGHx", | |
stmGlob: "STM32F767VGHx" | |
}, | |
{ | |
chibiDef: "STM32F767xx", | |
mcuCode: "STM32F767VGTx", | |
stmGlob: "STM32F767VGTx" | |
}, | |
{ | |
chibiDef: "STM32F767xx", | |
mcuCode: "STM32F767VIHx", | |
stmGlob: "STM32F767VIHx" | |
}, | |
{ | |
chibiDef: "STM32F767xx", | |
mcuCode: "STM32F767VITx", | |
stmGlob: "STM32F767VITx" | |
}, | |
{ | |
chibiDef: "STM32F767xx", | |
mcuCode: "STM32F767ZGTx", | |
stmGlob: "STM32F767ZGTx" | |
}, | |
{ | |
chibiDef: "STM32F767xx", | |
mcuCode: "STM32F767ZITx", | |
stmGlob: "STM32F767ZITx" | |
}, | |
{ | |
chibiDef: "STM32F769xx", | |
mcuCode: "STM32F769AGYx", | |
stmGlob: "STM32F769A(G-I)Yx" | |
}, | |
{ | |
chibiDef: "STM32F769xx", | |
mcuCode: "STM32F769AIYx", | |
stmGlob: "STM32F769A(G-I)Yx" | |
}, | |
{ | |
chibiDef: "STM32F769xx", | |
mcuCode: "STM32F769BGTx", | |
stmGlob: "STM32F769B(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F769xx", | |
mcuCode: "STM32F769BITx", | |
stmGlob: "STM32F769B(G-I)Tx" | |
}, | |
{ | |
chibiDef: "STM32F769xx", | |
mcuCode: "STM32F769IGTx", | |
stmGlob: "STM32F769IGTx" | |
}, | |
{ | |
chibiDef: "STM32F769xx", | |
mcuCode: "STM32F769IITx", | |
stmGlob: "STM32F769IITx" | |
}, | |
{ | |
chibiDef: "STM32F769xx", | |
mcuCode: "STM32F769NGHx", | |
stmGlob: "STM32F769NGHx" | |
}, | |
{ | |
chibiDef: "STM32F769xx", | |
mcuCode: "STM32F769NIHx", | |
stmGlob: "STM32F769NIHx" | |
}, | |
{ | |
chibiDef: "STM32F777xx", | |
mcuCode: "STM32F777BITx", | |
stmGlob: "STM32F777BITx" | |
}, | |
{ | |
chibiDef: "STM32F777xx", | |
mcuCode: "STM32F777IIKx", | |
stmGlob: "STM32F777IIKx" | |
}, | |
{ | |
chibiDef: "STM32F777xx", | |
mcuCode: "STM32F777IITx", | |
stmGlob: "STM32F777IITx" | |
}, | |
{ | |
chibiDef: "STM32F777xx", | |
mcuCode: "STM32F777NIHx", | |
stmGlob: "STM32F777NIHx" | |
}, | |
{ | |
chibiDef: "STM32F777xx", | |
mcuCode: "STM32F777VIHx", | |
stmGlob: "STM32F777VIHx" | |
}, | |
{ | |
chibiDef: "STM32F777xx", | |
mcuCode: "STM32F777VITx", | |
stmGlob: "STM32F777VITx" | |
}, | |
{ | |
chibiDef: "STM32F777xx", | |
mcuCode: "STM32F777ZITx", | |
stmGlob: "STM32F777ZITx" | |
}, | |
{ | |
chibiDef: "STM32F779xx", | |
mcuCode: "STM32F779AIYx", | |
stmGlob: "STM32F779AIYx" | |
}, | |
{ | |
chibiDef: "STM32F779xx", | |
mcuCode: "STM32F779BITx", | |
stmGlob: "STM32F779BITx" | |
}, | |
{ | |
chibiDef: "STM32F779xx", | |
mcuCode: "STM32F779IITx", | |
stmGlob: "STM32F779IITx" | |
}, | |
{ | |
chibiDef: "STM32F779xx", | |
mcuCode: "STM32F779NIHx", | |
stmGlob: "STM32F779NIHx" | |
}, | |
{ | |
chibiDef: "STM32H743xx", | |
mcuCode: "STM32H743AGIx", | |
stmGlob: "STM32H743A(G-I)Ix" | |
}, | |
{ | |
chibiDef: "STM32H743xx", | |
mcuCode: "STM32H743AIIx", | |
stmGlob: "STM32H743A(G-I)Ix" | |
}, | |
{ | |
chibiDef: "STM32H743xx", | |
mcuCode: "STM32H743BGTx", | |
stmGlob: "STM32H743BGTx" | |
}, | |
{ | |
chibiDef: "STM32H743xx", | |
mcuCode: "STM32H743BITx", | |
stmGlob: "STM32H743BITx" | |
}, | |
{ | |
chibiDef: "STM32H743xx", | |
mcuCode: "STM32H743IGKx", | |
stmGlob: "STM32H743IGKx" | |
}, | |
{ | |
chibiDef: "STM32H743xx", | |
mcuCode: "STM32H743IGTx", | |
stmGlob: "STM32H743IGTx" | |
}, | |
{ | |
chibiDef: "STM32H743xx", | |
mcuCode: "STM32H743IIKx", | |
stmGlob: "STM32H743IIKx" | |
}, | |
{ | |
chibiDef: "STM32H743xx", | |
mcuCode: "STM32H743IITx", | |
stmGlob: "STM32H743IITx" | |
}, | |
{ | |
chibiDef: "STM32H743xx", | |
mcuCode: "STM32H743VGHx", | |
stmGlob: "STM32H743V(G-I)Hx" | |
}, | |
{ | |
chibiDef: "STM32H743xx", | |
mcuCode: "STM32H743VIHx", | |
stmGlob: "STM32H743V(G-I)Hx" | |
}, | |
{ | |
chibiDef: "STM32H743xx", | |
mcuCode: "STM32H743VGTx", | |
stmGlob: "STM32H743VGTx" | |
}, | |
{ | |
chibiDef: "STM32H743xx", | |
mcuCode: "STM32H743VITx", | |
stmGlob: "STM32H743VITx" | |
}, | |
{ | |
chibiDef: "STM32H743xx", | |
mcuCode: "STM32H743XGHx", | |
stmGlob: "STM32H743XGHx" | |
}, | |
{ | |
chibiDef: "STM32H743xx", | |
mcuCode: "STM32H743XIHx", | |
stmGlob: "STM32H743XIHx" | |
}, | |
{ | |
chibiDef: "STM32H743xx", | |
mcuCode: "STM32H743ZGTx", | |
stmGlob: "STM32H743ZGTx" | |
}, | |
{ | |
chibiDef: "STM32H743xx", | |
mcuCode: "STM32H743ZITx", | |
stmGlob: "STM32H743ZITx" | |
}, | |
{ | |
chibiDef: "STM32H753xx", | |
mcuCode: "STM32H753AIIx", | |
stmGlob: "STM32H753AIIx" | |
}, | |
{ | |
chibiDef: "STM32H753xx", | |
mcuCode: "STM32H753BITx", | |
stmGlob: "STM32H753BITx" | |
}, | |
{ | |
chibiDef: "STM32H753xx", | |
mcuCode: "STM32H753IIKx", | |
stmGlob: "STM32H753IIKx" | |
}, | |
{ | |
chibiDef: "STM32H753xx", | |
mcuCode: "STM32H753IITx", | |
stmGlob: "STM32H753IITx" | |
}, | |
{ | |
chibiDef: "STM32H753xx", | |
mcuCode: "STM32H753VIHx", | |
stmGlob: "STM32H753VIHx" | |
}, | |
{ | |
chibiDef: "STM32H753xx", | |
mcuCode: "STM32H753VITx", | |
stmGlob: "STM32H753VITx" | |
}, | |
{ | |
chibiDef: "STM32H753xx", | |
mcuCode: "STM32H753XIHx", | |
stmGlob: "STM32H753XIHx" | |
}, | |
{ | |
chibiDef: "STM32H753xx", | |
mcuCode: "STM32H753ZITx", | |
stmGlob: "STM32H753ZITx" | |
}, | |
{ | |
chibiDef: "STM32L011xx", | |
mcuCode: "STM32L011D3Px", | |
stmGlob: "STM32L011D(3-4)Px" | |
}, | |
{ | |
chibiDef: "STM32L011xx", | |
mcuCode: "STM32L011D4Px", | |
stmGlob: "STM32L011D(3-4)Px" | |
}, | |
{ | |
chibiDef: "STM32L011xx", | |
mcuCode: "STM32L011E3Yx", | |
stmGlob: "STM32L011E(3-4)Yx" | |
}, | |
{ | |
chibiDef: "STM32L011xx", | |
mcuCode: "STM32L011E4Yx", | |
stmGlob: "STM32L011E(3-4)Yx" | |
}, | |
{ | |
chibiDef: "STM32L011xx", | |
mcuCode: "STM32L011F3Px", | |
stmGlob: "STM32L011F(3-4)Px" | |
}, | |
{ | |
chibiDef: "STM32L011xx", | |
mcuCode: "STM32L011F4Px", | |
stmGlob: "STM32L011F(3-4)Px" | |
}, | |
{ | |
chibiDef: "STM32L011xx", | |
mcuCode: "STM32L011F3Ux", | |
stmGlob: "STM32L011F(3-4)Ux" | |
}, | |
{ | |
chibiDef: "STM32L011xx", | |
mcuCode: "STM32L011F4Ux", | |
stmGlob: "STM32L011F(3-4)Ux" | |
}, | |
{ | |
chibiDef: "STM32L011xx", | |
mcuCode: "STM32L011G3Ux", | |
stmGlob: "STM32L011G(3-4)Ux" | |
}, | |
{ | |
chibiDef: "STM32L011xx", | |
mcuCode: "STM32L011G4Ux", | |
stmGlob: "STM32L011G(3-4)Ux" | |
}, | |
{ | |
chibiDef: "STM32L011xx", | |
mcuCode: "STM32L011K3Tx", | |
stmGlob: "STM32L011K(3-4)Tx" | |
}, | |
{ | |
chibiDef: "STM32L011xx", | |
mcuCode: "STM32L011K4Tx", | |
stmGlob: "STM32L011K(3-4)Tx" | |
}, | |
{ | |
chibiDef: "STM32L011xx", | |
mcuCode: "STM32L011K3Ux", | |
stmGlob: "STM32L011K(3-4)Ux" | |
}, | |
{ | |
chibiDef: "STM32L011xx", | |
mcuCode: "STM32L011K4Ux", | |
stmGlob: "STM32L011K(3-4)Ux" | |
}, | |
{ | |
chibiDef: "STM32L031xx", | |
mcuCode: "STM32L031C4Tx", | |
stmGlob: "STM32L031C(4-6)Tx" | |
}, | |
{ | |
chibiDef: "STM32L031xx", | |
mcuCode: "STM32L031C6Tx", | |
stmGlob: "STM32L031C(4-6)Tx" | |
}, | |
{ | |
chibiDef: "STM32L031xx", | |
mcuCode: "STM32L031C4Ux", | |
stmGlob: "STM32L031C(4-6)Ux" | |
}, | |
{ | |
chibiDef: "STM32L031xx", | |
mcuCode: "STM32L031C6Ux", | |
stmGlob: "STM32L031C(4-6)Ux" | |
}, | |
{ | |
chibiDef: "STM32L031xx", | |
mcuCode: "STM32L031E4Yx", | |
stmGlob: "STM32L031E(4-6)Yx" | |
}, | |
{ | |
chibiDef: "STM32L031xx", | |
mcuCode: "STM32L031E6Yx", | |
stmGlob: "STM32L031E(4-6)Yx" | |
}, | |
{ | |
chibiDef: "STM32L031xx", | |
mcuCode: "STM32L031F4Px", | |
stmGlob: "STM32L031F(4-6)Px" | |
}, | |
{ | |
chibiDef: "STM32L031xx", | |
mcuCode: "STM32L031F6Px", | |
stmGlob: "STM32L031F(4-6)Px" | |
}, | |
{ | |
chibiDef: "STM32L031xx", | |
mcuCode: "STM32L031G4Ux", | |
stmGlob: "STM32L031G(4-6)Ux" | |
}, | |
{ | |
chibiDef: "STM32L031xx", | |
mcuCode: "STM32L031G6Ux", | |
stmGlob: "STM32L031G(4-6)Ux" | |
}, | |
{ | |
chibiDef: "STM32L031xx", | |
mcuCode: "STM32L031G6UxS", | |
stmGlob: "STM32L031G6UxS" | |
}, | |
{ | |
chibiDef: "STM32L031xx", | |
mcuCode: "STM32L031K4Tx", | |
stmGlob: "STM32L031K(4-6)Tx" | |
}, | |
{ | |
chibiDef: "STM32L031xx", | |
mcuCode: "STM32L031K6Tx", | |
stmGlob: "STM32L031K(4-6)Tx" | |
}, | |
{ | |
chibiDef: "STM32L031xx", | |
mcuCode: "STM32L031K4Ux", | |
stmGlob: "STM32L031K(4-6)Ux" | |
}, | |
{ | |
chibiDef: "STM32L031xx", | |
mcuCode: "STM32L031K6Ux", | |
stmGlob: "STM32L031K(4-6)Ux" | |
}, | |
{ | |
chibiDef: "STM32L051xx", | |
mcuCode: "STM32L051C6Tx", | |
stmGlob: "STM32L051C(6-8)Tx" | |
}, | |
{ | |
chibiDef: "STM32L051xx", | |
mcuCode: "STM32L051C8Tx", | |
stmGlob: "STM32L051C(6-8)Tx" | |
}, | |
{ | |
chibiDef: "STM32L051xx", | |
mcuCode: "STM32L051C6Ux", | |
stmGlob: "STM32L051C(6-8)Ux" | |
}, | |
{ | |
chibiDef: "STM32L051xx", | |
mcuCode: "STM32L051C8Ux", | |
stmGlob: "STM32L051C(6-8)Ux" | |
}, | |
{ | |
chibiDef: "STM32L051xx", | |
mcuCode: "STM32L051K6Tx", | |
stmGlob: "STM32L051K(6-8)Tx" | |
}, | |
{ | |
chibiDef: "STM32L051xx", | |
mcuCode: "STM32L051K8Tx", | |
stmGlob: "STM32L051K(6-8)Tx" | |
}, | |
{ | |
chibiDef: "STM32L051xx", | |
mcuCode: "STM32L051K6Ux", | |
stmGlob: "STM32L051K(6-8)Ux" | |
}, | |
{ | |
chibiDef: "STM32L051xx", | |
mcuCode: "STM32L051K8Ux", | |
stmGlob: "STM32L051K(6-8)Ux" | |
}, | |
{ | |
chibiDef: "STM32L051xx", | |
mcuCode: "STM32L051R6Hx", | |
stmGlob: "STM32L051R(6-8)Hx" | |
}, | |
{ | |
chibiDef: "STM32L051xx", | |
mcuCode: "STM32L051R8Hx", | |
stmGlob: "STM32L051R(6-8)Hx" | |
}, | |
{ | |
chibiDef: "STM32L051xx", | |
mcuCode: "STM32L051R6Tx", | |
stmGlob: "STM32L051R(6-8)Tx" | |
}, | |
{ | |
chibiDef: "STM32L051xx", | |
mcuCode: "STM32L051R8Tx", | |
stmGlob: "STM32L051R(6-8)Tx" | |
}, | |
{ | |
chibiDef: "STM32L051xx", | |
mcuCode: "STM32L051T6Yx", | |
stmGlob: "STM32L051T(6-8)Yx" | |
}, | |
{ | |
chibiDef: "STM32L051xx", | |
mcuCode: "STM32L051T8Yx", | |
stmGlob: "STM32L051T(6-8)Yx" | |
}, | |
{ | |
chibiDef: "STM32L052xx", | |
mcuCode: "STM32L052C6Tx", | |
stmGlob: "STM32L052C(6-8)Tx" | |
}, | |
{ | |
chibiDef: "STM32L052xx", | |
mcuCode: "STM32L052C8Tx", | |
stmGlob: "STM32L052C(6-8)Tx" | |
}, | |
{ | |
chibiDef: "STM32L052xx", | |
mcuCode: "STM32L052C6Ux", | |
stmGlob: "STM32L052C(6-8)Ux" | |
}, | |
{ | |
chibiDef: "STM32L052xx", | |
mcuCode: "STM32L052C8Ux", | |
stmGlob: "STM32L052C(6-8)Ux" | |
}, | |
{ | |
chibiDef: "STM32L052xx", | |
mcuCode: "STM32L052K6Tx", | |
stmGlob: "STM32L052K(6-8)Tx" | |
}, | |
{ | |
chibiDef: "STM32L052xx", | |
mcuCode: "STM32L052K8Tx", | |
stmGlob: "STM32L052K(6-8)Tx" | |
}, | |
{ | |
chibiDef: "STM32L052xx", | |
mcuCode: "STM32L052K6Ux", | |
stmGlob: "STM32L052K(6-8)Ux" | |
}, | |
{ | |
chibiDef: "STM32L052xx", | |
mcuCode: "STM32L052K8Ux", | |
stmGlob: "STM32L052K(6-8)Ux" | |
}, | |
{ | |
chibiDef: "STM32L052xx", | |
mcuCode: "STM32L052R6Hx", | |
stmGlob: "STM32L052R(6-8)Hx" | |
}, | |
{ | |
chibiDef: "STM32L052xx", | |
mcuCode: "STM32L052R8Hx", | |
stmGlob: "STM32L052R(6-8)Hx" | |
}, | |
{ | |
chibiDef: "STM32L052xx", | |
mcuCode: "STM32L052R6Tx", | |
stmGlob: "STM32L052R(6-8)Tx" | |
}, | |
{ | |
chibiDef: "STM32L052xx", | |
mcuCode: "STM32L052R8Tx", | |
stmGlob: "STM32L052R(6-8)Tx" | |
}, | |
{ | |
chibiDef: "STM32L052xx", | |
mcuCode: "STM32L052T6Yx", | |
stmGlob: "STM32L052T(6-8)Yx" | |
}, | |
{ | |
chibiDef: "STM32L052xx", | |
mcuCode: "STM32L052T8Yx", | |
stmGlob: "STM32L052T(6-8)Yx" | |
}, | |
{ | |
chibiDef: "STM32L052xx", | |
mcuCode: "STM32L052T8Fx", | |
stmGlob: "STM32L052T8Fx" | |
}, | |
{ | |
chibiDef: "STM32L053xx", | |
mcuCode: "STM32L053C6Tx", | |
stmGlob: "STM32L053C(6-8)Tx" | |
}, | |
{ | |
chibiDef: "STM32L053xx", | |
mcuCode: "STM32L053C8Tx", | |
stmGlob: "STM32L053C(6-8)Tx" | |
}, | |
{ | |
chibiDef: "STM32L053xx", | |
mcuCode: "STM32L053C6Ux", | |
stmGlob: "STM32L053C(6-8)Ux" | |
}, | |
{ | |
chibiDef: "STM32L053xx", | |
mcuCode: "STM32L053C8Ux", | |
stmGlob: "STM32L053C(6-8)Ux" | |
}, | |
{ | |
chibiDef: "STM32L053xx", | |
mcuCode: "STM32L053R6Hx", | |
stmGlob: "STM32L053R(6-8)Hx" | |
}, | |
{ | |
chibiDef: "STM32L053xx", | |
mcuCode: "STM32L053R8Hx", | |
stmGlob: "STM32L053R(6-8)Hx" | |
}, | |
{ | |
chibiDef: "STM32L053xx", | |
mcuCode: "STM32L053R6Tx", | |
stmGlob: "STM32L053R(6-8)Tx" | |
}, | |
{ | |
chibiDef: "STM32L053xx", | |
mcuCode: "STM32L053R8Tx", | |
stmGlob: "STM32L053R(6-8)Tx" | |
}, | |
{ | |
chibiDef: "STM32L062xx", | |
mcuCode: "STM32L062C8Ux", | |
stmGlob: "STM32L062C8Ux" | |
}, | |
{ | |
chibiDef: "STM32L062xx", | |
mcuCode: "STM32L062K8Tx", | |
stmGlob: "STM32L062K8Tx" | |
}, | |
{ | |
chibiDef: "STM32L062xx", | |
mcuCode: "STM32L062K8Ux", | |
stmGlob: "STM32L062K8Ux" | |
}, | |
{ | |
chibiDef: "STM32L063xx", | |
mcuCode: "STM32L063C8Tx", | |
stmGlob: "STM32L063C8Tx" | |
}, | |
{ | |
chibiDef: "STM32L063xx", | |
mcuCode: "STM32L063C8Ux", | |
stmGlob: "STM32L063C8Ux" | |
}, | |
{ | |
chibiDef: "STM32L063xx", | |
mcuCode: "STM32L063R8Tx", | |
stmGlob: "STM32L063R8Tx" | |
}, | |
{ | |
chibiDef: "STM32L071xx", | |
mcuCode: "STM32L071C8Tx", | |
stmGlob: "STM32L071C8Tx" | |
}, | |
{ | |
chibiDef: "STM32L071xx", | |
mcuCode: "STM32L071C8Ux", | |
stmGlob: "STM32L071C8Ux" | |
}, | |
{ | |
chibiDef: "STM32L071xx", | |
mcuCode: "STM32L071CBTx", | |
stmGlob: "STM32L071C(B-Z)Tx" | |
}, | |
{ | |
chibiDef: "STM32L071xx", | |
mcuCode: "STM32L071CZTx", | |
stmGlob: "STM32L071C(B-Z)Tx" | |
}, | |
{ | |
chibiDef: "STM32L071xx", | |
mcuCode: "STM32L071CBUx", | |
stmGlob: "STM32L071C(B-Z)Ux" | |
}, | |
{ | |
chibiDef: "STM32L071xx", | |
mcuCode: "STM32L071CZUx", | |
stmGlob: "STM32L071C(B-Z)Ux" | |
}, | |
{ | |
chibiDef: "STM32L071xx", | |
mcuCode: "STM32L071CBYx", | |
stmGlob: "STM32L071C(B-Z)Yx" | |
}, | |
{ | |
chibiDef: "STM32L071xx", | |
mcuCode: "STM32L071CZYx", | |
stmGlob: "STM32L071C(B-Z)Yx" | |
}, | |
{ | |
chibiDef: "STM32L071xx", | |
mcuCode: "STM32L071K8Ux", | |
stmGlob: "STM32L071K8Ux" | |
}, | |
{ | |
chibiDef: "STM32L071xx", | |
mcuCode: "STM32L071KBTx", | |
stmGlob: "STM32L071K(B-Z)Tx" | |
}, | |
{ | |
chibiDef: "STM32L071xx", | |
mcuCode: "STM32L071KZTx", | |
stmGlob: "STM32L071K(B-Z)Tx" | |
}, | |
{ | |
chibiDef: "STM32L071xx", | |
mcuCode: "STM32L071KBUx", | |
stmGlob: "STM32L071K(B-Z)Ux" | |
}, | |
{ | |
chibiDef: "STM32L071xx", | |
mcuCode: "STM32L071KZUx", | |
stmGlob: "STM32L071K(B-Z)Ux" | |
}, | |
{ | |
chibiDef: "STM32L071xx", | |
mcuCode: "STM32L071RBHx", | |
stmGlob: "STM32L071R(B-Z)Hx" | |
}, | |
{ | |
chibiDef: "STM32L071xx", | |
mcuCode: "STM32L071RZHx", | |
stmGlob: "STM32L071R(B-Z)Hx" | |
}, | |
{ | |
chibiDef: "STM32L071xx", | |
mcuCode: "STM32L071RBTx", | |
stmGlob: "STM32L071R(B-Z)Tx" | |
}, | |
{ | |
chibiDef: "STM32L071xx", | |
mcuCode: "STM32L071RZTx", | |
stmGlob: "STM32L071R(B-Z)Tx" | |
}, | |
{ | |
chibiDef: "STM32L071xx", | |
mcuCode: "STM32L071V8Ix", | |
stmGlob: "STM32L071V8Ix" | |
}, | |
{ | |
chibiDef: "STM32L071xx", | |
mcuCode: "STM32L071V8Tx", | |
stmGlob: "STM32L071V8Tx" | |
}, | |
{ | |
chibiDef: "STM32L071xx", | |
mcuCode: "STM32L071VBIx", | |
stmGlob: "STM32L071V(B-Z)Ix" | |
}, | |
{ | |
chibiDef: "STM32L071xx", | |
mcuCode: "STM32L071VZIx", | |
stmGlob: "STM32L071V(B-Z)Ix" | |
}, | |
{ | |
chibiDef: "STM32L071xx", | |
mcuCode: "STM32L071VBTx", | |
stmGlob: "STM32L071V(B-Z)Tx" | |
}, | |
{ | |
chibiDef: "STM32L071xx", | |
mcuCode: "STM32L071VZTx", | |
stmGlob: "STM32L071V(B-Z)Tx" | |
}, | |
{ | |
chibiDef: "STM32L072xx", | |
mcuCode: "STM32L072CBTx", | |
stmGlob: "STM32L072C(B-Z)Tx" | |
}, | |
{ | |
chibiDef: "STM32L072xx", | |
mcuCode: "STM32L072CZTx", | |
stmGlob: "STM32L072C(B-Z)Tx" | |
}, | |
{ | |
chibiDef: "STM32L072xx", | |
mcuCode: "STM32L072CBUx", | |
stmGlob: "STM32L072C(B-Z)Ux" | |
}, | |
{ | |
chibiDef: "STM32L072xx", | |
mcuCode: "STM32L072CZUx", | |
stmGlob: "STM32L072C(B-Z)Ux" | |
}, | |
{ | |
chibiDef: "STM32L072xx", | |
mcuCode: "STM32L072CBYx", | |
stmGlob: "STM32L072C(B-Z)Yx" | |
}, | |
{ | |
chibiDef: "STM32L072xx", | |
mcuCode: "STM32L072CZYx", | |
stmGlob: "STM32L072C(B-Z)Yx" | |
}, | |
{ | |
chibiDef: "STM32L072xx", | |
mcuCode: "STM32L072CZEx", | |
stmGlob: "STM32L072CZEx" | |
}, | |
{ | |
chibiDef: "STM32L072xx", | |
mcuCode: "STM32L072KBTx", | |
stmGlob: "STM32L072K(B-Z)Tx" | |
}, | |
{ | |
chibiDef: "STM32L072xx", | |
mcuCode: "STM32L072KZTx", | |
stmGlob: "STM32L072K(B-Z)Tx" | |
}, | |
{ | |
chibiDef: "STM32L072xx", | |
mcuCode: "STM32L072KBUx", | |
stmGlob: "STM32L072K(B-Z)Ux" | |
}, | |
{ | |
chibiDef: "STM32L072xx", | |
mcuCode: "STM32L072KZUx", | |
stmGlob: "STM32L072K(B-Z)Ux" | |
}, | |
{ | |
chibiDef: "STM32L072xx", | |
mcuCode: "STM32L072RBHx", | |
stmGlob: "STM32L072R(B-Z)Hx" | |
}, | |
{ | |
chibiDef: "STM32L072xx", | |
mcuCode: "STM32L072RZHx", | |
stmGlob: "STM32L072R(B-Z)Hx" | |
}, | |
{ | |
chibiDef: "STM32L072xx", | |
mcuCode: "STM32L072RBIx", | |
stmGlob: "STM32L072R(B-Z)Ix" | |
}, | |
{ | |
chibiDef: "STM32L072xx", | |
mcuCode: "STM32L072RZIx", | |
stmGlob: "STM32L072R(B-Z)Ix" | |
}, | |
{ | |
chibiDef: "STM32L072xx", | |
mcuCode: "STM32L072RBTx", | |
stmGlob: "STM32L072R(B-Z)Tx" | |
}, | |
{ | |
chibiDef: "STM32L072xx", | |
mcuCode: "STM32L072RZTx", | |
stmGlob: "STM32L072R(B-Z)Tx" | |
}, | |
{ | |
chibiDef: "STM32L072xx", | |
mcuCode: "STM32L072V8Ix", | |
stmGlob: "STM32L072V8Ix" | |
}, | |
{ | |
chibiDef: "STM32L072xx", | |
mcuCode: "STM32L072V8Tx", | |
stmGlob: "STM32L072V8Tx" | |
}, | |
{ | |
chibiDef: "STM32L072xx", | |
mcuCode: "STM32L072VBIx", | |
stmGlob: "STM32L072V(B-Z)Ix" | |
}, | |
{ | |
chibiDef: "STM32L072xx", | |
mcuCode: "STM32L072VZIx", | |
stmGlob: "STM32L072V(B-Z)Ix" | |
}, | |
{ | |
chibiDef: "STM32L072xx", | |
mcuCode: "STM32L072VBTx", | |
stmGlob: "STM32L072V(B-Z)Tx" | |
}, | |
{ | |
chibiDef: "STM32L072xx", | |
mcuCode: "STM32L072VZTx", | |
stmGlob: "STM32L072V(B-Z)Tx" | |
}, | |
{ | |
chibiDef: "STM32L073xx", | |
mcuCode: "STM32L073CBTx", | |
stmGlob: "STM32L073C(B-Z)Tx" | |
}, | |
{ | |
chibiDef: "STM32L073xx", | |
mcuCode: "STM32L073CZTx", | |
stmGlob: "STM32L073C(B-Z)Tx" | |
}, | |
{ | |
chibiDef: "STM32L073xx", | |
mcuCode: "STM32L073CBUx", | |
stmGlob: "STM32L073C(B-Z)Ux" | |
}, | |
{ | |
chibiDef: "STM32L073xx", | |
mcuCode: "STM32L073CZUx", | |
stmGlob: "STM32L073C(B-Z)Ux" | |
}, | |
{ | |
chibiDef: "STM32L073xx", | |
mcuCode: "STM32L073RBHx", | |
stmGlob: "STM32L073R(B-Z)Hx" | |
}, | |
{ | |
chibiDef: "STM32L073xx", | |
mcuCode: "STM32L073RZHx", | |
stmGlob: "STM32L073R(B-Z)Hx" | |
}, | |
{ | |
chibiDef: "STM32L073xx", | |
mcuCode: "STM32L073RBTx", | |
stmGlob: "STM32L073R(B-Z)Tx" | |
}, | |
{ | |
chibiDef: "STM32L073xx", | |
mcuCode: "STM32L073RZTx", | |
stmGlob: "STM32L073R(B-Z)Tx" | |
}, | |
{ | |
chibiDef: "STM32L073xx", | |
mcuCode: "STM32L073RZIx", | |
stmGlob: "STM32L073RZIx" | |
}, | |
{ | |
chibiDef: "STM32L073xx", | |
mcuCode: "STM32L073V8Ix", | |
stmGlob: "STM32L073V8Ix" | |
}, | |
{ | |
chibiDef: "STM32L073xx", | |
mcuCode: "STM32L073V8Tx", | |
stmGlob: "STM32L073V8Tx" | |
}, | |
{ | |
chibiDef: "STM32L073xx", | |
mcuCode: "STM32L073VBIx", | |
stmGlob: "STM32L073V(B-Z)Ix" | |
}, | |
{ | |
chibiDef: "STM32L073xx", | |
mcuCode: "STM32L073VZIx", | |
stmGlob: "STM32L073V(B-Z)Ix" | |
}, | |
{ | |
chibiDef: "STM32L073xx", | |
mcuCode: "STM32L073VBTx", | |
stmGlob: "STM32L073V(B-Z)Tx" | |
}, | |
{ | |
chibiDef: "STM32L073xx", | |
mcuCode: "STM32L073VZTx", | |
stmGlob: "STM32L073V(B-Z)Tx" | |
}, | |
{ | |
chibiDef: "STM32L100xB", | |
mcuCode: "STM32L100RBTxA", | |
stmGlob: "STM32L100R(8-B)TxA" | |
}, | |
{ | |
chibiDef: "STM32L100xB", | |
mcuCode: "STM32L100RBTx", | |
stmGlob: "STM32L100R(8-B)Tx" | |
}, | |
{ | |
chibiDef: "STM32L100xC", | |
mcuCode: "STM32L100RCTx", | |
stmGlob: "STM32L100RCTx" | |
}, | |
{ | |
chibiDef: "STM32L151xB", | |
mcuCode: "STM32L151CBTxA", | |
stmGlob: "STM32L151C(6-8-B)TxA" | |
}, | |
{ | |
chibiDef: "STM32L151xB", | |
mcuCode: "STM32L151CBTx", | |
stmGlob: "STM32L151C(6-8-B)Tx" | |
}, | |
{ | |
chibiDef: "STM32L151xB", | |
mcuCode: "STM32L151CBUxA", | |
stmGlob: "STM32L151C(6-8-B)UxA" | |
}, | |
{ | |
chibiDef: "STM32L151xB", | |
mcuCode: "STM32L151CBUx", | |
stmGlob: "STM32L151C(6-8-B)Ux" | |
}, | |
{ | |
chibiDef: "STM32L151xC", | |
mcuCode: "STM32L151CCTx", | |
stmGlob: "STM32L151CCTx" | |
}, | |
{ | |
chibiDef: "STM32L151xC", | |
mcuCode: "STM32L151CCUx", | |
stmGlob: "STM32L151CCUx" | |
}, | |
{ | |
chibiDef: "STM32L151xC", | |
mcuCode: "STM32L151QCHx", | |
stmGlob: "STM32L151QCHx" | |
}, | |
{ | |
chibiDef: "STM32L151xD", | |
mcuCode: "STM32L151QDHx", | |
stmGlob: "STM32L151QDHx" | |
}, | |
{ | |
chibiDef: "STM32L151xE", | |
mcuCode: "STM32L151QEHx", | |
stmGlob: "STM32L151QEHx" | |
}, | |
{ | |
chibiDef: "STM32L151xB", | |
mcuCode: "STM32L151RBHxA", | |
stmGlob: "STM32L151R(6-8-B)HxA" | |
}, | |
{ | |
chibiDef: "STM32L151xB", | |
mcuCode: "STM32L151RBHx", | |
stmGlob: "STM32L151R(6-8-B)Hx" | |
}, | |
{ | |
chibiDef: "STM32L151xB", | |
mcuCode: "STM32L151RBTxA", | |
stmGlob: "STM32L151R(6-8-B)TxA" | |
}, | |
{ | |
chibiDef: "STM32L151xB", | |
mcuCode: "STM32L151RBTx", | |
stmGlob: "STM32L151R(6-8-B)Tx" | |
}, | |
{ | |
chibiDef: "STM32L151xC", | |
mcuCode: "STM32L151RCTxA", | |
stmGlob: "STM32L151RCTxA" | |
}, | |
{ | |
chibiDef: "STM32L151xC", | |
mcuCode: "STM32L151RCTx", | |
stmGlob: "STM32L151RCTx" | |
}, | |
{ | |
chibiDef: "STM32L151xC", | |
mcuCode: "STM32L151RCYx", | |
stmGlob: "STM32L151RCYx" | |
}, | |
{ | |
chibiDef: "STM32L151xD", | |
mcuCode: "STM32L151RDTx", | |
stmGlob: "STM32L151RDTx" | |
}, | |
{ | |
chibiDef: "STM32L151xD", | |
mcuCode: "STM32L151RDYx", | |
stmGlob: "STM32L151RDYx" | |
}, | |
{ | |
chibiDef: "STM32L151xE", | |
mcuCode: "STM32L151RETx", | |
stmGlob: "STM32L151RETx" | |
}, | |
{ | |
chibiDef: "STM32L151xC", | |
mcuCode: "STM32L151UCYx", | |
stmGlob: "STM32L151UCYx" | |
}, | |
{ | |
chibiDef: "STM32L151xB", | |
mcuCode: "STM32L151VBHxA", | |
stmGlob: "STM32L151V(8-B)HxA" | |
}, | |
{ | |
chibiDef: "STM32L151xB", | |
mcuCode: "STM32L151VBHx", | |
stmGlob: "STM32L151V(8-B)Hx" | |
}, | |
{ | |
chibiDef: "STM32L151xB", | |
mcuCode: "STM32L151VBTxA", | |
stmGlob: "STM32L151V(8-B)TxA" | |
}, | |
{ | |
chibiDef: "STM32L151xB", | |
mcuCode: "STM32L151VBTx", | |
stmGlob: "STM32L151V(8-B)Tx" | |
}, | |
{ | |
chibiDef: "STM32L151xC", | |
mcuCode: "STM32L151VCHx", | |
stmGlob: "STM32L151VCHx" | |
}, | |
{ | |
chibiDef: "STM32L151xC", | |
mcuCode: "STM32L151VCTxA", | |
stmGlob: "STM32L151VCTxA" | |
}, | |
{ | |
chibiDef: "STM32L151xC", | |
mcuCode: "STM32L151VCTx", | |
stmGlob: "STM32L151VCTx" | |
}, | |
{ | |
chibiDef: "STM32L151xD", | |
mcuCode: "STM32L151VDTx", | |
stmGlob: "STM32L151VDTx" | |
}, | |
{ | |
chibiDef: "STM32L151xD", | |
mcuCode: "STM32L151VDTxX", | |
stmGlob: "STM32L151VDTxX" | |
}, | |
{ | |
chibiDef: "STM32L151xD", | |
mcuCode: "STM32L151VDYxX", | |
stmGlob: "STM32L151VDYxX" | |
}, | |
{ | |
chibiDef: "STM32L151xE", | |
mcuCode: "STM32L151VETx", | |
stmGlob: "STM32L151VETx" | |
}, | |
{ | |
chibiDef: "STM32L151xE", | |
mcuCode: "STM32L151VEYx", | |
stmGlob: "STM32L151VEYx" | |
}, | |
{ | |
chibiDef: "STM32L151xC", | |
mcuCode: "STM32L151ZCTx", | |
stmGlob: "STM32L151ZCTx" | |
}, | |
{ | |
chibiDef: "STM32L151xD", | |
mcuCode: "STM32L151ZDTx", | |
stmGlob: "STM32L151ZDTx" | |
}, | |
{ | |
chibiDef: "STM32L151xE", | |
mcuCode: "STM32L151ZETx", | |
stmGlob: "STM32L151ZETx" | |
}, | |
{ | |
chibiDef: "STM32L152xB", | |
mcuCode: "STM32L152CBTxA", | |
stmGlob: "STM32L152C(6-8-B)TxA" | |
}, | |
{ | |
chibiDef: "STM32L152xB", | |
mcuCode: "STM32L152CBTx", | |
stmGlob: "STM32L152C(6-8-B)Tx" | |
}, | |
{ | |
chibiDef: "STM32L152xB", | |
mcuCode: "STM32L152CBUxA", | |
stmGlob: "STM32L152C(6-8-B)UxA" | |
}, | |
{ | |
chibiDef: "STM32L152xB", | |
mcuCode: "STM32L152CBUx", | |
stmGlob: "STM32L152C(6-8-B)Ux" | |
}, | |
{ | |
chibiDef: "STM32L152xC", | |
mcuCode: "STM32L152CCTx", | |
stmGlob: "STM32L152CCTx" | |
}, | |
{ | |
chibiDef: "STM32L152xC", | |
mcuCode: "STM32L152CCUx", | |
stmGlob: "STM32L152CCUx" | |
}, | |
{ | |
chibiDef: "STM32L152xC", | |
mcuCode: "STM32L152QCHx", | |
stmGlob: "STM32L152QCHx" | |
}, | |
{ | |
chibiDef: "STM32L152xD", | |
mcuCode: "STM32L152QDHx", | |
stmGlob: "STM32L152QDHx" | |
}, | |
{ | |
chibiDef: "STM32L152xB", | |
mcuCode: "STM32L152RBHxA", | |
stmGlob: "STM32L152R(6-8-B)HxA" | |
}, | |
{ | |
chibiDef: "STM32L152xB", | |
mcuCode: "STM32L152RBHx", | |
stmGlob: "STM32L152R(6-8-B)Hx" | |
}, | |
{ | |
chibiDef: "STM32L152xB", | |
mcuCode: "STM32L152RBTxA", | |
stmGlob: "STM32L152R(6-8-B)TxA" | |
}, | |
{ | |
chibiDef: "STM32L152xB", | |
mcuCode: "STM32L152RBTx", | |
stmGlob: "STM32L152R(6-8-B)Tx" | |
}, | |
{ | |
chibiDef: "STM32L152xC", | |
mcuCode: "STM32L152RCTxA", | |
stmGlob: "STM32L152RCTxA" | |
}, | |
{ | |
chibiDef: "STM32L152xC", | |
mcuCode: "STM32L152RCTx", | |
stmGlob: "STM32L152RCTx" | |
}, | |
{ | |
chibiDef: "STM32L152xD", | |
mcuCode: "STM32L152RDTx", | |
stmGlob: "STM32L152RDTx" | |
}, | |
{ | |
chibiDef: "STM32L152xD", | |
mcuCode: "STM32L152RDYx", | |
stmGlob: "STM32L152RDYx" | |
}, | |
{ | |
chibiDef: "STM32L152xC", | |
mcuCode: "STM32L152UCYx", | |
stmGlob: "STM32L152UCYx" | |
}, | |
{ | |
chibiDef: "STM32L152xB", | |
mcuCode: "STM32L152VBHxA", | |
stmGlob: "STM32L152V(8-B)HxA" | |
}, | |
{ | |
chibiDef: "STM32L152xB", | |
mcuCode: "STM32L152VBHx", | |
stmGlob: "STM32L152V(8-B)Hx" | |
}, | |
{ | |
chibiDef: "STM32L152xB", | |
mcuCode: "STM32L152VBTxA", | |
stmGlob: "STM32L152V(8-B)TxA" | |
}, | |
{ | |
chibiDef: "STM32L152xB", | |
mcuCode: "STM32L152VBTx", | |
stmGlob: "STM32L152V(8-B)Tx" | |
}, | |
{ | |
chibiDef: "STM32L152xC", | |
mcuCode: "STM32L152VCHx", | |
stmGlob: "STM32L152VCHx" | |
}, | |
{ | |
chibiDef: "STM32L152xC", | |
mcuCode: "STM32L152VCTxA", | |
stmGlob: "STM32L152VCTxA" | |
}, | |
{ | |
chibiDef: "STM32L152xC", | |
mcuCode: "STM32L152VCTx", | |
stmGlob: "STM32L152VCTx" | |
}, | |
{ | |
chibiDef: "STM32L152xD", | |
mcuCode: "STM32L152VDTx", | |
stmGlob: "STM32L152VDTx" | |
}, | |
{ | |
chibiDef: "STM32L152xD", | |
mcuCode: "STM32L152VDTxX", | |
stmGlob: "STM32L152VDTxX" | |
}, | |
{ | |
chibiDef: "STM32L152xC", | |
mcuCode: "STM32L152ZCTx", | |
stmGlob: "STM32L152ZCTx" | |
}, | |
{ | |
chibiDef: "STM32L152xD", | |
mcuCode: "STM32L152ZDTx", | |
stmGlob: "STM32L152ZDTx" | |
}, | |
{ | |
chibiDef: "STM32L162xC", | |
mcuCode: "STM32L162QCHx", | |
stmGlob: "STM32L162QCHx" | |
}, | |
{ | |
chibiDef: "STM32L162xD", | |
mcuCode: "STM32L162QDHx", | |
stmGlob: "STM32L162QDHx" | |
}, | |
{ | |
chibiDef: "STM32L162xC", | |
mcuCode: "STM32L162RCTxA", | |
stmGlob: "STM32L162RCTxA" | |
}, | |
{ | |
chibiDef: "STM32L162xC", | |
mcuCode: "STM32L162RCTx", | |
stmGlob: "STM32L162RCTx" | |
}, | |
{ | |
chibiDef: "STM32L162xD", | |
mcuCode: "STM32L162RDTx", | |
stmGlob: "STM32L162RDTx" | |
}, | |
{ | |
chibiDef: "STM32L162xD", | |
mcuCode: "STM32L162RDYx", | |
stmGlob: "STM32L162RDYx" | |
}, | |
{ | |
chibiDef: "STM32L162xE", | |
mcuCode: "STM32L162RETx", | |
stmGlob: "STM32L162RETx" | |
}, | |
{ | |
chibiDef: "STM32L162xC", | |
mcuCode: "STM32L162VCHx", | |
stmGlob: "STM32L162VCHx" | |
}, | |
{ | |
chibiDef: "STM32L162xC", | |
mcuCode: "STM32L162VCTxA", | |
stmGlob: "STM32L162VCTxA" | |
}, | |
{ | |
chibiDef: "STM32L162xC", | |
mcuCode: "STM32L162VCTx", | |
stmGlob: "STM32L162VCTx" | |
}, | |
{ | |
chibiDef: "STM32L162xD", | |
mcuCode: "STM32L162VDTx", | |
stmGlob: "STM32L162VDTx" | |
}, | |
{ | |
chibiDef: "STM32L162xD", | |
mcuCode: "STM32L162VDYxX", | |
stmGlob: "STM32L162VDYxX" | |
}, | |
{ | |
chibiDef: "STM32L162xE", | |
mcuCode: "STM32L162VETx", | |
stmGlob: "STM32L162VETx" | |
}, | |
{ | |
chibiDef: "STM32L162xE", | |
mcuCode: "STM32L162VEYx", | |
stmGlob: "STM32L162VEYx" | |
}, | |
{ | |
chibiDef: "STM32L162xC", | |
mcuCode: "STM32L162ZCTx", | |
stmGlob: "STM32L162ZCTx" | |
}, | |
{ | |
chibiDef: "STM32L162xD", | |
mcuCode: "STM32L162ZDTx", | |
stmGlob: "STM32L162ZDTx" | |
}, | |
{ | |
chibiDef: "STM32L162xE", | |
mcuCode: "STM32L162ZETx", | |
stmGlob: "STM32L162ZETx" | |
}, | |
{ | |
chibiDef: "STM32L432xx", | |
mcuCode: "STM32L432KBUx", | |
stmGlob: "STM32L432K(B-C)Ux" | |
}, | |
{ | |
chibiDef: "STM32L432xx", | |
mcuCode: "STM32L432KCUx", | |
stmGlob: "STM32L432K(B-C)Ux" | |
}, | |
{ | |
chibiDef: "STM32L443xx", | |
mcuCode: "STM32L443CCTx", | |
stmGlob: "STM32L443CCTx" | |
}, | |
{ | |
chibiDef: "STM32L443xx", | |
mcuCode: "STM32L443CCUx", | |
stmGlob: "STM32L443CCUx" | |
}, | |
{ | |
chibiDef: "STM32L443xx", | |
mcuCode: "STM32L443CCYx", | |
stmGlob: "STM32L443CCYx" | |
}, | |
{ | |
chibiDef: "STM32L443xx", | |
mcuCode: "STM32L443RCIx", | |
stmGlob: "STM32L443RCIx" | |
}, | |
{ | |
chibiDef: "STM32L443xx", | |
mcuCode: "STM32L443RCTx", | |
stmGlob: "STM32L443RCTx" | |
}, | |
{ | |
chibiDef: "STM32L443xx", | |
mcuCode: "STM32L443RCYx", | |
stmGlob: "STM32L443RCYx" | |
}, | |
{ | |
chibiDef: "STM32L443xx", | |
mcuCode: "STM32L443VCIx", | |
stmGlob: "STM32L443VCIx" | |
}, | |
{ | |
chibiDef: "STM32L443xx", | |
mcuCode: "STM32L443VCTx", | |
stmGlob: "STM32L443VCTx" | |
}, | |
{ | |
chibiDef: "STM32L476xx", | |
mcuCode: "STM32L476JEYx", | |
stmGlob: "STM32L476J(E-G)Yx" | |
}, | |
{ | |
chibiDef: "STM32L476xx", | |
mcuCode: "STM32L476JGYx", | |
stmGlob: "STM32L476J(E-G)Yx" | |
}, | |
{ | |
chibiDef: "STM32L476xx", | |
mcuCode: "STM32L476JGYxP", | |
stmGlob: "STM32L476JGYxP" | |
}, | |
{ | |
chibiDef: "STM32L476xx", | |
mcuCode: "STM32L476MEYx", | |
stmGlob: "STM32L476M(E-G)Yx" | |
}, | |
{ | |
chibiDef: "STM32L476xx", | |
mcuCode: "STM32L476MGYx", | |
stmGlob: "STM32L476M(E-G)Yx" | |
}, | |
{ | |
chibiDef: "STM32L476xx", | |
mcuCode: "STM32L476QEIx", | |
stmGlob: "STM32L476Q(E-G)Ix" | |
}, | |
{ | |
chibiDef: "STM32L476xx", | |
mcuCode: "STM32L476QGIx", | |
stmGlob: "STM32L476Q(E-G)Ix" | |
}, | |
{ | |
chibiDef: "STM32L476xx", | |
mcuCode: "STM32L476RCTx", | |
stmGlob: "STM32L476R(C-E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32L476xx", | |
mcuCode: "STM32L476RETx", | |
stmGlob: "STM32L476R(C-E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32L476xx", | |
mcuCode: "STM32L476RGTx", | |
stmGlob: "STM32L476R(C-E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32L476xx", | |
mcuCode: "STM32L476VCTx", | |
stmGlob: "STM32L476V(C-E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32L476xx", | |
mcuCode: "STM32L476VETx", | |
stmGlob: "STM32L476V(C-E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32L476xx", | |
mcuCode: "STM32L476VGTx", | |
stmGlob: "STM32L476V(C-E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32L476xx", | |
mcuCode: "STM32L476ZETx", | |
stmGlob: "STM32L476Z(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32L476xx", | |
mcuCode: "STM32L476ZGTx", | |
stmGlob: "STM32L476Z(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32L476xx", | |
mcuCode: "STM32L476ZGJx", | |
stmGlob: "STM32L476ZGJx" | |
}, | |
{ | |
chibiDef: "STM32L476xx", | |
mcuCode: "STM32L476ZGTxP", | |
stmGlob: "STM32L476ZGTxP" | |
}, | |
{ | |
chibiDef: "STM32L496xx", | |
mcuCode: "STM32L496AEIx", | |
stmGlob: "STM32L496A(E-G)Ix" | |
}, | |
{ | |
chibiDef: "STM32L496xx", | |
mcuCode: "STM32L496AGIx", | |
stmGlob: "STM32L496A(E-G)Ix" | |
}, | |
{ | |
chibiDef: "STM32L496xx", | |
mcuCode: "STM32L496AGIxP", | |
stmGlob: "STM32L496AGIxP" | |
}, | |
{ | |
chibiDef: "STM32L496xx", | |
mcuCode: "STM32L496QEIx", | |
stmGlob: "STM32L496Q(E-G)Ix" | |
}, | |
{ | |
chibiDef: "STM32L496xx", | |
mcuCode: "STM32L496QGIx", | |
stmGlob: "STM32L496Q(E-G)Ix" | |
}, | |
{ | |
chibiDef: "STM32L496xx", | |
mcuCode: "STM32L496QGIxP", | |
stmGlob: "STM32L496QGIxP" | |
}, | |
{ | |
chibiDef: "STM32L496xx", | |
mcuCode: "STM32L496RETx", | |
stmGlob: "STM32L496R(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32L496xx", | |
mcuCode: "STM32L496RGTx", | |
stmGlob: "STM32L496R(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32L496xx", | |
mcuCode: "STM32L496RGTxP", | |
stmGlob: "STM32L496RGTxP" | |
}, | |
{ | |
chibiDef: "STM32L496xx", | |
mcuCode: "STM32L496VETx", | |
stmGlob: "STM32L496V(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32L496xx", | |
mcuCode: "STM32L496VGTx", | |
stmGlob: "STM32L496V(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32L496xx", | |
mcuCode: "STM32L496VGTxP", | |
stmGlob: "STM32L496VGTxP" | |
}, | |
{ | |
chibiDef: "STM32L496xx", | |
mcuCode: "STM32L496VGYxP", | |
stmGlob: "STM32L496VGYxP" | |
}, | |
{ | |
chibiDef: "STM32L496xx", | |
mcuCode: "STM32L496VGYx", | |
stmGlob: "STM32L496VGYx" | |
}, | |
{ | |
chibiDef: "STM32L496xx", | |
mcuCode: "STM32L496WGYxP", | |
stmGlob: "STM32L496WGYxP" | |
}, | |
{ | |
chibiDef: "STM32L496xx", | |
mcuCode: "STM32L496ZETx", | |
stmGlob: "STM32L496Z(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32L496xx", | |
mcuCode: "STM32L496ZGTx", | |
stmGlob: "STM32L496Z(E-G)Tx" | |
}, | |
{ | |
chibiDef: "STM32L496xx", | |
mcuCode: "STM32L496ZGTxP", | |
stmGlob: "STM32L496ZGTxP" | |
} | |
]; | |
var supportedMcus$1 = /*#__PURE__*/Object.freeze({ | |
__proto__: null, | |
'default': supportedMcus | |
}); | |
var require$$5 = getCjsExportFromNamespace(supportedMcus$1); | |
// Generated by LiveScript 1.6.0 | |
var ref$$4, DcsTcpClient$1, Actor$2, SignalBranch$2, config$1, fs, ractiveCompile, readdirSyncRecursive, supportedMcus$2, find$2, map$2, pairsToObj$1, TemplateEngine; | |
ref$$4 = dcs, DcsTcpClient$1 = ref$$4.DcsTcpClient, Actor$2 = ref$$4.Actor, SignalBranch$2 = ref$$4.SignalBranch; | |
config$1 = config; | |
fs = fs__default['default']; | |
ractiveCompile = ractiveTemplate.ractiveCompile; | |
readdirSyncRecursive = readdirSyncRecursive_1.readdirSyncRecursive; | |
supportedMcus$2 = require$$5; | |
ref$$4 = preludeLs__default['default'], find$2 = ref$$4.find, map$2 = ref$$4.map, pairsToObj$1 = ref$$4.pairsToObj; | |
new (TemplateEngine = (function(superclass){ | |
var prototype = extend$((import$(TemplateEngine, superclass).displayName = 'TemplateEngine', TemplateEngine), superclass).prototype; | |
TemplateEngine.prototype.action = function(){ | |
var this$ = this; | |
return this.onTopic('@templating.get', function(msg){ | |
var configOrig, data, mcu, ref$, pinout, response, b, s, dir, templates; | |
configOrig = JSON.stringify(msg.data.config, null, 2); | |
data = {}; | |
for (mcu in ref$ = msg.data.config) { | |
pinout = ref$[mcu]; | |
data["mcu"] = find$2(fn$, supportedMcus$2); | |
data["pinout"] = pinout; | |
} | |
response = {}; | |
b = new SignalBranch$2; | |
if (data.mcu) { | |
s = b.add(); | |
dir = "./hw-template"; | |
templates = readdirSyncRecursive(dir); | |
this$.sendRequest("@datasheet.mcu-info", { | |
id: mcu | |
}, function(err, res){ | |
var e, pinNames, pin, ref$, pinout, ref1$, i$, len$, template, file, compiled; | |
if (e = err || res.error) { | |
return s.go(e); | |
} | |
pinNames = pairsToObj$1( | |
map$2(function(it){ | |
return [it.Position, it.Name.replace(/-.+/, '')]; | |
})( | |
map$2(function(it){ | |
return it._attributes; | |
})( | |
res.data.info.Pin))); | |
for (pin in ref$ = data.pinout) { | |
pinout = ref$[pin]; | |
pinout.pinName = pinNames[pin]; | |
pinout.ioName = pinNames[pin] + "_" + pinout.peripheral.type.toUpperCase(); | |
pinout.af = (ref1$ = pinout.peripheral.type) !== 'din' && ref1$ !== 'dout'; | |
pinout.gpioPort = "GPIO" + pinNames[pin][1].toUpperCase(); | |
} | |
/********************************************************* | |
data.pinout = { | |
pin-number: | |
peripheral: # Object | |
id: String, peripheral id, eg. "din" or "pwm-1.3", see webapps/main/stm/peripheral-defs.ls | |
name: String, Human readable name | |
stm: String, STM type, eg. GPIO | |
type: String, peripheral type, eg. din for Digital Input | |
config: # Object, Configuration regarding to @peripheral.type | |
pin-name: eg. PA1 | |
io-name: eg. PA1_PWM | |
gpio-port: eg. GPIOA | |
*********************************************************/ | |
for (i$ = 0, len$ = (ref$ = templates).length; i$ < len$; ++i$) { | |
template = ref$[i$]; | |
file = fs.readFileSync(dir + "/" + template, "utf-8"); | |
compiled = ractiveCompile(file, data); | |
response[template] = compiled; | |
} | |
response["config.json"] = configOrig; | |
return s.go(); | |
}); | |
} else { | |
response["error"] = "Unknown MCU: " + mcu; | |
} | |
return b.joined(function(){ | |
this$.log.log("Requested hardware definition."); | |
return this$.sendResponse(msg, response); | |
}); | |
function fn$(it){ | |
return it.stmGlob === mcu; | |
} | |
}); | |
}; | |
function TemplateEngine(){ | |
TemplateEngine.superclass.apply(this, arguments); | |
} | |
return TemplateEngine; | |
}(Actor$2))); | |
new DcsTcpClient$1({ | |
port: config$1.dcsPort | |
}).login({ | |
user: "templating", | |
password: "1234" | |
}); | |
function extend$(sub, sup){ | |
function fun(){} fun.prototype = (sub.superclass = sup).prototype; | |
(sub.prototype = new fun).constructor = sub; | |
if (typeof sup.extended == 'function') sup.extended(sub); | |
return sub; | |
} | |
function import$(obj, src){ | |
var own = {}.hasOwnProperty; | |
for (var key in src) if (own.call(src, key)) obj[key] = src[key]; | |
return obj; | |
} | |
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiX190ZW1wbGF0ZS5scy5qcyIsInNvdXJjZXMiOlsiLi4vLi4vc2NhZGEuanMvbGliL2Rjcy9ub2RlX21vZHVsZXMvY29sb3JzL2xpYi9zdHlsZXMuanMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL25vZGVfbW9kdWxlcy9jb2xvcnMvbGliL3N5c3RlbS9oYXMtZmxhZy5qcyIsIi4uLy4uL3NjYWRhLmpzL2xpYi9kY3Mvbm9kZV9tb2R1bGVzL2NvbG9ycy9saWIvc3lzdGVtL3N1cHBvcnRzLWNvbG9ycy5qcyIsIi4uLy4uL3NjYWRhLmpzL2xpYi9kY3Mvbm9kZV9tb2R1bGVzL2NvbG9ycy9saWIvY3VzdG9tL3RyYXAuanMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL25vZGVfbW9kdWxlcy9jb2xvcnMvbGliL2N1c3RvbS96YWxnby5qcyIsIi4uLy4uL3NjYWRhLmpzL2xpYi9kY3Mvbm9kZV9tb2R1bGVzL2NvbG9ycy9saWIvbWFwcy9hbWVyaWNhLmpzIiwiLi4vLi4vc2NhZGEuanMvbGliL2Rjcy9ub2RlX21vZHVsZXMvY29sb3JzL2xpYi9tYXBzL3plYnJhLmpzIiwiLi4vLi4vc2NhZGEuanMvbGliL2Rjcy9ub2RlX21vZHVsZXMvY29sb3JzL2xpYi9tYXBzL3JhaW5ib3cuanMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL25vZGVfbW9kdWxlcy9jb2xvcnMvbGliL21hcHMvcmFuZG9tLmpzIiwiLi4vLi4vc2NhZGEuanMvbGliL2Rjcy9ub2RlX21vZHVsZXMvY29sb3JzL2xpYi9jb2xvcnMuanMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL25vZGVfbW9kdWxlcy9jb2xvcnMvbGliL2V4dGVuZFN0cmluZ1Byb3RvdHlwZS5qcyIsIi4uLy4uL3NjYWRhLmpzL2xpYi9kY3Mvbm9kZV9tb2R1bGVzL2NvbG9ycy9saWIvaW5kZXguanMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL25vZGVfbW9kdWxlcy9tb21lbnQvbW9tZW50LmpzIiwiLi4vLi4vc2NhZGEuanMvbGliL2Rjcy9ub2RlX21vZHVsZXMvcHJlbHVkZS1scy9saWIvRnVuYy5qcyIsIi4uLy4uL3NjYWRhLmpzL2xpYi9kY3Mvbm9kZV9tb2R1bGVzL3ByZWx1ZGUtbHMvbGliL0xpc3QuanMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL25vZGVfbW9kdWxlcy9wcmVsdWRlLWxzL2xpYi9PYmouanMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL25vZGVfbW9kdWxlcy9wcmVsdWRlLWxzL2xpYi9TdHIuanMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL25vZGVfbW9kdWxlcy9wcmVsdWRlLWxzL2xpYi9OdW0uanMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL25vZGVfbW9kdWxlcy9wcmVsdWRlLWxzL2xpYi9pbmRleC5qcyIsIi4uLy4uL3NjYWRhLmpzL2xpYi9kY3MvbGliL2V2ZW50LWVtaXR0ZXIubHMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL2xpYi9sb2dnZXIubHMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL25vZGVfbW9kdWxlcy9zZXRpbW1lZGlhdGUvc2V0SW1tZWRpYXRlLmpzIiwiLi4vLi4vc2NhZGEuanMvbGliL2Rjcy9saWIvc2xlZXAubHMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL25vZGVfbW9kdWxlcy9qc29uZGlmZnBhdGNoL3NyYy9lbnZpcm9ubWVudC5qcyIsIi4uLy4uL3NjYWRhLmpzL2xpYi9kY3Mvbm9kZV9tb2R1bGVzL2pzb25kaWZmcGF0Y2gvc3JjL3Byb2Nlc3Nvci5qcyIsIi4uLy4uL3NjYWRhLmpzL2xpYi9kY3Mvbm9kZV9tb2R1bGVzL2pzb25kaWZmcGF0Y2gvc3JjL3BpcGUuanMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL25vZGVfbW9kdWxlcy9qc29uZGlmZnBhdGNoL3NyYy9jb250ZXh0cy9jb250ZXh0LmpzIiwiLi4vLi4vc2NhZGEuanMvbGliL2Rjcy9ub2RlX21vZHVsZXMvanNvbmRpZmZwYXRjaC9zcmMvY2xvbmUuanMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL25vZGVfbW9kdWxlcy9qc29uZGlmZnBhdGNoL3NyYy9jb250ZXh0cy9kaWZmLmpzIiwiLi4vLi4vc2NhZGEuanMvbGliL2Rjcy9ub2RlX21vZHVsZXMvanNvbmRpZmZwYXRjaC9zcmMvY29udGV4dHMvcGF0Y2guanMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL25vZGVfbW9kdWxlcy9qc29uZGlmZnBhdGNoL3NyYy9jb250ZXh0cy9yZXZlcnNlLmpzIiwiLi4vLi4vc2NhZGEuanMvbGliL2Rjcy9ub2RlX21vZHVsZXMvanNvbmRpZmZwYXRjaC9zcmMvZmlsdGVycy90cml2aWFsLmpzIiwiLi4vLi4vc2NhZGEuanMvbGliL2Rjcy9ub2RlX21vZHVsZXMvanNvbmRpZmZwYXRjaC9zcmMvZmlsdGVycy9uZXN0ZWQuanMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL25vZGVfbW9kdWxlcy9qc29uZGlmZnBhdGNoL3NyYy9maWx0ZXJzL2xjcy5qcyIsIi4uLy4uL3NjYWRhLmpzL2xpYi9kY3Mvbm9kZV9tb2R1bGVzL2pzb25kaWZmcGF0Y2gvc3JjL2ZpbHRlcnMvYXJyYXlzLmpzIiwiLi4vLi4vc2NhZGEuanMvbGliL2Rjcy9ub2RlX21vZHVsZXMvanNvbmRpZmZwYXRjaC9zcmMvZmlsdGVycy9kYXRlcy5qcyIsIi4uLy4uL3NjYWRhLmpzL2xpYi9kY3Mvbm9kZV9tb2R1bGVzL2pzb25kaWZmcGF0Y2gvc3JjL2ZpbHRlcnMvdGV4dHMuanMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL25vZGVfbW9kdWxlcy9qc29uZGlmZnBhdGNoL3NyYy9kaWZmcGF0Y2hlci5qcyIsIi4uLy4uL3NjYWRhLmpzL2xpYi9kY3Mvbm9kZV9tb2R1bGVzL2pzb25kaWZmcGF0Y2gvc3JjL2RhdGUtcmV2aXZlci5qcyIsIi4uLy4uL3NjYWRhLmpzL2xpYi9kY3Mvbm9kZV9tb2R1bGVzL2pzb25kaWZmcGF0Y2gvc3JjL21haW4uanMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL2xpYi9wYWNraW5nLmxzIiwiLi4vLi4vc2NhZGEuanMvbGliL2Rjcy9saWIvbWVyZ2UubHMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL2xpYi9pcC10by1oZXgubHMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL2xpYi9pbmRleC5scyIsIi4uLy4uL3NjYWRhLmpzL2xpYi9kY3MvbGliL2RlYnVnLXRvb2xzLmxzIiwiLi4vLi4vc2NhZGEuanMvbGliL2Rjcy9zcmMvdG9waWMtbWF0Y2gubHMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL3NyYy9hY3Rvci9hY3Rvci1tYW5hZ2VyLmxzIiwiLi4vLi4vc2NhZGEuanMvbGliL2Rjcy9zcmMvc2lnbmFsL2RlcHMubHMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL3NyYy9zaWduYWwvc3JjL3NpZ25hbC5scyIsIi4uLy4uL3NjYWRhLmpzL2xpYi9kY3Mvc3JjL3NpZ25hbC9zcmMvc2lnbmFsLWJyYW5jaC5scyIsIi4uLy4uL3NjYWRhLmpzL2xpYi9kY3Mvc3JjL3NpZ25hbC9pbmRleC5scyIsIi4uLy4uL3NjYWRhLmpzL2xpYi9kY3Mvc3JjL2FjdG9yL3JlcXVlc3QubHMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL3NyYy9hY3Rvci9pbmRleC5scyIsIi4uLy4uL3NjYWRhLmpzL2xpYi9kY3Mvc3JjL2ZpbHRlcnMubHMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL25vZGVfbW9kdWxlcy9pbmhlcml0cy9pbmhlcml0c19icm93c2VyLmpzIiwiLi4vLi4vc2NhZGEuanMvbGliL2Rjcy9ub2RlX21vZHVsZXMvaW5oZXJpdHMvaW5oZXJpdHMuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc2FmZS1idWZmZXIvaW5kZXguanMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL25vZGVfbW9kdWxlcy9zaGEuanMvaGFzaC5qcyIsIi4uLy4uL3NjYWRhLmpzL2xpYi9kY3Mvbm9kZV9tb2R1bGVzL3NoYS5qcy9zaGEuanMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL25vZGVfbW9kdWxlcy9zaGEuanMvc2hhMS5qcyIsIi4uLy4uL3NjYWRhLmpzL2xpYi9kY3Mvbm9kZV9tb2R1bGVzL3NoYS5qcy9zaGEyNTYuanMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL25vZGVfbW9kdWxlcy9zaGEuanMvc2hhMjI0LmpzIiwiLi4vLi4vc2NhZGEuanMvbGliL2Rjcy9ub2RlX21vZHVsZXMvc2hhLmpzL3NoYTUxMi5qcyIsIi4uLy4uL3NjYWRhLmpzL2xpYi9kY3Mvbm9kZV9tb2R1bGVzL3NoYS5qcy9zaGEzODQuanMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL25vZGVfbW9kdWxlcy9zaGEuanMvaW5kZXguanMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL3NyYy9hdXRoLWhlbHBlcnMubHMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL3NyYy9hdXRoLXJlcXVlc3QubHMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL25vZGVfbW9kdWxlcy91dWlkNC9pbmRleC5qcyIsIi4uLy4uL3NjYWRhLmpzL2xpYi9kY3Mvc3JjL2Vycm9ycy5scyIsIi4uLy4uL3NjYWRhLmpzL2xpYi9kY3Mvc3JjL2F1dGgtaGFuZGxlci5scyIsIi4uLy4uL3NjYWRhLmpzL2xpYi9kY3Mvc2VydmljZXMvZGNzLXByb3h5L2RlcHMubHMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL3NlcnZpY2VzL2Rjcy1wcm94eS9wcm90b2NvbC1hY3Rvci9oZWxwZXJzLmxzIiwiLi4vLi4vc2NhZGEuanMvbGliL2Rjcy9zZXJ2aWNlcy9kY3MtcHJveHkvcHJvdG9jb2wtYWN0b3IvY2xpZW50LmxzIiwiLi4vLi4vc2NhZGEuanMvbGliL2Rjcy9zZXJ2aWNlcy9jb3VjaC1kY3Mvbm9kZV9tb2R1bGVzL21zL2luZGV4LmpzIiwiLi4vLi4vc2NhZGEuanMvbGliL2Rjcy90cmFuc3BvcnRzL3RjcC9ub2RlX21vZHVsZXMvZGVidWcvc3JjL2RlYnVnLmpzIiwiLi4vLi4vc2NhZGEuanMvbGliL2Rjcy90cmFuc3BvcnRzL3RjcC9ub2RlX21vZHVsZXMvZGVidWcvc3JjL2Jyb3dzZXIuanMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL3RyYW5zcG9ydHMvdGNwL25vZGVfbW9kdWxlcy9kZWJ1Zy9zcmMvbm9kZS5qcyIsIi4uLy4uL3NjYWRhLmpzL2xpYi9kY3MvdHJhbnNwb3J0cy90Y3Avbm9kZV9tb2R1bGVzL2RlYnVnL3NyYy9pbmRleC5qcyIsIi4uLy4uL3NjYWRhLmpzL2xpYi9kY3MvdHJhbnNwb3J0cy90Y3Avbm9kZV9tb2R1bGVzL25vZGUtbmV0LXJlY29ubmVjdC9zcmMvaW5kZXguanMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL3RyYW5zcG9ydHMvdGNwL2luZGV4LmxzIiwiLi4vLi4vc2NhZGEuanMvbGliL2Rjcy9zZXJ2aWNlcy9kY3MtcHJveHkvdGNwL2NsaWVudC5scyIsIi4uLy4uL3NjYWRhLmpzL2xpYi9kY3MvcHJveHktYWN0b3JzL2lvLXByb3h5L2lvLXByb3h5LWNsaWVudC5scyIsIi4uLy4uL3NjYWRhLmpzL2xpYi9kY3MvbGliL2tleXBhdGgubHMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL2xpYi9tZW1vcnktbWFwLmxzIiwiLi4vLi4vc2NhZGEuanMvbGliL2Rjcy9wcm94eS1hY3RvcnMvaW8tcHJveHkvaW8tcHJveHktaGFuZGxlci5scyIsIi4uLy4uL3NjYWRhLmpzL2xpYi9kY3MvZHJpdmVycy9kcml2ZXItYWJzdHJhY3QvaW5kZXgubHMiLCIuLi8uLi9zY2FkYS5qcy9saWIvZGNzL2luZGV4LmxzIiwiLi4vLi4vY29uZmlnLmxzIiwicmFjdGl2ZS10ZW1wbGF0ZS5scyIsInJlYWRkaXItc3luYy1yZWN1cnNpdmUubHMiLCJ0ZW1wbGF0ZS5scyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuVGhlIE1JVCBMaWNlbnNlIChNSVQpXG5cbkNvcHlyaWdodCAoYykgU2luZHJlIFNvcmh1cyA8c2luZHJlc29yaHVzQGdtYWlsLmNvbT4gKHNpbmRyZXNvcmh1cy5jb20pXG5cblBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHlcbm9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlIFwiU29mdHdhcmVcIiksIHRvIGRlYWxcbmluIHRoZSBTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dCBsaW1pdGF0aW9uIHRoZSByaWdodHNcbnRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGxcbmNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpc1xuZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczpcblxuVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW5cbmFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlIFNvZnR3YXJlLlxuXG5USEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SXG5JTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSxcbkZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRVxuQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUlxuTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSxcbk9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU5cblRIRSBTT0ZUV0FSRS5cblxuKi9cblxudmFyIHN0eWxlcyA9IHt9O1xubW9kdWxlWydleHBvcnRzJ10gPSBzdHlsZXM7XG5cbnZhciBjb2RlcyA9IHtcbiAgcmVzZXQ6IFswLCAwXSxcblxuICBib2xkOiBbMSwgMjJdLFxuICBkaW06IFsyLCAyMl0sXG4gIGl0YWxpYzogWzMsIDIzXSxcbiAgdW5kZXJsaW5lOiBbNCwgMjRdLFxuICBpbnZlcnNlOiBbNywgMjddLFxuICBoaWRkZW46IFs4LCAyOF0sXG4gIHN0cmlrZXRocm91Z2g6IFs5LCAyOV0sXG5cbiAgYmxhY2s6IFszMCwgMzldLFxuICByZWQ6IFszMSwgMzldLFxuICBncmVlbjogWzMyLCAzOV0sXG4gIHllbGxvdzogWzMzLCAzOV0sXG4gIGJsdWU6IFszNCwgMzldLFxuICBtYWdlbnRhOiBbMzUsIDM5XSxcbiAgY3lhbjogWzM2LCAzOV0sXG4gIHdoaXRlOiBbMzcsIDM5XSxcbiAgZ3JheTogWzkwLCAzOV0sXG4gIGdyZXk6IFs5MCwgMzldLFxuXG4gIGJyaWdodFJlZDogWzkxLCAzOV0sXG4gIGJyaWdodEdyZWVuOiBbOTIsIDM5XSxcbiAgYnJpZ2h0WWVsbG93OiBbOTMsIDM5XSxcbiAgYnJpZ2h0Qmx1ZTogWzk0LCAzOV0sXG4gIGJyaWdodE1hZ2VudGE6IFs5NSwgMzldLFxuICBicmlnaHRDeWFuOiBbOTYsIDM5XSxcbiAgYnJpZ2h0V2hpdGU6IFs5NywgMzldLFxuXG4gIGJnQmxhY2s6IFs0MCwgNDldLFxuICBiZ1JlZDogWzQxLCA0OV0sXG4gIGJnR3JlZW46IFs0MiwgNDldLFxuICBiZ1llbGxvdzogWzQzLCA0OV0sXG4gIGJnQmx1ZTogWzQ0LCA0OV0sXG4gIGJnTWFnZW50YTogWzQ1LCA0OV0sXG4gIGJnQ3lhbjogWzQ2LCA0OV0sXG4gIGJnV2hpdGU6IFs0NywgNDldLFxuICBiZ0dyYXk6IFsxMDAsIDQ5XSxcbiAgYmdHcmV5OiBbMTAwLCA0OV0sXG5cbiAgYmdCcmlnaHRSZWQ6IFsxMDEsIDQ5XSxcbiAgYmdCcmlnaHRHcmVlbjogWzEwMiwgNDldLFxuICBiZ0JyaWdodFllbGxvdzogWzEwMywgNDldLFxuICBiZ0JyaWdodEJsdWU6IFsxMDQsIDQ5XSxcbiAgYmdCcmlnaHRNYWdlbnRhOiBbMTA1LCA0OV0sXG4gIGJnQnJpZ2h0Q3lhbjogWzEwNiwgNDldLFxuICBiZ0JyaWdodFdoaXRlOiBbMTA3LCA0OV0sXG5cbiAgLy8gbGVnYWN5IHN0eWxlcyBmb3IgY29sb3JzIHByZSB2MS4wLjBcbiAgYmxhY2tCRzogWzQwLCA0OV0sXG4gIHJlZEJHOiBbNDEsIDQ5XSxcbiAgZ3JlZW5CRzogWzQyLCA0OV0sXG4gIHllbGxvd0JHOiBbNDMsIDQ5XSxcbiAgYmx1ZUJHOiBbNDQsIDQ5XSxcbiAgbWFnZW50YUJHOiBbNDUsIDQ5XSxcbiAgY3lhbkJHOiBbNDYsIDQ5XSxcbiAgd2hpdGVCRzogWzQ3LCA0OV0sXG5cbn07XG5cbk9iamVjdC5rZXlzKGNvZGVzKS5mb3JFYWNoKGZ1bmN0aW9uKGtleSkge1xuICB2YXIgdmFsID0gY29kZXNba2V5XTtcbiAgdmFyIHN0eWxlID0gc3R5bGVzW2tleV0gPSBbXTtcbiAgc3R5bGUub3BlbiA9ICdcXHUwMDFiWycgKyB2YWxbMF0gKyAnbSc7XG4gIHN0eWxlLmNsb3NlID0gJ1xcdTAwMWJbJyArIHZhbFsxXSArICdtJztcbn0pO1xuIiwiLypcbk1JVCBMaWNlbnNlXG5cbkNvcHlyaWdodCAoYykgU2luZHJlIFNvcmh1cyA8c2luZHJlc29yaHVzQGdtYWlsLmNvbT4gKHNpbmRyZXNvcmh1cy5jb20pXG5cblBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHkgb2ZcbnRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlIFwiU29mdHdhcmVcIiksIHRvIGRlYWwgaW5cbnRoZSBTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dCBsaW1pdGF0aW9uIHRoZSByaWdodHMgdG9cbnVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGwgY29waWVzXG5vZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpcyBmdXJuaXNoZWQgdG8gZG9cbnNvLCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczpcblxuVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxsXG5jb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlIFNvZnR3YXJlLlxuXG5USEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SXG5JTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSxcbkZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRVxuQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUlxuTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSxcbk9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU4gVEhFXG5TT0ZUV0FSRS5cbiovXG5cbid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbihmbGFnLCBhcmd2KSB7XG4gIGFyZ3YgPSBhcmd2IHx8IHByb2Nlc3MuYXJndjtcblxuICB2YXIgdGVybWluYXRvclBvcyA9IGFyZ3YuaW5kZXhPZignLS0nKTtcbiAgdmFyIHByZWZpeCA9IC9eLXsxLDJ9Ly50ZXN0KGZsYWcpID8gJycgOiAnLS0nO1xuICB2YXIgcG9zID0gYXJndi5pbmRleE9mKHByZWZpeCArIGZsYWcpO1xuXG4gIHJldHVybiBwb3MgIT09IC0xICYmICh0ZXJtaW5hdG9yUG9zID09PSAtMSA/IHRydWUgOiBwb3MgPCB0ZXJtaW5hdG9yUG9zKTtcbn07XG4iLCIvKlxuVGhlIE1JVCBMaWNlbnNlIChNSVQpXG5cbkNvcHlyaWdodCAoYykgU2luZHJlIFNvcmh1cyA8c2luZHJlc29yaHVzQGdtYWlsLmNvbT4gKHNpbmRyZXNvcmh1cy5jb20pXG5cblBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHlcbm9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlIFwiU29mdHdhcmVcIiksIHRvIGRlYWxcbmluIHRoZSBTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dCBsaW1pdGF0aW9uIHRoZSByaWdodHNcbnRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGxcbmNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpc1xuZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczpcblxuVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW5cbmFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlIFNvZnR3YXJlLlxuXG5USEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SXG5JTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSxcbkZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRVxuQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUlxuTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSxcbk9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU5cblRIRSBTT0ZUV0FSRS5cblxuKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgb3MgPSByZXF1aXJlKCdvcycpO1xudmFyIGhhc0ZsYWcgPSByZXF1aXJlKCcuL2hhcy1mbGFnLmpzJyk7XG5cbnZhciBlbnYgPSBwcm9jZXNzLmVudjtcblxudmFyIGZvcmNlQ29sb3IgPSB2b2lkIDA7XG5pZiAoaGFzRmxhZygnbm8tY29sb3InKSB8fCBoYXNGbGFnKCduby1jb2xvcnMnKSB8fCBoYXNGbGFnKCdjb2xvcj1mYWxzZScpKSB7XG4gIGZvcmNlQ29sb3IgPSBmYWxzZTtcbn0gZWxzZSBpZiAoaGFzRmxhZygnY29sb3InKSB8fCBoYXNGbGFnKCdjb2xvcnMnKSB8fCBoYXNGbGFnKCdjb2xvcj10cnVlJylcbiAgICAgICAgICAgfHwgaGFzRmxhZygnY29sb3I9YWx3YXlzJykpIHtcbiAgZm9yY2VDb2xvciA9IHRydWU7XG59XG5pZiAoJ0ZPUkNFX0NPTE9SJyBpbiBlbnYpIHtcbiAgZm9yY2VDb2xvciA9IGVudi5GT1JDRV9DT0xPUi5sZW5ndGggPT09IDBcbiAgICB8fCBwYXJzZUludChlbnYuRk9SQ0VfQ09MT1IsIDEwKSAhPT0gMDtcbn1cblxuZnVuY3Rpb24gdHJhbnNsYXRlTGV2ZWwobGV2ZWwpIHtcbiAgaWYgKGxldmVsID09PSAwKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgcmV0dXJuIHtcbiAgICBsZXZlbDogbGV2ZWwsXG4gICAgaGFzQmFzaWM6IHRydWUsXG4gICAgaGFzMjU2OiBsZXZlbCA+PSAyLFxuICAgIGhhczE2bTogbGV2ZWwgPj0gMyxcbiAgfTtcbn1cblxuZnVuY3Rpb24gc3VwcG9ydHNDb2xvcihzdHJlYW0pIHtcbiAgaWYgKGZvcmNlQ29sb3IgPT09IGZhbHNlKSB7XG4gICAgcmV0dXJuIDA7XG4gIH1cblxuICBpZiAoaGFzRmxhZygnY29sb3I9MTZtJykgfHwgaGFzRmxhZygnY29sb3I9ZnVsbCcpXG4gICAgICB8fCBoYXNGbGFnKCdjb2xvcj10cnVlY29sb3InKSkge1xuICAgIHJldHVybiAzO1xuICB9XG5cbiAgaWYgKGhhc0ZsYWcoJ2NvbG9yPTI1NicpKSB7XG4gICAgcmV0dXJuIDI7XG4gIH1cblxuICBpZiAoc3RyZWFtICYmICFzdHJlYW0uaXNUVFkgJiYgZm9yY2VDb2xvciAhPT0gdHJ1ZSkge1xuICAgIHJldHVybiAwO1xuICB9XG5cbiAgdmFyIG1pbiA9IGZvcmNlQ29sb3IgPyAxIDogMDtcblxuICBpZiAocHJvY2Vzcy5wbGF0Zm9ybSA9PT0gJ3dpbjMyJykge1xuICAgIC8vIE5vZGUuanMgNy41LjAgaXMgdGhlIGZpcnN0IHZlcnNpb24gb2YgTm9kZS5qcyB0byBpbmNsdWRlIGEgcGF0Y2ggdG9cbiAgICAvLyBsaWJ1diB0aGF0IGVuYWJsZXMgMjU2IGNvbG9yIG91dHB1dCBvbiBXaW5kb3dzLiBBbnl0aGluZyBlYXJsaWVyIGFuZCBpdFxuICAgIC8vIHdvbid0IHdvcmsuIEhvd2V2ZXIsIGhlcmUgd2UgdGFyZ2V0IE5vZGUuanMgOCBhdCBtaW5pbXVtIGFzIGl0IGlzIGFuIExUU1xuICAgIC8vIHJlbGVhc2UsIGFuZCBOb2RlLmpzIDcgaXMgbm90LiBXaW5kb3dzIDEwIGJ1aWxkIDEwNTg2IGlzIHRoZSBmaXJzdFxuICAgIC8vIFdpbmRvd3MgcmVsZWFzZSB0aGF0IHN1cHBvcnRzIDI1NiBjb2xvcnMuIFdpbmRvd3MgMTAgYnVpbGQgMTQ5MzEgaXMgdGhlXG4gICAgLy8gZmlyc3QgcmVsZWFzZSB0aGF0IHN1cHBvcnRzIDE2bS9UcnVlQ29sb3IuXG4gICAgdmFyIG9zUmVsZWFzZSA9IG9zLnJlbGVhc2UoKS5zcGxpdCgnLicpO1xuICAgIGlmIChOdW1iZXIocHJvY2Vzcy52ZXJzaW9ucy5ub2RlLnNwbGl0KCcuJylbMF0pID49IDhcbiAgICAgICAgJiYgTnVtYmVyKG9zUmVsZWFzZVswXSkgPj0gMTAgJiYgTnVtYmVyKG9zUmVsZWFzZVsyXSkgPj0gMTA1ODYpIHtcbiAgICAgIHJldHVybiBOdW1iZXIob3NSZWxlYXNlWzJdKSA+PSAxNDkzMSA/IDMgOiAyO1xuICAgIH1cblxuICAgIHJldHVybiAxO1xuICB9XG5cbiAgaWYgKCdDSScgaW4gZW52KSB7XG4gICAgaWYgKFsnVFJBVklTJywgJ0NJUkNMRUNJJywgJ0FQUFZFWU9SJywgJ0dJVExBQl9DSSddLnNvbWUoZnVuY3Rpb24oc2lnbikge1xuICAgICAgcmV0dXJuIHNpZ24gaW4gZW52O1xuICAgIH0pIHx8IGVudi5DSV9OQU1FID09PSAnY29kZXNoaXAnKSB7XG4gICAgICByZXR1cm4gMTtcbiAgICB9XG5cbiAgICByZXR1cm4gbWluO1xuICB9XG5cbiAgaWYgKCdURUFNQ0lUWV9WRVJTSU9OJyBpbiBlbnYpIHtcbiAgICByZXR1cm4gKC9eKDlcXC4oMCpbMS05XVxcZCopXFwufFxcZHsyLH1cXC4pLy50ZXN0KGVudi5URUFNQ0lUWV9WRVJTSU9OKSA/IDEgOiAwXG4gICAgKTtcbiAgfVxuXG4gIGlmICgnVEVSTV9QUk9HUkFNJyBpbiBlbnYpIHtcbiAgICB2YXIgdmVyc2lvbiA9IHBhcnNlSW50KChlbnYuVEVSTV9QUk9HUkFNX1ZFUlNJT04gfHwgJycpLnNwbGl0KCcuJylbMF0sIDEwKTtcblxuICAgIHN3aXRjaCAoZW52LlRFUk1fUFJPR1JBTSkge1xuICAgICAgY2FzZSAnaVRlcm0uYXBwJzpcbiAgICAgICAgcmV0dXJuIHZlcnNpb24gPj0gMyA/IDMgOiAyO1xuICAgICAgY2FzZSAnSHlwZXInOlxuICAgICAgICByZXR1cm4gMztcbiAgICAgIGNhc2UgJ0FwcGxlX1Rlcm1pbmFsJzpcbiAgICAgICAgcmV0dXJuIDI7XG4gICAgICAvLyBObyBkZWZhdWx0XG4gICAgfVxuICB9XG5cbiAgaWYgKC8tMjU2KGNvbG9yKT8kL2kudGVzdChlbnYuVEVSTSkpIHtcbiAgICByZXR1cm4gMjtcbiAgfVxuXG4gIGlmICgvXnNjcmVlbnxeeHRlcm18XnZ0MTAwfF5yeHZ0fGNvbG9yfGFuc2l8Y3lnd2lufGxpbnV4L2kudGVzdChlbnYuVEVSTSkpIHtcbiAgICByZXR1cm4gMTtcbiAgfVxuXG4gIGlmICgnQ09MT1JURVJNJyBpbiBlbnYpIHtcbiAgICByZXR1cm4gMTtcbiAgfVxuXG4gIGlmIChlbnYuVEVSTSA9PT0gJ2R1bWInKSB7XG4gICAgcmV0dXJuIG1pbjtcbiAgfVxuXG4gIHJldHVybiBtaW47XG59XG5cbmZ1bmN0aW9uIGdldFN1cHBvcnRMZXZlbChzdHJlYW0pIHtcbiAgdmFyIGxldmVsID0gc3VwcG9ydHNDb2xvcihzdHJlYW0pO1xuICByZXR1cm4gdHJhbnNsYXRlTGV2ZWwobGV2ZWwpO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgc3VwcG9ydHNDb2xvcjogZ2V0U3VwcG9ydExldmVsLFxuICBzdGRvdXQ6IGdldFN1cHBvcnRMZXZlbChwcm9jZXNzLnN0ZG91dCksXG4gIHN0ZGVycjogZ2V0U3VwcG9ydExldmVsKHByb2Nlc3Muc3RkZXJyKSxcbn07XG4iLCJtb2R1bGVbJ2V4cG9ydHMnXSA9IGZ1bmN0aW9uIHJ1blRoZVRyYXAodGV4dCwgb3B0aW9ucykge1xuICB2YXIgcmVzdWx0ID0gJyc7XG4gIHRleHQgPSB0ZXh0IHx8ICdSdW4gdGhlIHRyYXAsIGRyb3AgdGhlIGJhc3MnO1xuICB0ZXh0ID0gdGV4dC5zcGxpdCgnJyk7XG4gIHZhciB0cmFwID0ge1xuICAgIGE6IFsnXFx1MDA0MCcsICdcXHUwMTA0JywgJ1xcdTAyM2EnLCAnXFx1MDI0NScsICdcXHUwMzk0JywgJ1xcdTAzOWInLCAnXFx1MDQxNCddLFxuICAgIGI6IFsnXFx1MDBkZicsICdcXHUwMTgxJywgJ1xcdTAyNDMnLCAnXFx1MDI2ZScsICdcXHUwM2IyJywgJ1xcdTBlM2YnXSxcbiAgICBjOiBbJ1xcdTAwYTknLCAnXFx1MDIzYicsICdcXHUwM2ZlJ10sXG4gICAgZDogWydcXHUwMGQwJywgJ1xcdTAxOGEnLCAnXFx1MDUwMCcsICdcXHUwNTAxJywgJ1xcdTA1MDInLCAnXFx1MDUwMyddLFxuICAgIGU6IFsnXFx1MDBjYicsICdcXHUwMTE1JywgJ1xcdTAxOGUnLCAnXFx1MDI1OCcsICdcXHUwM2EzJywgJ1xcdTAzYmUnLCAnXFx1MDRiYycsXG4gICAgICAnXFx1MGE2YyddLFxuICAgIGY6IFsnXFx1MDRmYSddLFxuICAgIGc6IFsnXFx1MDI2MiddLFxuICAgIGg6IFsnXFx1MDEyNicsICdcXHUwMTk1JywgJ1xcdTA0YTInLCAnXFx1MDRiYScsICdcXHUwNGM3JywgJ1xcdTA1MGEnXSxcbiAgICBpOiBbJ1xcdTBmMGYnXSxcbiAgICBqOiBbJ1xcdTAxMzQnXSxcbiAgICBrOiBbJ1xcdTAxMzgnLCAnXFx1MDRhMCcsICdcXHUwNGMzJywgJ1xcdTA1MWUnXSxcbiAgICBsOiBbJ1xcdTAxMzknXSxcbiAgICBtOiBbJ1xcdTAyOGQnLCAnXFx1MDRjZCcsICdcXHUwNGNlJywgJ1xcdTA1MjAnLCAnXFx1MDUyMScsICdcXHUwZDY5J10sXG4gICAgbjogWydcXHUwMGQxJywgJ1xcdTAxNGInLCAnXFx1MDE5ZCcsICdcXHUwMzc2JywgJ1xcdTAzYTAnLCAnXFx1MDQ4YSddLFxuICAgIG86IFsnXFx1MDBkOCcsICdcXHUwMGY1JywgJ1xcdTAwZjgnLCAnXFx1MDFmZScsICdcXHUwMjk4JywgJ1xcdTA0N2EnLCAnXFx1MDVkZCcsXG4gICAgICAnXFx1MDZkZCcsICdcXHUwZTRmJ10sXG4gICAgcDogWydcXHUwMWY3JywgJ1xcdTA0OGUnXSxcbiAgICBxOiBbJ1xcdTA5Y2QnXSxcbiAgICByOiBbJ1xcdTAwYWUnLCAnXFx1MDFhNicsICdcXHUwMjEwJywgJ1xcdTAyNGMnLCAnXFx1MDI4MCcsICdcXHUwNDJmJ10sXG4gICAgczogWydcXHUwMGE3JywgJ1xcdTAzZGUnLCAnXFx1MDNkZicsICdcXHUwM2U4J10sXG4gICAgdDogWydcXHUwMTQxJywgJ1xcdTAxNjYnLCAnXFx1MDM3MyddLFxuICAgIHU6IFsnXFx1MDFiMScsICdcXHUwNTRkJ10sXG4gICAgdjogWydcXHUwNWQ4J10sXG4gICAgdzogWydcXHUwNDI4JywgJ1xcdTA0NjAnLCAnXFx1MDQ3YycsICdcXHUwZDcwJ10sXG4gICAgeDogWydcXHUwNGIyJywgJ1xcdTA0ZmUnLCAnXFx1MDRmYycsICdcXHUwNGZkJ10sXG4gICAgeTogWydcXHUwMGE1JywgJ1xcdTA0YjAnLCAnXFx1MDRjYiddLFxuICAgIHo6IFsnXFx1MDFiNScsICdcXHUwMjQwJ10sXG4gIH07XG4gIHRleHQuZm9yRWFjaChmdW5jdGlvbihjKSB7XG4gICAgYyA9IGMudG9Mb3dlckNhc2UoKTtcbiAgICB2YXIgY2hhcnMgPSB0cmFwW2NdIHx8IFsnICddO1xuICAgIHZhciByYW5kID0gTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogY2hhcnMubGVuZ3RoKTtcbiAgICBpZiAodHlwZW9mIHRyYXBbY10gIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICByZXN1bHQgKz0gdHJhcFtjXVtyYW5kXTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmVzdWx0ICs9IGM7XG4gICAgfVxuICB9KTtcbiAgcmV0dXJuIHJlc3VsdDtcbn07XG4iLCIvLyBwbGVhc2Ugbm9cbm1vZHVsZVsnZXhwb3J0cyddID0gZnVuY3Rpb24gemFsZ28odGV4dCwgb3B0aW9ucykge1xuICB0ZXh0ID0gdGV4dCB8fCAnICAgaGUgaXMgaGVyZSAgICc7XG4gIHZhciBzb3VsID0ge1xuICAgICd1cCc6IFtcbiAgICAgICfMjScsICfMjicsICfMhCcsICfMhScsXG4gICAgICAnzL8nLCAnzJEnLCAnzIYnLCAnzJAnLFxuICAgICAgJ82SJywgJ82XJywgJ82RJywgJ8yHJyxcbiAgICAgICfMiCcsICfMiicsICfNgicsICfMkycsXG4gICAgICAnzIgnLCAnzYonLCAnzYsnLCAnzYwnLFxuICAgICAgJ8yDJywgJ8yCJywgJ8yMJywgJ82QJyxcbiAgICAgICfMgCcsICfMgScsICfMiycsICfMjycsXG4gICAgICAnzJInLCAnzJMnLCAnzJQnLCAnzL0nLFxuICAgICAgJ8yJJywgJ82jJywgJ82kJywgJ82lJyxcbiAgICAgICfNpicsICfNpycsICfNqCcsICfNqScsXG4gICAgICAnzaonLCAnzasnLCAnzawnLCAnza0nLFxuICAgICAgJ82uJywgJ82vJywgJ8y+JywgJ82bJyxcbiAgICAgICfNhicsICfMmicsXG4gICAgXSxcbiAgICAnZG93bic6IFtcbiAgICAgICfMlicsICfMlycsICfMmCcsICfMmScsXG4gICAgICAnzJwnLCAnzJ0nLCAnzJ4nLCAnzJ8nLFxuICAgICAgJ8ygJywgJ8ykJywgJ8ylJywgJ8ymJyxcbiAgICAgICfMqScsICfMqicsICfMqycsICfMrCcsXG4gICAgICAnzK0nLCAnzK4nLCAnzK8nLCAnzLAnLFxuICAgICAgJ8yxJywgJ8yyJywgJ8yzJywgJ8y5JyxcbiAgICAgICfMuicsICfMuycsICfMvCcsICfNhScsXG4gICAgICAnzYcnLCAnzYgnLCAnzYknLCAnzY0nLFxuICAgICAgJ82OJywgJ82TJywgJ82UJywgJ82VJyxcbiAgICAgICfNlicsICfNmScsICfNmicsICfMoycsXG4gICAgXSxcbiAgICAnbWlkJzogW1xuICAgICAgJ8yVJywgJ8ybJywgJ8yAJywgJ8yBJyxcbiAgICAgICfNmCcsICfMoScsICfMoicsICfMpycsXG4gICAgICAnzKgnLCAnzLQnLCAnzLUnLCAnzLYnLFxuICAgICAgJ82cJywgJ82dJywgJ82eJyxcbiAgICAgICfNnycsICfNoCcsICfNoicsICfMuCcsXG4gICAgICAnzLcnLCAnzaEnLCAnINKJJyxcbiAgICBdLFxuICB9O1xuICB2YXIgYWxsID0gW10uY29uY2F0KHNvdWwudXAsIHNvdWwuZG93biwgc291bC5taWQpO1xuXG4gIGZ1bmN0aW9uIHJhbmRvbU51bWJlcihyYW5nZSkge1xuICAgIHZhciByID0gTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogcmFuZ2UpO1xuICAgIHJldHVybiByO1xuICB9XG5cbiAgZnVuY3Rpb24gaXNDaGFyKGNoYXJhY3Rlcikge1xuICAgIHZhciBib29sID0gZmFsc2U7XG4gICAgYWxsLmZpbHRlcihmdW5jdGlvbihpKSB7XG4gICAgICBib29sID0gKGkgPT09IGNoYXJhY3Rlcik7XG4gICAgfSk7XG4gICAgcmV0dXJuIGJvb2w7XG4gIH1cblxuXG4gIGZ1bmN0aW9uIGhlQ29tZXModGV4dCwgb3B0aW9ucykge1xuICAgIHZhciByZXN1bHQgPSAnJztcbiAgICB2YXIgY291bnRzO1xuICAgIHZhciBsO1xuICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgIG9wdGlvbnNbJ3VwJ10gPVxuICAgICAgdHlwZW9mIG9wdGlvbnNbJ3VwJ10gIT09ICd1bmRlZmluZWQnID8gb3B0aW9uc1sndXAnXSA6IHRydWU7XG4gICAgb3B0aW9uc1snbWlkJ10gPVxuICAgICAgdHlwZW9mIG9wdGlvbnNbJ21pZCddICE9PSAndW5kZWZpbmVkJyA/IG9wdGlvbnNbJ21pZCddIDogdHJ1ZTtcbiAgICBvcHRpb25zWydkb3duJ10gPVxuICAgICAgdHlwZW9mIG9wdGlvbnNbJ2Rvd24nXSAhPT0gJ3VuZGVmaW5lZCcgPyBvcHRpb25zWydkb3duJ10gOiB0cnVlO1xuICAgIG9wdGlvbnNbJ3NpemUnXSA9XG4gICAgICB0eXBlb2Ygb3B0aW9uc1snc2l6ZSddICE9PSAndW5kZWZpbmVkJyA/IG9wdGlvbnNbJ3NpemUnXSA6ICdtYXhpJztcbiAgICB0ZXh0ID0gdGV4dC5zcGxpdCgnJyk7XG4gICAgZm9yIChsIGluIHRleHQpIHtcbiAgICAgIGlmIChpc0NoYXIobCkpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICByZXN1bHQgPSByZXN1bHQgKyB0ZXh0W2xdO1xuICAgICAgY291bnRzID0geyd1cCc6IDAsICdkb3duJzogMCwgJ21pZCc6IDB9O1xuICAgICAgc3dpdGNoIChvcHRpb25zLnNpemUpIHtcbiAgICAgICAgY2FzZSAnbWluaSc6XG4gICAgICAgICAgY291bnRzLnVwID0gcmFuZG9tTnVtYmVyKDgpO1xuICAgICAgICAgIGNvdW50cy5taWQgPSByYW5kb21OdW1iZXIoMik7XG4gICAgICAgICAgY291bnRzLmRvd24gPSByYW5kb21OdW1iZXIoOCk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgJ21heGknOlxuICAgICAgICAgIGNvdW50cy51cCA9IHJhbmRvbU51bWJlcigxNikgKyAzO1xuICAgICAgICAgIGNvdW50cy5taWQgPSByYW5kb21OdW1iZXIoNCkgKyAxO1xuICAgICAgICAgIGNvdW50cy5kb3duID0gcmFuZG9tTnVtYmVyKDY0KSArIDM7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgY291bnRzLnVwID0gcmFuZG9tTnVtYmVyKDgpICsgMTtcbiAgICAgICAgICBjb3VudHMubWlkID0gcmFuZG9tTnVtYmVyKDYpIC8gMjtcbiAgICAgICAgICBjb3VudHMuZG93biA9IHJhbmRvbU51bWJlcig4KSArIDE7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICB9XG5cbiAgICAgIHZhciBhcnIgPSBbJ3VwJywgJ21pZCcsICdkb3duJ107XG4gICAgICBmb3IgKHZhciBkIGluIGFycikge1xuICAgICAgICB2YXIgaW5kZXggPSBhcnJbZF07XG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDw9IGNvdW50c1tpbmRleF07IGkrKykge1xuICAgICAgICAgIGlmIChvcHRpb25zW2luZGV4XSkge1xuICAgICAgICAgICAgcmVzdWx0ID0gcmVzdWx0ICsgc291bFtpbmRleF1bcmFuZG9tTnVtYmVyKHNvdWxbaW5kZXhdLmxlbmd0aCldO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG4gIC8vIGRvbid0IHN1bW1vbiBoaW1cbiAgcmV0dXJuIGhlQ29tZXModGV4dCwgb3B0aW9ucyk7XG59O1xuXG4iLCJtb2R1bGVbJ2V4cG9ydHMnXSA9IGZ1bmN0aW9uKGNvbG9ycykge1xuICByZXR1cm4gZnVuY3Rpb24obGV0dGVyLCBpLCBleHBsb2RlZCkge1xuICAgIGlmIChsZXR0ZXIgPT09ICcgJykgcmV0dXJuIGxldHRlcjtcbiAgICBzd2l0Y2ggKGklMykge1xuICAgICAgY2FzZSAwOiByZXR1cm4gY29sb3JzLnJlZChsZXR0ZXIpO1xuICAgICAgY2FzZSAxOiByZXR1cm4gY29sb3JzLndoaXRlKGxldHRlcik7XG4gICAgICBjYXNlIDI6IHJldHVybiBjb2xvcnMuYmx1ZShsZXR0ZXIpO1xuICAgIH1cbiAgfTtcbn07XG4iLCJtb2R1bGVbJ2V4cG9ydHMnXSA9IGZ1bmN0aW9uKGNvbG9ycykge1xuICByZXR1cm4gZnVuY3Rpb24obGV0dGVyLCBpLCBleHBsb2RlZCkge1xuICAgIHJldHVybiBpICUgMiA9PT0gMCA/IGxldHRlciA6IGNvbG9ycy5pbnZlcnNlKGxldHRlcik7XG4gIH07XG59O1xuIiwibW9kdWxlWydleHBvcnRzJ10gPSBmdW5jdGlvbihjb2xvcnMpIHtcbiAgLy8gUm9ZIEcgQmlWXG4gIHZhciByYWluYm93Q29sb3JzID0gWydyZWQnLCAneWVsbG93JywgJ2dyZWVuJywgJ2JsdWUnLCAnbWFnZW50YSddO1xuICByZXR1cm4gZnVuY3Rpb24obGV0dGVyLCBpLCBleHBsb2RlZCkge1xuICAgIGlmIChsZXR0ZXIgPT09ICcgJykge1xuICAgICAgcmV0dXJuIGxldHRlcjtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIGNvbG9yc1tyYWluYm93Q29sb3JzW2krKyAlIHJhaW5ib3dDb2xvcnMubGVuZ3RoXV0obGV0dGVyKTtcbiAgICB9XG4gIH07XG59O1xuXG4iLCJtb2R1bGVbJ2V4cG9ydHMnXSA9IGZ1bmN0aW9uKGNvbG9ycykge1xuICB2YXIgYXZhaWxhYmxlID0gWyd1bmRlcmxpbmUnLCAnaW52ZXJzZScsICdncmV5JywgJ3llbGxvdycsICdyZWQnLCAnZ3JlZW4nLFxuICAgICdibHVlJywgJ3doaXRlJywgJ2N5YW4nLCAnbWFnZW50YScsICdicmlnaHRZZWxsb3cnLCAnYnJpZ2h0UmVkJyxcbiAgICAnYnJpZ2h0R3JlZW4nLCAnYnJpZ2h0Qmx1ZScsICdicmlnaHRXaGl0ZScsICdicmlnaHRDeWFuJywgJ2JyaWdodE1hZ2VudGEnXTtcbiAgcmV0dXJuIGZ1bmN0aW9uKGxldHRlciwgaSwgZXhwbG9kZWQpIHtcbiAgICByZXR1cm4gbGV0dGVyID09PSAnICcgPyBsZXR0ZXIgOlxuICAgICAgY29sb3JzW1xuICAgICAgICAgIGF2YWlsYWJsZVtNYXRoLnJvdW5kKE1hdGgucmFuZG9tKCkgKiAoYXZhaWxhYmxlLmxlbmd0aCAtIDIpKV1cbiAgICAgIF0obGV0dGVyKTtcbiAgfTtcbn07XG4iLCIvKlxuXG5UaGUgTUlUIExpY2Vuc2UgKE1JVClcblxuT3JpZ2luYWwgTGlicmFyeVxuICAtIENvcHlyaWdodCAoYykgTWFyYWsgU3F1aXJlc1xuXG5BZGRpdGlvbmFsIGZ1bmN0aW9uYWxpdHlcbiAtIENvcHlyaWdodCAoYykgU2luZHJlIFNvcmh1cyA8c2luZHJlc29yaHVzQGdtYWlsLmNvbT4gKHNpbmRyZXNvcmh1cy5jb20pXG5cblBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHlcbm9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlIFwiU29mdHdhcmVcIiksIHRvIGRlYWxcbmluIHRoZSBTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dCBsaW1pdGF0aW9uIHRoZSByaWdodHNcbnRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGxcbmNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpc1xuZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczpcblxuVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW5cbmFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlIFNvZnR3YXJlLlxuXG5USEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SXG5JTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSxcbkZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRVxuQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUlxuTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSxcbk9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU5cblRIRSBTT0ZUV0FSRS5cblxuKi9cblxudmFyIGNvbG9ycyA9IHt9O1xubW9kdWxlWydleHBvcnRzJ10gPSBjb2xvcnM7XG5cbmNvbG9ycy50aGVtZXMgPSB7fTtcblxudmFyIHV0aWwgPSByZXF1aXJlKCd1dGlsJyk7XG52YXIgYW5zaVN0eWxlcyA9IGNvbG9ycy5zdHlsZXMgPSByZXF1aXJlKCcuL3N0eWxlcycpO1xudmFyIGRlZmluZVByb3BzID0gT2JqZWN0LmRlZmluZVByb3BlcnRpZXM7XG52YXIgbmV3TGluZVJlZ2V4ID0gbmV3IFJlZ0V4cCgvW1xcclxcbl0rL2cpO1xuXG5jb2xvcnMuc3VwcG9ydHNDb2xvciA9IHJlcXVpcmUoJy4vc3lzdGVtL3N1cHBvcnRzLWNvbG9ycycpLnN1cHBvcnRzQ29sb3I7XG5cbmlmICh0eXBlb2YgY29sb3JzLmVuYWJsZWQgPT09ICd1bmRlZmluZWQnKSB7XG4gIGNvbG9ycy5lbmFibGVkID0gY29sb3JzLnN1cHBvcnRzQ29sb3IoKSAhPT0gZmFsc2U7XG59XG5cbmNvbG9ycy5lbmFibGUgPSBmdW5jdGlvbigpIHtcbiAgY29sb3JzLmVuYWJsZWQgPSB0cnVlO1xufTtcblxuY29sb3JzLmRpc2FibGUgPSBmdW5jdGlvbigpIHtcbiAgY29sb3JzLmVuYWJsZWQgPSBmYWxzZTtcbn07XG5cbmNvbG9ycy5zdHJpcENvbG9ycyA9IGNvbG9ycy5zdHJpcCA9IGZ1bmN0aW9uKHN0cikge1xuICByZXR1cm4gKCcnICsgc3RyKS5yZXBsYWNlKC9cXHgxQlxcW1xcZCttL2csICcnKTtcbn07XG5cbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bnVzZWQtdmFyc1xudmFyIHN0eWxpemUgPSBjb2xvcnMuc3R5bGl6ZSA9IGZ1bmN0aW9uIHN0eWxpemUoc3RyLCBzdHlsZSkge1xuICBpZiAoIWNvbG9ycy5lbmFibGVkKSB7XG4gICAgcmV0dXJuIHN0cisnJztcbiAgfVxuXG4gIHZhciBzdHlsZU1hcCA9IGFuc2lTdHlsZXNbc3R5bGVdO1xuXG4gIC8vIFN0eWxpemUgc2hvdWxkIHdvcmsgZm9yIG5vbi1BTlNJIHN0eWxlcywgdG9vXG4gIGlmKCFzdHlsZU1hcCAmJiBzdHlsZSBpbiBjb2xvcnMpe1xuICAgIC8vIFN0eWxlIG1hcHMgbGlrZSB0cmFwIG9wZXJhdGUgYXMgZnVuY3Rpb25zIG9uIHN0cmluZ3M7XG4gICAgLy8gdGhleSBkb24ndCBoYXZlIHByb3BlcnRpZXMgbGlrZSBvcGVuIG9yIGNsb3NlLlxuICAgIHJldHVybiBjb2xvcnNbc3R5bGVdKHN0cik7XG4gIH1cblxuICByZXR1cm4gc3R5bGVNYXAub3BlbiArIHN0ciArIHN0eWxlTWFwLmNsb3NlO1xufTtcblxudmFyIG1hdGNoT3BlcmF0b3JzUmUgPSAvW3xcXFxce30oKVtcXF1eJCsqPy5dL2c7XG52YXIgZXNjYXBlU3RyaW5nUmVnZXhwID0gZnVuY3Rpb24oc3RyKSB7XG4gIGlmICh0eXBlb2Ygc3RyICE9PSAnc3RyaW5nJykge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0V4cGVjdGVkIGEgc3RyaW5nJyk7XG4gIH1cbiAgcmV0dXJuIHN0ci5yZXBsYWNlKG1hdGNoT3BlcmF0b3JzUmUsICdcXFxcJCYnKTtcbn07XG5cbmZ1bmN0aW9uIGJ1aWxkKF9zdHlsZXMpIHtcbiAgdmFyIGJ1aWxkZXIgPSBmdW5jdGlvbiBidWlsZGVyKCkge1xuICAgIHJldHVybiBhcHBseVN0eWxlLmFwcGx5KGJ1aWxkZXIsIGFyZ3VtZW50cyk7XG4gIH07XG4gIGJ1aWxkZXIuX3N0eWxlcyA9IF9zdHlsZXM7XG4gIC8vIF9fcHJvdG9fXyBpcyB1c2VkIGJlY2F1c2Ugd2UgbXVzdCByZXR1cm4gYSBmdW5jdGlvbiwgYnV0IHRoZXJlIGlzXG4gIC8vIG5vIHdheSB0byBjcmVhdGUgYSBmdW5jdGlvbiB3aXRoIGEgZGlmZmVyZW50IHByb3RvdHlwZS5cbiAgYnVpbGRlci5fX3Byb3RvX18gPSBwcm90bztcbiAgcmV0dXJuIGJ1aWxkZXI7XG59XG5cbnZhciBzdHlsZXMgPSAoZnVuY3Rpb24oKSB7XG4gIHZhciByZXQgPSB7fTtcbiAgYW5zaVN0eWxlcy5ncmV5ID0gYW5zaVN0eWxlcy5ncmF5O1xuICBPYmplY3Qua2V5cyhhbnNpU3R5bGVzKS5mb3JFYWNoKGZ1bmN0aW9uKGtleSkge1xuICAgIGFuc2lTdHlsZXNba2V5XS5jbG9zZVJlID1cbiAgICAgIG5ldyBSZWdFeHAoZXNjYXBlU3RyaW5nUmVnZXhwKGFuc2lTdHlsZXNba2V5XS5jbG9zZSksICdnJyk7XG4gICAgcmV0W2tleV0gPSB7XG4gICAgICBnZXQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gYnVpbGQodGhpcy5fc3R5bGVzLmNvbmNhdChrZXkpKTtcbiAgICAgIH0sXG4gICAgfTtcbiAgfSk7XG4gIHJldHVybiByZXQ7XG59KSgpO1xuXG52YXIgcHJvdG8gPSBkZWZpbmVQcm9wcyhmdW5jdGlvbiBjb2xvcnMoKSB7fSwgc3R5bGVzKTtcblxuZnVuY3Rpb24gYXBwbHlTdHlsZSgpIHtcbiAgdmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMpO1xuXG4gIHZhciBzdHIgPSBhcmdzLm1hcChmdW5jdGlvbihhcmcpIHtcbiAgICAvLyBVc2Ugd2VhayBlcXVhbGl0eSBjaGVjayBzbyB3ZSBjYW4gY29sb3JpemUgbnVsbC91bmRlZmluZWQgaW4gc2FmZSBtb2RlXG4gICAgaWYgKGFyZyAhPSBudWxsICYmIGFyZy5jb25zdHJ1Y3RvciA9PT0gU3RyaW5nKSB7XG4gICAgICByZXR1cm4gYXJnO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gdXRpbC5pbnNwZWN0KGFyZyk7XG4gICAgfVxuICB9KS5qb2luKCcgJyk7XG5cbiAgaWYgKCFjb2xvcnMuZW5hYmxlZCB8fCAhc3RyKSB7XG4gICAgcmV0dXJuIHN0cjtcbiAgfVxuXG4gIHZhciBuZXdMaW5lc1ByZXNlbnQgPSBzdHIuaW5kZXhPZignXFxuJykgIT0gLTE7XG5cbiAgdmFyIG5lc3RlZFN0eWxlcyA9IHRoaXMuX3N0eWxlcztcblxuICB2YXIgaSA9IG5lc3RlZFN0eWxlcy5sZW5ndGg7XG4gIHdoaWxlIChpLS0pIHtcbiAgICB2YXIgY29kZSA9IGFuc2lTdHlsZXNbbmVzdGVkU3R5bGVzW2ldXTtcbiAgICBzdHIgPSBjb2RlLm9wZW4gKyBzdHIucmVwbGFjZShjb2RlLmNsb3NlUmUsIGNvZGUub3BlbikgKyBjb2RlLmNsb3NlO1xuICAgIGlmIChuZXdMaW5lc1ByZXNlbnQpIHtcbiAgICAgIHN0ciA9IHN0ci5yZXBsYWNlKG5ld0xpbmVSZWdleCwgZnVuY3Rpb24obWF0Y2gpIHtcbiAgICAgICAgcmV0dXJuIGNvZGUuY2xvc2UgKyBtYXRjaCArIGNvZGUub3BlbjtcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBzdHI7XG59XG5cbmNvbG9ycy5zZXRUaGVtZSA9IGZ1bmN0aW9uKHRoZW1lKSB7XG4gIGlmICh0eXBlb2YgdGhlbWUgPT09ICdzdHJpbmcnKSB7XG4gICAgY29uc29sZS5sb2coJ2NvbG9ycy5zZXRUaGVtZSBub3cgb25seSBhY2NlcHRzIGFuIG9iamVjdCwgbm90IGEgc3RyaW5nLiAgJyArXG4gICAgICAnSWYgeW91IGFyZSB0cnlpbmcgdG8gc2V0IGEgdGhlbWUgZnJvbSBhIGZpbGUsIGl0IGlzIG5vdyB5b3VyICh0aGUgJyArXG4gICAgICAnY2FsbGVyXFwncykgcmVzcG9uc2liaWxpdHkgdG8gcmVxdWlyZSB0aGUgZmlsZS4gIFRoZSBvbGQgc3ludGF4ICcgK1xuICAgICAgJ2xvb2tlZCBsaWtlIGNvbG9ycy5zZXRUaGVtZShfX2Rpcm5hbWUgKyAnICtcbiAgICAgICdcXCcvLi4vdGhlbWVzL2dlbmVyaWMtbG9nZ2luZy5qc1xcJyk7IFRoZSBuZXcgc3ludGF4IGxvb2tzIGxpa2UgJytcbiAgICAgICdjb2xvcnMuc2V0VGhlbWUocmVxdWlyZShfX2Rpcm5hbWUgKyAnICtcbiAgICAgICdcXCcvLi4vdGhlbWVzL2dlbmVyaWMtbG9nZ2luZy5qc1xcJykpOycpO1xuICAgIHJldHVybjtcbiAgfVxuICBmb3IgKHZhciBzdHlsZSBpbiB0aGVtZSkge1xuICAgIChmdW5jdGlvbihzdHlsZSkge1xuICAgICAgY29sb3JzW3N0eWxlXSA9IGZ1bmN0aW9uKHN0cikge1xuICAgICAgICBpZiAodHlwZW9mIHRoZW1lW3N0eWxlXSA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICB2YXIgb3V0ID0gc3RyO1xuICAgICAgICAgIGZvciAodmFyIGkgaW4gdGhlbWVbc3R5bGVdKSB7XG4gICAgICAgICAgICBvdXQgPSBjb2xvcnNbdGhlbWVbc3R5bGVdW2ldXShvdXQpO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gb3V0O1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBjb2xvcnNbdGhlbWVbc3R5bGVdXShzdHIpO1xuICAgICAgfTtcbiAgICB9KShzdHlsZSk7XG4gIH1cbn07XG5cbmZ1bmN0aW9uIGluaXQoKSB7XG4gIHZhciByZXQgPSB7fTtcbiAgT2JqZWN0LmtleXMoc3R5bGVzKS5mb3JFYWNoKGZ1bmN0aW9uKG5hbWUpIHtcbiAgICByZXRbbmFtZV0gPSB7XG4gICAgICBnZXQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gYnVpbGQoW25hbWVdKTtcbiAgICAgIH0sXG4gICAgfTtcbiAgfSk7XG4gIHJldHVybiByZXQ7XG59XG5cbnZhciBzZXF1ZW5jZXIgPSBmdW5jdGlvbiBzZXF1ZW5jZXIobWFwLCBzdHIpIHtcbiAgdmFyIGV4cGxvZGVkID0gc3RyLnNwbGl0KCcnKTtcbiAgZXhwbG9kZWQgPSBleHBsb2RlZC5tYXAobWFwKTtcbiAgcmV0dXJuIGV4cGxvZGVkLmpvaW4oJycpO1xufTtcblxuLy8gY3VzdG9tIGZvcm1hdHRlciBtZXRob2RzXG5jb2xvcnMudHJhcCA9IHJlcXVpcmUoJy4vY3VzdG9tL3RyYXAnKTtcbmNvbG9ycy56YWxnbyA9IHJlcXVpcmUoJy4vY3VzdG9tL3phbGdvJyk7XG5cbi8vIG1hcHNcbmNvbG9ycy5tYXBzID0ge307XG5jb2xvcnMubWFwcy5hbWVyaWNhID0gcmVxdWlyZSgnLi9tYXBzL2FtZXJpY2EnKShjb2xvcnMpO1xuY29sb3JzLm1hcHMuemVicmEgPSByZXF1aXJlKCcuL21hcHMvemVicmEnKShjb2xvcnMpO1xuY29sb3JzLm1hcHMucmFpbmJvdyA9IHJlcXVpcmUoJy4vbWFwcy9yYWluYm93JykoY29sb3JzKTtcbmNvbG9ycy5tYXBzLnJhbmRvbSA9IHJlcXVpcmUoJy4vbWFwcy9yYW5kb20nKShjb2xvcnMpO1xuXG5mb3IgKHZhciBtYXAgaW4gY29sb3JzLm1hcHMpIHtcbiAgKGZ1bmN0aW9uKG1hcCkge1xuICAgIGNvbG9yc1ttYXBdID0gZnVuY3Rpb24oc3RyKSB7XG4gICAgICByZXR1cm4gc2VxdWVuY2VyKGNvbG9ycy5tYXBzW21hcF0sIHN0cik7XG4gICAgfTtcbiAgfSkobWFwKTtcbn1cblxuZGVmaW5lUHJvcHMoY29sb3JzLCBpbml0KCkpO1xuIiwidmFyIGNvbG9ycyA9IHJlcXVpcmUoJy4vY29sb3JzJyk7XG5cbm1vZHVsZVsnZXhwb3J0cyddID0gZnVuY3Rpb24oKSB7XG4gIC8vXG4gIC8vIEV4dGVuZHMgcHJvdG90eXBlIG9mIG5hdGl2ZSBzdHJpbmcgb2JqZWN0IHRvIGFsbG93IGZvciBcImZvb1wiLnJlZCBzeW50YXhcbiAgLy9cbiAgdmFyIGFkZFByb3BlcnR5ID0gZnVuY3Rpb24oY29sb3IsIGZ1bmMpIHtcbiAgICBTdHJpbmcucHJvdG90eXBlLl9fZGVmaW5lR2V0dGVyX18oY29sb3IsIGZ1bmMpO1xuICB9O1xuXG4gIGFkZFByb3BlcnR5KCdzdHJpcCcsIGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiBjb2xvcnMuc3RyaXAodGhpcyk7XG4gIH0pO1xuXG4gIGFkZFByb3BlcnR5KCdzdHJpcENvbG9ycycsIGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiBjb2xvcnMuc3RyaXAodGhpcyk7XG4gIH0pO1xuXG4gIGFkZFByb3BlcnR5KCd0cmFwJywgZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIGNvbG9ycy50cmFwKHRoaXMpO1xuICB9KTtcblxuICBhZGRQcm9wZXJ0eSgnemFsZ28nLCBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gY29sb3JzLnphbGdvKHRoaXMpO1xuICB9KTtcblxuICBhZGRQcm9wZXJ0eSgnemVicmEnLCBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gY29sb3JzLnplYnJhKHRoaXMpO1xuICB9KTtcblxuICBhZGRQcm9wZXJ0eSgncmFpbmJvdycsIGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiBjb2xvcnMucmFpbmJvdyh0aGlzKTtcbiAgfSk7XG5cbiAgYWRkUHJvcGVydHkoJ3JhbmRvbScsIGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiBjb2xvcnMucmFuZG9tKHRoaXMpO1xuICB9KTtcblxuICBhZGRQcm9wZXJ0eSgnYW1lcmljYScsIGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiBjb2xvcnMuYW1lcmljYSh0aGlzKTtcbiAgfSk7XG5cbiAgLy9cbiAgLy8gSXRlcmF0ZSB0aHJvdWdoIGFsbCBkZWZhdWx0IHN0eWxlcyBhbmQgY29sb3JzXG4gIC8vXG4gIHZhciB4ID0gT2JqZWN0LmtleXMoY29sb3JzLnN0eWxlcyk7XG4gIHguZm9yRWFjaChmdW5jdGlvbihzdHlsZSkge1xuICAgIGFkZFByb3BlcnR5KHN0eWxlLCBmdW5jdGlvbigpIHtcbiAgICAgIHJldHVybiBjb2xvcnMuc3R5bGl6ZSh0aGlzLCBzdHlsZSk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGZ1bmN0aW9uIGFwcGx5VGhlbWUodGhlbWUpIHtcbiAgICAvL1xuICAgIC8vIFJlbWFyazogVGhpcyBpcyBhIGxpc3Qgb2YgbWV0aG9kcyB0aGF0IGV4aXN0XG4gICAgLy8gb24gU3RyaW5nIHRoYXQgeW91IHNob3VsZCBub3Qgb3ZlcndyaXRlLlxuICAgIC8vXG4gICAgdmFyIHN0cmluZ1Byb3RvdHlwZUJsYWNrbGlzdCA9IFtcbiAgICAgICdfX2RlZmluZUdldHRlcl9fJywgJ19fZGVmaW5lU2V0dGVyX18nLCAnX19sb29rdXBHZXR0ZXJfXycsXG4gICAgICAnX19sb29rdXBTZXR0ZXJfXycsICdjaGFyQXQnLCAnY29uc3RydWN0b3InLCAnaGFzT3duUHJvcGVydHknLFxuICAgICAgJ2lzUHJvdG90eXBlT2YnLCAncHJvcGVydHlJc0VudW1lcmFibGUnLCAndG9Mb2NhbGVTdHJpbmcnLCAndG9TdHJpbmcnLFxuICAgICAgJ3ZhbHVlT2YnLCAnY2hhckNvZGVBdCcsICdpbmRleE9mJywgJ2xhc3RJbmRleE9mJywgJ2xlbmd0aCcsXG4gICAgICAnbG9jYWxlQ29tcGFyZScsICdtYXRjaCcsICdyZXBlYXQnLCAncmVwbGFjZScsICdzZWFyY2gnLCAnc2xpY2UnLFxuICAgICAgJ3NwbGl0JywgJ3N1YnN0cmluZycsICd0b0xvY2FsZUxvd2VyQ2FzZScsICd0b0xvY2FsZVVwcGVyQ2FzZScsXG4gICAgICAndG9Mb3dlckNhc2UnLCAndG9VcHBlckNhc2UnLCAndHJpbScsICd0cmltTGVmdCcsICd0cmltUmlnaHQnLFxuICAgIF07XG5cbiAgICBPYmplY3Qua2V5cyh0aGVtZSkuZm9yRWFjaChmdW5jdGlvbihwcm9wKSB7XG4gICAgICBpZiAoc3RyaW5nUHJvdG90eXBlQmxhY2tsaXN0LmluZGV4T2YocHJvcCkgIT09IC0xKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCd3YXJuOiAnLnJlZCArICgnU3RyaW5nLnByb3RvdHlwZScgKyBwcm9wKS5tYWdlbnRhICtcbiAgICAgICAgICAnIGlzIHByb2JhYmx5IHNvbWV0aGluZyB5b3UgZG9uXFwndCB3YW50IHRvIG92ZXJyaWRlLiAgJyArXG4gICAgICAgICAgJ0lnbm9yaW5nIHN0eWxlIG5hbWUnKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGlmICh0eXBlb2YodGhlbWVbcHJvcF0pID09PSAnc3RyaW5nJykge1xuICAgICAgICAgIGNvbG9yc1twcm9wXSA9IGNvbG9yc1t0aGVtZVtwcm9wXV07XG4gICAgICAgICAgYWRkUHJvcGVydHkocHJvcCwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICByZXR1cm4gY29sb3JzW3Byb3BdKHRoaXMpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHZhciB0aGVtZVByb3BBcHBsaWNhdG9yID0gZnVuY3Rpb24oc3RyKSB7XG4gICAgICAgICAgICB2YXIgcmV0ID0gc3RyIHx8IHRoaXM7XG4gICAgICAgICAgICBmb3IgKHZhciB0ID0gMDsgdCA8IHRoZW1lW3Byb3BdLmxlbmd0aDsgdCsrKSB7XG4gICAgICAgICAgICAgIHJldCA9IGNvbG9yc1t0aGVtZVtwcm9wXVt0XV0ocmV0KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiByZXQ7XG4gICAgICAgICAgfTtcbiAgICAgICAgICBhZGRQcm9wZXJ0eShwcm9wLCB0aGVtZVByb3BBcHBsaWNhdG9yKTtcbiAgICAgICAgICBjb2xvcnNbcHJvcF0gPSBmdW5jdGlvbihzdHIpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGVtZVByb3BBcHBsaWNhdG9yKHN0cik7XG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgY29sb3JzLnNldFRoZW1lID0gZnVuY3Rpb24odGhlbWUpIHtcbiAgICBpZiAodHlwZW9mIHRoZW1lID09PSAnc3RyaW5nJykge1xuICAgICAgY29uc29sZS5sb2coJ2NvbG9ycy5zZXRUaGVtZSBub3cgb25seSBhY2NlcHRzIGFuIG9iamVjdCwgbm90IGEgc3RyaW5nLiAnICtcbiAgICAgICAgJ0lmIHlvdSBhcmUgdHJ5aW5nIHRvIHNldCBhIHRoZW1lIGZyb20gYSBmaWxlLCBpdCBpcyBub3cgeW91ciAodGhlICcgK1xuICAgICAgICAnY2FsbGVyXFwncykgcmVzcG9uc2liaWxpdHkgdG8gcmVxdWlyZSB0aGUgZmlsZS4gIFRoZSBvbGQgc3ludGF4ICcgK1xuICAgICAgICAnbG9va2VkIGxpa2UgY29sb3JzLnNldFRoZW1lKF9fZGlybmFtZSArICcgK1xuICAgICAgICAnXFwnLy4uL3RoZW1lcy9nZW5lcmljLWxvZ2dpbmcuanNcXCcpOyBUaGUgbmV3IHN5bnRheCBsb29rcyBsaWtlICcrXG4gICAgICAgICdjb2xvcnMuc2V0VGhlbWUocmVxdWlyZShfX2Rpcm5hbWUgKyAnICtcbiAgICAgICAgJ1xcJy8uLi90aGVtZXMvZ2VuZXJpYy1sb2dnaW5nLmpzXFwnKSk7Jyk7XG4gICAgICByZXR1cm47XG4gICAgfSBlbHNlIHtcbiAgICAgIGFwcGx5VGhlbWUodGhlbWUpO1xuICAgIH1cbiAgfTtcbn07XG4iLCJ2YXIgY29sb3JzID0gcmVxdWlyZSgnLi9jb2xvcnMnKTtcbm1vZHVsZVsnZXhwb3J0cyddID0gY29sb3JzO1xuXG4vLyBSZW1hcms6IEJ5IGRlZmF1bHQsIGNvbG9ycyB3aWxsIGFkZCBzdHlsZSBwcm9wZXJ0aWVzIHRvIFN0cmluZy5wcm90b3R5cGUuXG4vL1xuLy8gSWYgeW91IGRvbid0IHdpc2ggdG8gZXh0ZW5kIFN0cmluZy5wcm90b3R5cGUsIHlvdSBjYW4gZG8gdGhpcyBpbnN0ZWFkIGFuZFxuLy8gbmF0aXZlIFN0cmluZyB3aWxsIG5vdCBiZSB0b3VjaGVkOlxuLy9cbi8vICAgdmFyIGNvbG9ycyA9IHJlcXVpcmUoJ2NvbG9ycy9zYWZlKTtcbi8vICAgY29sb3JzLnJlZChcImZvb1wiKVxuLy9cbi8vXG5yZXF1aXJlKCcuL2V4dGVuZFN0cmluZ1Byb3RvdHlwZScpKCk7XG4iLCIvLyEgbW9tZW50LmpzXG4vLyEgdmVyc2lvbiA6IDIuMjcuMFxuLy8hIGF1dGhvcnMgOiBUaW0gV29vZCwgSXNrcmVuIENoZXJuZXYsIE1vbWVudC5qcyBjb250cmlidXRvcnNcbi8vISBsaWNlbnNlIDogTUlUXG4vLyEgbW9tZW50anMuY29tXG5cbjsoZnVuY3Rpb24gKGdsb2JhbCwgZmFjdG9yeSkge1xuICAgIHR5cGVvZiBleHBvcnRzID09PSAnb2JqZWN0JyAmJiB0eXBlb2YgbW9kdWxlICE9PSAndW5kZWZpbmVkJyA/IG1vZHVsZS5leHBvcnRzID0gZmFjdG9yeSgpIDpcbiAgICB0eXBlb2YgZGVmaW5lID09PSAnZnVuY3Rpb24nICYmIGRlZmluZS5hbWQgPyBkZWZpbmUoZmFjdG9yeSkgOlxuICAgIGdsb2JhbC5tb21lbnQgPSBmYWN0b3J5KClcbn0odGhpcywgKGZ1bmN0aW9uICgpIHsgJ3VzZSBzdHJpY3QnO1xuXG4gICAgdmFyIGhvb2tDYWxsYmFjaztcblxuICAgIGZ1bmN0aW9uIGhvb2tzKCkge1xuICAgICAgICByZXR1cm4gaG9va0NhbGxiYWNrLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7XG4gICAgfVxuXG4gICAgLy8gVGhpcyBpcyBkb25lIHRvIHJlZ2lzdGVyIHRoZSBtZXRob2QgY2FsbGVkIHdpdGggbW9tZW50KClcbiAgICAvLyB3aXRob3V0IGNyZWF0aW5nIGNpcmN1bGFyIGRlcGVuZGVuY2llcy5cbiAgICBmdW5jdGlvbiBzZXRIb29rQ2FsbGJhY2soY2FsbGJhY2spIHtcbiAgICAgICAgaG9va0NhbGxiYWNrID0gY2FsbGJhY2s7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gaXNBcnJheShpbnB1dCkge1xuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgaW5wdXQgaW5zdGFuY2VvZiBBcnJheSB8fFxuICAgICAgICAgICAgT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKGlucHV0KSA9PT0gJ1tvYmplY3QgQXJyYXldJ1xuICAgICAgICApO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGlzT2JqZWN0KGlucHV0KSB7XG4gICAgICAgIC8vIElFOCB3aWxsIHRyZWF0IHVuZGVmaW5lZCBhbmQgbnVsbCBhcyBvYmplY3QgaWYgaXQgd2Fzbid0IGZvclxuICAgICAgICAvLyBpbnB1dCAhPSBudWxsXG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICBpbnB1dCAhPSBudWxsICYmXG4gICAgICAgICAgICBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwoaW5wdXQpID09PSAnW29iamVjdCBPYmplY3RdJ1xuICAgICAgICApO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGhhc093blByb3AoYSwgYikge1xuICAgICAgICByZXR1cm4gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGEsIGIpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGlzT2JqZWN0RW1wdHkob2JqKSB7XG4gICAgICAgIGlmIChPYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcykge1xuICAgICAgICAgICAgcmV0dXJuIE9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKG9iaikubGVuZ3RoID09PSAwO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdmFyIGs7XG4gICAgICAgICAgICBmb3IgKGsgaW4gb2JqKSB7XG4gICAgICAgICAgICAgICAgaWYgKGhhc093blByb3Aob2JqLCBrKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiBpc1VuZGVmaW5lZChpbnB1dCkge1xuICAgICAgICByZXR1cm4gaW5wdXQgPT09IHZvaWQgMDtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBpc051bWJlcihpbnB1dCkge1xuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgdHlwZW9mIGlucHV0ID09PSAnbnVtYmVyJyB8fFxuICAgICAgICAgICAgT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKGlucHV0KSA9PT0gJ1tvYmplY3QgTnVtYmVyXSdcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBpc0RhdGUoaW5wdXQpIHtcbiAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgIGlucHV0IGluc3RhbmNlb2YgRGF0ZSB8fFxuICAgICAgICAgICAgT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKGlucHV0KSA9PT0gJ1tvYmplY3QgRGF0ZV0nXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gbWFwKGFyciwgZm4pIHtcbiAgICAgICAgdmFyIHJlcyA9IFtdLFxuICAgICAgICAgICAgaTtcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IGFyci5sZW5ndGg7ICsraSkge1xuICAgICAgICAgICAgcmVzLnB1c2goZm4oYXJyW2ldLCBpKSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJlcztcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBleHRlbmQoYSwgYikge1xuICAgICAgICBmb3IgKHZhciBpIGluIGIpIHtcbiAgICAgICAgICAgIGlmIChoYXNPd25Qcm9wKGIsIGkpKSB7XG4gICAgICAgICAgICAgICAgYVtpXSA9IGJbaV07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoaGFzT3duUHJvcChiLCAndG9TdHJpbmcnKSkge1xuICAgICAgICAgICAgYS50b1N0cmluZyA9IGIudG9TdHJpbmc7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoaGFzT3duUHJvcChiLCAndmFsdWVPZicpKSB7XG4gICAgICAgICAgICBhLnZhbHVlT2YgPSBiLnZhbHVlT2Y7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gYTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBjcmVhdGVVVEMoaW5wdXQsIGZvcm1hdCwgbG9jYWxlLCBzdHJpY3QpIHtcbiAgICAgICAgcmV0dXJuIGNyZWF0ZUxvY2FsT3JVVEMoaW5wdXQsIGZvcm1hdCwgbG9jYWxlLCBzdHJpY3QsIHRydWUpLnV0YygpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGRlZmF1bHRQYXJzaW5nRmxhZ3MoKSB7XG4gICAgICAgIC8vIFdlIG5lZWQgdG8gZGVlcCBjbG9uZSB0aGlzIG9iamVjdC5cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGVtcHR5OiBmYWxzZSxcbiAgICAgICAgICAgIHVudXNlZFRva2VuczogW10sXG4gICAgICAgICAgICB1bnVzZWRJbnB1dDogW10sXG4gICAgICAgICAgICBvdmVyZmxvdzogLTIsXG4gICAgICAgICAgICBjaGFyc0xlZnRPdmVyOiAwLFxuICAgICAgICAgICAgbnVsbElucHV0OiBmYWxzZSxcbiAgICAgICAgICAgIGludmFsaWRFcmE6IG51bGwsXG4gICAgICAgICAgICBpbnZhbGlkTW9udGg6IG51bGwsXG4gICAgICAgICAgICBpbnZhbGlkRm9ybWF0OiBmYWxzZSxcbiAgICAgICAgICAgIHVzZXJJbnZhbGlkYXRlZDogZmFsc2UsXG4gICAgICAgICAgICBpc286IGZhbHNlLFxuICAgICAgICAgICAgcGFyc2VkRGF0ZVBhcnRzOiBbXSxcbiAgICAgICAgICAgIGVyYTogbnVsbCxcbiAgICAgICAgICAgIG1lcmlkaWVtOiBudWxsLFxuICAgICAgICAgICAgcmZjMjgyMjogZmFsc2UsXG4gICAgICAgICAgICB3ZWVrZGF5TWlzbWF0Y2g6IGZhbHNlLFxuICAgICAgICB9O1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGdldFBhcnNpbmdGbGFncyhtKSB7XG4gICAgICAgIGlmIChtLl9wZiA9PSBudWxsKSB7XG4gICAgICAgICAgICBtLl9wZiA9IGRlZmF1bHRQYXJzaW5nRmxhZ3MoKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbS5fcGY7XG4gICAgfVxuXG4gICAgdmFyIHNvbWU7XG4gICAgaWYgKEFycmF5LnByb3RvdHlwZS5zb21lKSB7XG4gICAgICAgIHNvbWUgPSBBcnJheS5wcm90b3R5cGUuc29tZTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBzb21lID0gZnVuY3Rpb24gKGZ1bikge1xuICAgICAgICAgICAgdmFyIHQgPSBPYmplY3QodGhpcyksXG4gICAgICAgICAgICAgICAgbGVuID0gdC5sZW5ndGggPj4+IDAsXG4gICAgICAgICAgICAgICAgaTtcblxuICAgICAgICAgICAgZm9yIChpID0gMDsgaSA8IGxlbjsgaSsrKSB7XG4gICAgICAgICAgICAgICAgaWYgKGkgaW4gdCAmJiBmdW4uY2FsbCh0aGlzLCB0W2ldLCBpLCB0KSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBpc1ZhbGlkKG0pIHtcbiAgICAgICAgaWYgKG0uX2lzVmFsaWQgPT0gbnVsbCkge1xuICAgICAgICAgICAgdmFyIGZsYWdzID0gZ2V0UGFyc2luZ0ZsYWdzKG0pLFxuICAgICAgICAgICAgICAgIHBhcnNlZFBhcnRzID0gc29tZS5jYWxsKGZsYWdzLnBhcnNlZERhdGVQYXJ0cywgZnVuY3Rpb24gKGkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGkgIT0gbnVsbDtcbiAgICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgICAgICBpc05vd1ZhbGlkID1cbiAgICAgICAgICAgICAgICAgICAgIWlzTmFOKG0uX2QuZ2V0VGltZSgpKSAmJlxuICAgICAgICAgICAgICAgICAgICBmbGFncy5vdmVyZmxvdyA8IDAgJiZcbiAgICAgICAgICAgICAgICAgICAgIWZsYWdzLmVtcHR5ICYmXG4gICAgICAgICAgICAgICAgICAgICFmbGFncy5pbnZhbGlkRXJhICYmXG4gICAgICAgICAgICAgICAgICAgICFmbGFncy5pbnZhbGlkTW9udGggJiZcbiAgICAgICAgICAgICAgICAgICAgIWZsYWdzLmludmFsaWRXZWVrZGF5ICYmXG4gICAgICAgICAgICAgICAgICAgICFmbGFncy53ZWVrZGF5TWlzbWF0Y2ggJiZcbiAgICAgICAgICAgICAgICAgICAgIWZsYWdzLm51bGxJbnB1dCAmJlxuICAgICAgICAgICAgICAgICAgICAhZmxhZ3MuaW52YWxpZEZvcm1hdCAmJlxuICAgICAgICAgICAgICAgICAgICAhZmxhZ3MudXNlckludmFsaWRhdGVkICYmXG4gICAgICAgICAgICAgICAgICAgICghZmxhZ3MubWVyaWRpZW0gfHwgKGZsYWdzLm1lcmlkaWVtICYmIHBhcnNlZFBhcnRzKSk7XG5cbiAgICAgICAgICAgIGlmIChtLl9zdHJpY3QpIHtcbiAgICAgICAgICAgICAgICBpc05vd1ZhbGlkID1cbiAgICAgICAgICAgICAgICAgICAgaXNOb3dWYWxpZCAmJlxuICAgICAgICAgICAgICAgICAgICBmbGFncy5jaGFyc0xlZnRPdmVyID09PSAwICYmXG4gICAgICAgICAgICAgICAgICAgIGZsYWdzLnVudXNlZFRva2Vucy5sZW5ndGggPT09IDAgJiZcbiAgICAgICAgICAgICAgICAgICAgZmxhZ3MuYmlnSG91ciA9PT0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoT2JqZWN0LmlzRnJvemVuID09IG51bGwgfHwgIU9iamVjdC5pc0Zyb3plbihtKSkge1xuICAgICAgICAgICAgICAgIG0uX2lzVmFsaWQgPSBpc05vd1ZhbGlkO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gaXNOb3dWYWxpZDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbS5faXNWYWxpZDtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBjcmVhdGVJbnZhbGlkKGZsYWdzKSB7XG4gICAgICAgIHZhciBtID0gY3JlYXRlVVRDKE5hTik7XG4gICAgICAgIGlmIChmbGFncyAhPSBudWxsKSB7XG4gICAgICAgICAgICBleHRlbmQoZ2V0UGFyc2luZ0ZsYWdzKG0pLCBmbGFncyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBnZXRQYXJzaW5nRmxhZ3MobSkudXNlckludmFsaWRhdGVkID0gdHJ1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBtO1xuICAgIH1cblxuICAgIC8vIFBsdWdpbnMgdGhhdCBhZGQgcHJvcGVydGllcyBzaG91bGQgYWxzbyBhZGQgdGhlIGtleSBoZXJlIChudWxsIHZhbHVlKSxcbiAgICAvLyBzbyB3ZSBjYW4gcHJvcGVybHkgY2xvbmUgb3Vyc2VsdmVzLlxuICAgIHZhciBtb21lbnRQcm9wZXJ0aWVzID0gKGhvb2tzLm1vbWVudFByb3BlcnRpZXMgPSBbXSksXG4gICAgICAgIHVwZGF0ZUluUHJvZ3Jlc3MgPSBmYWxzZTtcblxuICAgIGZ1bmN0aW9uIGNvcHlDb25maWcodG8sIGZyb20pIHtcbiAgICAgICAgdmFyIGksIHByb3AsIHZhbDtcblxuICAgICAgICBpZiAoIWlzVW5kZWZpbmVkKGZyb20uX2lzQU1vbWVudE9iamVjdCkpIHtcbiAgICAgICAgICAgIHRvLl9pc0FNb21lbnRPYmplY3QgPSBmcm9tLl9pc0FNb21lbnRPYmplY3Q7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFpc1VuZGVmaW5lZChmcm9tLl9pKSkge1xuICAgICAgICAgICAgdG8uX2kgPSBmcm9tLl9pO1xuICAgICAgICB9XG4gICAgICAgIGlmICghaXNVbmRlZmluZWQoZnJvbS5fZikpIHtcbiAgICAgICAgICAgIHRvLl9mID0gZnJvbS5fZjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIWlzVW5kZWZpbmVkKGZyb20uX2wpKSB7XG4gICAgICAgICAgICB0by5fbCA9IGZyb20uX2w7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFpc1VuZGVmaW5lZChmcm9tLl9zdHJpY3QpKSB7XG4gICAgICAgICAgICB0by5fc3RyaWN0ID0gZnJvbS5fc3RyaWN0O1xuICAgICAgICB9XG4gICAgICAgIGlmICghaXNVbmRlZmluZWQoZnJvbS5fdHptKSkge1xuICAgICAgICAgICAgdG8uX3R6bSA9IGZyb20uX3R6bTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIWlzVW5kZWZpbmVkKGZyb20uX2lzVVRDKSkge1xuICAgICAgICAgICAgdG8uX2lzVVRDID0gZnJvbS5faXNVVEM7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFpc1VuZGVmaW5lZChmcm9tLl9vZmZzZXQpKSB7XG4gICAgICAgICAgICB0by5fb2Zmc2V0ID0gZnJvbS5fb2Zmc2V0O1xuICAgICAgICB9XG4gICAgICAgIGlmICghaXNVbmRlZmluZWQoZnJvbS5fcGYpKSB7XG4gICAgICAgICAgICB0by5fcGYgPSBnZXRQYXJzaW5nRmxhZ3MoZnJvbSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFpc1VuZGVmaW5lZChmcm9tLl9sb2NhbGUpKSB7XG4gICAgICAgICAgICB0by5fbG9jYWxlID0gZnJvbS5fbG9jYWxlO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKG1vbWVudFByb3BlcnRpZXMubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgZm9yIChpID0gMDsgaSA8IG1vbWVudFByb3BlcnRpZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICBwcm9wID0gbW9tZW50UHJvcGVydGllc1tpXTtcbiAgICAgICAgICAgICAgICB2YWwgPSBmcm9tW3Byb3BdO1xuICAgICAgICAgICAgICAgIGlmICghaXNVbmRlZmluZWQodmFsKSkge1xuICAgICAgICAgICAgICAgICAgICB0b1twcm9wXSA9IHZhbDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdG87XG4gICAgfVxuXG4gICAgLy8gTW9tZW50IHByb3RvdHlwZSBvYmplY3RcbiAgICBmdW5jdGlvbiBNb21lbnQoY29uZmlnKSB7XG4gICAgICAgIGNvcHlDb25maWcodGhpcywgY29uZmlnKTtcbiAgICAgICAgdGhpcy5fZCA9IG5ldyBEYXRlKGNvbmZpZy5fZCAhPSBudWxsID8gY29uZmlnLl9kLmdldFRpbWUoKSA6IE5hTik7XG4gICAgICAgIGlmICghdGhpcy5pc1ZhbGlkKCkpIHtcbiAgICAgICAgICAgIHRoaXMuX2QgPSBuZXcgRGF0ZShOYU4pO1xuICAgICAgICB9XG4gICAgICAgIC8vIFByZXZlbnQgaW5maW5pdGUgbG9vcCBpbiBjYXNlIHVwZGF0ZU9mZnNldCBjcmVhdGVzIG5ldyBtb21lbnRcbiAgICAgICAgLy8gb2JqZWN0cy5cbiAgICAgICAgaWYgKHVwZGF0ZUluUHJvZ3Jlc3MgPT09IGZhbHNlKSB7XG4gICAgICAgICAgICB1cGRhdGVJblByb2dyZXNzID0gdHJ1ZTtcbiAgICAgICAgICAgIGhvb2tzLnVwZGF0ZU9mZnNldCh0aGlzKTtcbiAgICAgICAgICAgIHVwZGF0ZUluUHJvZ3Jlc3MgPSBmYWxzZTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIGlzTW9tZW50KG9iaikge1xuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgb2JqIGluc3RhbmNlb2YgTW9tZW50IHx8IChvYmogIT0gbnVsbCAmJiBvYmouX2lzQU1vbWVudE9iamVjdCAhPSBudWxsKVxuICAgICAgICApO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHdhcm4obXNnKSB7XG4gICAgICAgIGlmIChcbiAgICAgICAgICAgIGhvb2tzLnN1cHByZXNzRGVwcmVjYXRpb25XYXJuaW5ncyA9PT0gZmFsc2UgJiZcbiAgICAgICAgICAgIHR5cGVvZiBjb25zb2xlICE9PSAndW5kZWZpbmVkJyAmJlxuICAgICAgICAgICAgY29uc29sZS53YXJuXG4gICAgICAgICkge1xuICAgICAgICAgICAgY29uc29sZS53YXJuKCdEZXByZWNhdGlvbiB3YXJuaW5nOiAnICsgbXNnKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIGRlcHJlY2F0ZShtc2csIGZuKSB7XG4gICAgICAgIHZhciBmaXJzdFRpbWUgPSB0cnVlO1xuXG4gICAgICAgIHJldHVybiBleHRlbmQoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgaWYgKGhvb2tzLmRlcHJlY2F0aW9uSGFuZGxlciAhPSBudWxsKSB7XG4gICAgICAgICAgICAgICAgaG9va3MuZGVwcmVjYXRpb25IYW5kbGVyKG51bGwsIG1zZyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoZmlyc3RUaW1lKSB7XG4gICAgICAgICAgICAgICAgdmFyIGFyZ3MgPSBbXSxcbiAgICAgICAgICAgICAgICAgICAgYXJnLFxuICAgICAgICAgICAgICAgICAgICBpLFxuICAgICAgICAgICAgICAgICAgICBrZXk7XG4gICAgICAgICAgICAgICAgZm9yIChpID0gMDsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgICAgICBhcmcgPSAnJztcbiAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBhcmd1bWVudHNbaV0gPT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBhcmcgKz0gJ1xcblsnICsgaSArICddICc7XG4gICAgICAgICAgICAgICAgICAgICAgICBmb3IgKGtleSBpbiBhcmd1bWVudHNbMF0pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoaGFzT3duUHJvcChhcmd1bWVudHNbMF0sIGtleSkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXJnICs9IGtleSArICc6ICcgKyBhcmd1bWVudHNbMF1ba2V5XSArICcsICc7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgYXJnID0gYXJnLnNsaWNlKDAsIC0yKTsgLy8gUmVtb3ZlIHRyYWlsaW5nIGNvbW1hIGFuZCBzcGFjZVxuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgYXJnID0gYXJndW1lbnRzW2ldO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGFyZ3MucHVzaChhcmcpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB3YXJuKFxuICAgICAgICAgICAgICAgICAgICBtc2cgK1xuICAgICAgICAgICAgICAgICAgICAgICAgJ1xcbkFyZ3VtZW50czogJyArXG4gICAgICAgICAgICAgICAgICAgICAgICBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmdzKS5qb2luKCcnKSArXG4gICAgICAgICAgICAgICAgICAgICAgICAnXFxuJyArXG4gICAgICAgICAgICAgICAgICAgICAgICBuZXcgRXJyb3IoKS5zdGFja1xuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgZmlyc3RUaW1lID0gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gZm4uYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgfSwgZm4pO1xuICAgIH1cblxuICAgIHZhciBkZXByZWNhdGlvbnMgPSB7fTtcblxuICAgIGZ1bmN0aW9uIGRlcHJlY2F0ZVNpbXBsZShuYW1lLCBtc2cpIHtcbiAgICAgICAgaWYgKGhvb2tzLmRlcHJlY2F0aW9uSGFuZGxlciAhPSBudWxsKSB7XG4gICAgICAgICAgICBob29rcy5kZXByZWNhdGlvbkhhbmRsZXIobmFtZSwgbXNnKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIWRlcHJlY2F0aW9uc1tuYW1lXSkge1xuICAgICAgICAgICAgd2Fybihtc2cpO1xuICAgICAgICAgICAgZGVwcmVjYXRpb25zW25hbWVdID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGhvb2tzLnN1cHByZXNzRGVwcmVjYXRpb25XYXJuaW5ncyA9IGZhbHNlO1xuICAgIGhvb2tzLmRlcHJlY2F0aW9uSGFuZGxlciA9IG51bGw7XG5cbiAgICBmdW5jdGlvbiBpc0Z1bmN0aW9uKGlucHV0KSB7XG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICAodHlwZW9mIEZ1bmN0aW9uICE9PSAndW5kZWZpbmVkJyAmJiBpbnB1dCBpbnN0YW5jZW9mIEZ1bmN0aW9uKSB8fFxuICAgICAgICAgICAgT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKGlucHV0KSA9PT0gJ1tvYmplY3QgRnVuY3Rpb25dJ1xuICAgICAgICApO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHNldChjb25maWcpIHtcbiAgICAgICAgdmFyIHByb3AsIGk7XG4gICAgICAgIGZvciAoaSBpbiBjb25maWcpIHtcbiAgICAgICAgICAgIGlmIChoYXNPd25Qcm9wKGNvbmZpZywgaSkpIHtcbiAgICAgICAgICAgICAgICBwcm9wID0gY29uZmlnW2ldO1xuICAgICAgICAgICAgICAgIGlmIChpc0Z1bmN0aW9uKHByb3ApKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXNbaV0gPSBwcm9wO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXNbJ18nICsgaV0gPSBwcm9wO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICB0aGlzLl9jb25maWcgPSBjb25maWc7XG4gICAgICAgIC8vIExlbmllbnQgb3JkaW5hbCBwYXJzaW5nIGFjY2VwdHMganVzdCBhIG51bWJlciBpbiBhZGRpdGlvbiB0b1xuICAgICAgICAvLyBudW1iZXIgKyAocG9zc2libHkpIHN0dWZmIGNvbWluZyBmcm9tIF9kYXlPZk1vbnRoT3JkaW5hbFBhcnNlLlxuICAgICAgICAvLyBUT0RPOiBSZW1vdmUgXCJvcmRpbmFsUGFyc2VcIiBmYWxsYmFjayBpbiBuZXh0IG1ham9yIHJlbGVhc2UuXG4gICAgICAgIHRoaXMuX2RheU9mTW9udGhPcmRpbmFsUGFyc2VMZW5pZW50ID0gbmV3IFJlZ0V4cChcbiAgICAgICAgICAgICh0aGlzLl9kYXlPZk1vbnRoT3JkaW5hbFBhcnNlLnNvdXJjZSB8fCB0aGlzLl9vcmRpbmFsUGFyc2Uuc291cmNlKSArXG4gICAgICAgICAgICAgICAgJ3wnICtcbiAgICAgICAgICAgICAgICAvXFxkezEsMn0vLnNvdXJjZVxuICAgICAgICApO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIG1lcmdlQ29uZmlncyhwYXJlbnRDb25maWcsIGNoaWxkQ29uZmlnKSB7XG4gICAgICAgIHZhciByZXMgPSBleHRlbmQoe30sIHBhcmVudENvbmZpZyksXG4gICAgICAgICAgICBwcm9wO1xuICAgICAgICBmb3IgKHByb3AgaW4gY2hpbGRDb25maWcpIHtcbiAgICAgICAgICAgIGlmIChoYXNPd25Qcm9wKGNoaWxkQ29uZmlnLCBwcm9wKSkge1xuICAgICAgICAgICAgICAgIGlmIChpc09iamVjdChwYXJlbnRDb25maWdbcHJvcF0pICYmIGlzT2JqZWN0KGNoaWxkQ29uZmlnW3Byb3BdKSkge1xuICAgICAgICAgICAgICAgICAgICByZXNbcHJvcF0gPSB7fTtcbiAgICAgICAgICAgICAgICAgICAgZXh0ZW5kKHJlc1twcm9wXSwgcGFyZW50Q29uZmlnW3Byb3BdKTtcbiAgICAgICAgICAgICAgICAgICAgZXh0ZW5kKHJlc1twcm9wXSwgY2hpbGRDb25maWdbcHJvcF0pO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoY2hpbGRDb25maWdbcHJvcF0gIT0gbnVsbCkge1xuICAgICAgICAgICAgICAgICAgICByZXNbcHJvcF0gPSBjaGlsZENvbmZpZ1twcm9wXTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBkZWxldGUgcmVzW3Byb3BdO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBmb3IgKHByb3AgaW4gcGFyZW50Q29uZmlnKSB7XG4gICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgaGFzT3duUHJvcChwYXJlbnRDb25maWcsIHByb3ApICYmXG4gICAgICAgICAgICAgICAgIWhhc093blByb3AoY2hpbGRDb25maWcsIHByb3ApICYmXG4gICAgICAgICAgICAgICAgaXNPYmplY3QocGFyZW50Q29uZmlnW3Byb3BdKVxuICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgLy8gbWFrZSBzdXJlIGNoYW5nZXMgdG8gcHJvcGVydGllcyBkb24ndCBtb2RpZnkgcGFyZW50IGNvbmZpZ1xuICAgICAgICAgICAgICAgIHJlc1twcm9wXSA9IGV4dGVuZCh7fSwgcmVzW3Byb3BdKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcmVzO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIExvY2FsZShjb25maWcpIHtcbiAgICAgICAgaWYgKGNvbmZpZyAhPSBudWxsKSB7XG4gICAgICAgICAgICB0aGlzLnNldChjb25maWcpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgdmFyIGtleXM7XG5cbiAgICBpZiAoT2JqZWN0LmtleXMpIHtcbiAgICAgICAga2V5cyA9IE9iamVjdC5rZXlzO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGtleXMgPSBmdW5jdGlvbiAob2JqKSB7XG4gICAgICAgICAgICB2YXIgaSxcbiAgICAgICAgICAgICAgICByZXMgPSBbXTtcbiAgICAgICAgICAgIGZvciAoaSBpbiBvYmopIHtcbiAgICAgICAgICAgICAgICBpZiAoaGFzT3duUHJvcChvYmosIGkpKSB7XG4gICAgICAgICAgICAgICAgICAgIHJlcy5wdXNoKGkpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiByZXM7XG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgdmFyIGRlZmF1bHRDYWxlbmRhciA9IHtcbiAgICAgICAgc2FtZURheTogJ1tUb2RheSBhdF0gTFQnLFxuICAgICAgICBuZXh0RGF5OiAnW1RvbW9ycm93IGF0XSBMVCcsXG4gICAgICAgIG5leHRXZWVrOiAnZGRkZCBbYXRdIExUJyxcbiAgICAgICAgbGFzdERheTogJ1tZZXN0ZXJkYXkgYXRdIExUJyxcbiAgICAgICAgbGFzdFdlZWs6ICdbTGFzdF0gZGRkZCBbYXRdIExUJyxcbiAgICAgICAgc2FtZUVsc2U6ICdMJyxcbiAgICB9O1xuXG4gICAgZnVuY3Rpb24gY2FsZW5kYXIoa2V5LCBtb20sIG5vdykge1xuICAgICAgICB2YXIgb3V0cHV0ID0gdGhpcy5fY2FsZW5kYXJba2V5XSB8fCB0aGlzLl9jYWxlbmRhclsnc2FtZUVsc2UnXTtcbiAgICAgICAgcmV0dXJuIGlzRnVuY3Rpb24ob3V0cHV0KSA/IG91dHB1dC5jYWxsKG1vbSwgbm93KSA6IG91dHB1dDtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiB6ZXJvRmlsbChudW1iZXIsIHRhcmdldExlbmd0aCwgZm9yY2VTaWduKSB7XG4gICAgICAgIHZhciBhYnNOdW1iZXIgPSAnJyArIE1hdGguYWJzKG51bWJlciksXG4gICAgICAgICAgICB6ZXJvc1RvRmlsbCA9IHRhcmdldExlbmd0aCAtIGFic051bWJlci5sZW5ndGgsXG4gICAgICAgICAgICBzaWduID0gbnVtYmVyID49IDA7XG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICAoc2lnbiA/IChmb3JjZVNpZ24gPyAnKycgOiAnJykgOiAnLScpICtcbiAgICAgICAgICAgIE1hdGgucG93KDEwLCBNYXRoLm1heCgwLCB6ZXJvc1RvRmlsbCkpLnRvU3RyaW5nKCkuc3Vic3RyKDEpICtcbiAgICAgICAgICAgIGFic051bWJlclxuICAgICAgICApO1xuICAgIH1cblxuICAgIHZhciBmb3JtYXR0aW5nVG9rZW5zID0gLyhcXFtbXlxcW10qXFxdKXwoXFxcXCk/KFtIaF1tbShzcyk/fE1vfE1NP00/TT98RG98REREb3xERD9EP0Q/fGRkZD9kP3xkbz98d1tvfHddP3xXW298V10/fFFvP3xOezEsNX18WVlZWVlZfFlZWVlZfFlZWVl8WVl8eXsyLDR9fHlvP3xnZyhnZ2c/KT98R0coR0dHPyk/fGV8RXxhfEF8aGg/fEhIP3xraz98bW0/fHNzP3xTezEsOX18eHxYfHp6P3xaWj98LikvZyxcbiAgICAgICAgbG9jYWxGb3JtYXR0aW5nVG9rZW5zID0gLyhcXFtbXlxcW10qXFxdKXwoXFxcXCk/KExUU3xMVHxMTD9MP0w/fGx7MSw0fSkvZyxcbiAgICAgICAgZm9ybWF0RnVuY3Rpb25zID0ge30sXG4gICAgICAgIGZvcm1hdFRva2VuRnVuY3Rpb25zID0ge307XG5cbiAgICAvLyB0b2tlbjogICAgJ00nXG4gICAgLy8gcGFkZGVkOiAgIFsnTU0nLCAyXVxuICAgIC8vIG9yZGluYWw6ICAnTW8nXG4gICAgLy8gY2FsbGJhY2s6IGZ1bmN0aW9uICgpIHsgdGhpcy5tb250aCgpICsgMSB9XG4gICAgZnVuY3Rpb24gYWRkRm9ybWF0VG9rZW4odG9rZW4sIHBhZGRlZCwgb3JkaW5hbCwgY2FsbGJhY2spIHtcbiAgICAgICAgdmFyIGZ1bmMgPSBjYWxsYmFjaztcbiAgICAgICAgaWYgKHR5cGVvZiBjYWxsYmFjayA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgIGZ1bmMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXNbY2FsbGJhY2tdKCk7XG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIGlmICh0b2tlbikge1xuICAgICAgICAgICAgZm9ybWF0VG9rZW5GdW5jdGlvbnNbdG9rZW5dID0gZnVuYztcbiAgICAgICAgfVxuICAgICAgICBpZiAocGFkZGVkKSB7XG4gICAgICAgICAgICBmb3JtYXRUb2tlbkZ1bmN0aW9uc1twYWRkZWRbMF1dID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB6ZXJvRmlsbChmdW5jLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyksIHBhZGRlZFsxXSwgcGFkZGVkWzJdKTtcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG9yZGluYWwpIHtcbiAgICAgICAgICAgIGZvcm1hdFRva2VuRnVuY3Rpb25zW29yZGluYWxdID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmxvY2FsZURhdGEoKS5vcmRpbmFsKFxuICAgICAgICAgICAgICAgICAgICBmdW5jLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyksXG4gICAgICAgICAgICAgICAgICAgIHRva2VuXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiByZW1vdmVGb3JtYXR0aW5nVG9rZW5zKGlucHV0KSB7XG4gICAgICAgIGlmIChpbnB1dC5tYXRjaCgvXFxbW1xcc1xcU10vKSkge1xuICAgICAgICAgICAgcmV0dXJuIGlucHV0LnJlcGxhY2UoL15cXFt8XFxdJC9nLCAnJyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGlucHV0LnJlcGxhY2UoL1xcXFwvZywgJycpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIG1ha2VGb3JtYXRGdW5jdGlvbihmb3JtYXQpIHtcbiAgICAgICAgdmFyIGFycmF5ID0gZm9ybWF0Lm1hdGNoKGZvcm1hdHRpbmdUb2tlbnMpLFxuICAgICAgICAgICAgaSxcbiAgICAgICAgICAgIGxlbmd0aDtcblxuICAgICAgICBmb3IgKGkgPSAwLCBsZW5ndGggPSBhcnJheS5sZW5ndGg7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgaWYgKGZvcm1hdFRva2VuRnVuY3Rpb25zW2FycmF5W2ldXSkge1xuICAgICAgICAgICAgICAgIGFycmF5W2ldID0gZm9ybWF0VG9rZW5GdW5jdGlvbnNbYXJyYXlbaV1dO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBhcnJheVtpXSA9IHJlbW92ZUZvcm1hdHRpbmdUb2tlbnMoYXJyYXlbaV0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGZ1bmN0aW9uIChtb20pIHtcbiAgICAgICAgICAgIHZhciBvdXRwdXQgPSAnJyxcbiAgICAgICAgICAgICAgICBpO1xuICAgICAgICAgICAgZm9yIChpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgb3V0cHV0ICs9IGlzRnVuY3Rpb24oYXJyYXlbaV0pXG4gICAgICAgICAgICAgICAgICAgID8gYXJyYXlbaV0uY2FsbChtb20sIGZvcm1hdClcbiAgICAgICAgICAgICAgICAgICAgOiBhcnJheVtpXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBvdXRwdXQ7XG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgLy8gZm9ybWF0IGRhdGUgdXNpbmcgbmF0aXZlIGRhdGUgb2JqZWN0XG4gICAgZnVuY3Rpb24gZm9ybWF0TW9tZW50KG0sIGZvcm1hdCkge1xuICAgICAgICBpZiAoIW0uaXNWYWxpZCgpKSB7XG4gICAgICAgICAgICByZXR1cm4gbS5sb2NhbGVEYXRhKCkuaW52YWxpZERhdGUoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGZvcm1hdCA9IGV4cGFuZEZvcm1hdChmb3JtYXQsIG0ubG9jYWxlRGF0YSgpKTtcbiAgICAgICAgZm9ybWF0RnVuY3Rpb25zW2Zvcm1hdF0gPVxuICAgICAgICAgICAgZm9ybWF0RnVuY3Rpb25zW2Zvcm1hdF0gfHwgbWFrZUZvcm1hdEZ1bmN0aW9uKGZvcm1hdCk7XG5cbiAgICAgICAgcmV0dXJuIGZvcm1hdEZ1bmN0aW9uc1tmb3JtYXRdKG0pO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGV4cGFuZEZvcm1hdChmb3JtYXQsIGxvY2FsZSkge1xuICAgICAgICB2YXIgaSA9IDU7XG5cbiAgICAgICAgZnVuY3Rpb24gcmVwbGFjZUxvbmdEYXRlRm9ybWF0VG9rZW5zKGlucHV0KSB7XG4gICAgICAgICAgICByZXR1cm4gbG9jYWxlLmxvbmdEYXRlRm9ybWF0KGlucHV0KSB8fCBpbnB1dDtcbiAgICAgICAgfVxuXG4gICAgICAgIGxvY2FsRm9ybWF0dGluZ1Rva2Vucy5sYXN0SW5kZXggPSAwO1xuICAgICAgICB3aGlsZSAoaSA+PSAwICYmIGxvY2FsRm9ybWF0dGluZ1Rva2Vucy50ZXN0KGZvcm1hdCkpIHtcbiAgICAgICAgICAgIGZvcm1hdCA9IGZvcm1hdC5yZXBsYWNlKFxuICAgICAgICAgICAgICAgIGxvY2FsRm9ybWF0dGluZ1Rva2VucyxcbiAgICAgICAgICAgICAgICByZXBsYWNlTG9uZ0RhdGVGb3JtYXRUb2tlbnNcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBsb2NhbEZvcm1hdHRpbmdUb2tlbnMubGFzdEluZGV4ID0gMDtcbiAgICAgICAgICAgIGkgLT0gMTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBmb3JtYXQ7XG4gICAgfVxuXG4gICAgdmFyIGRlZmF1bHRMb25nRGF0ZUZvcm1hdCA9IHtcbiAgICAgICAgTFRTOiAnaDptbTpzcyBBJyxcbiAgICAgICAgTFQ6ICdoOm1tIEEnLFxuICAgICAgICBMOiAnTU0vREQvWVlZWScsXG4gICAgICAgIExMOiAnTU1NTSBELCBZWVlZJyxcbiAgICAgICAgTExMOiAnTU1NTSBELCBZWVlZIGg6bW0gQScsXG4gICAgICAgIExMTEw6ICdkZGRkLCBNTU1NIEQsIFlZWVkgaDptbSBBJyxcbiAgICB9O1xuXG4gICAgZnVuY3Rpb24gbG9uZ0RhdGVGb3JtYXQoa2V5KSB7XG4gICAgICAgIHZhciBmb3JtYXQgPSB0aGlzLl9sb25nRGF0ZUZvcm1hdFtrZXldLFxuICAgICAgICAgICAgZm9ybWF0VXBwZXIgPSB0aGlzLl9sb25nRGF0ZUZvcm1hdFtrZXkudG9VcHBlckNhc2UoKV07XG5cbiAgICAgICAgaWYgKGZvcm1hdCB8fCAhZm9ybWF0VXBwZXIpIHtcbiAgICAgICAgICAgIHJldHVybiBmb3JtYXQ7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLl9sb25nRGF0ZUZvcm1hdFtrZXldID0gZm9ybWF0VXBwZXJcbiAgICAgICAgICAgIC5tYXRjaChmb3JtYXR0aW5nVG9rZW5zKVxuICAgICAgICAgICAgLm1hcChmdW5jdGlvbiAodG9rKSB7XG4gICAgICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgICAgICB0b2sgPT09ICdNTU1NJyB8fFxuICAgICAgICAgICAgICAgICAgICB0b2sgPT09ICdNTScgfHxcbiAgICAgICAgICAgICAgICAgICAgdG9rID09PSAnREQnIHx8XG4gICAgICAgICAgICAgICAgICAgIHRvayA9PT0gJ2RkZGQnXG4gICAgICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB0b2suc2xpY2UoMSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybiB0b2s7XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLmpvaW4oJycpO1xuXG4gICAgICAgIHJldHVybiB0aGlzLl9sb25nRGF0ZUZvcm1hdFtrZXldO1xuICAgIH1cblxuICAgIHZhciBkZWZhdWx0SW52YWxpZERhdGUgPSAnSW52YWxpZCBkYXRlJztcblxuICAgIGZ1bmN0aW9uIGludmFsaWREYXRlKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5faW52YWxpZERhdGU7XG4gICAgfVxuXG4gICAgdmFyIGRlZmF1bHRPcmRpbmFsID0gJyVkJyxcbiAgICAgICAgZGVmYXVsdERheU9mTW9udGhPcmRpbmFsUGFyc2UgPSAvXFxkezEsMn0vO1xuXG4gICAgZnVuY3Rpb24gb3JkaW5hbChudW1iZXIpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX29yZGluYWwucmVwbGFjZSgnJWQnLCBudW1iZXIpO1xuICAgIH1cblxuICAgIHZhciBkZWZhdWx0UmVsYXRpdmVUaW1lID0ge1xuICAgICAgICBmdXR1cmU6ICdpbiAlcycsXG4gICAgICAgIHBhc3Q6ICclcyBhZ28nLFxuICAgICAgICBzOiAnYSBmZXcgc2Vjb25kcycsXG4gICAgICAgIHNzOiAnJWQgc2Vjb25kcycsXG4gICAgICAgIG06ICdhIG1pbnV0ZScsXG4gICAgICAgIG1tOiAnJWQgbWludXRlcycsXG4gICAgICAgIGg6ICdhbiBob3VyJyxcbiAgICAgICAgaGg6ICclZCBob3VycycsXG4gICAgICAgIGQ6ICdhIGRheScsXG4gICAgICAgIGRkOiAnJWQgZGF5cycsXG4gICAgICAgIHc6ICdhIHdlZWsnLFxuICAgICAgICB3dzogJyVkIHdlZWtzJyxcbiAgICAgICAgTTogJ2EgbW9udGgnLFxuICAgICAgICBNTTogJyVkIG1vbnRocycsXG4gICAgICAgIHk6ICdhIHllYXInLFxuICAgICAgICB5eTogJyVkIHllYXJzJyxcbiAgICB9O1xuXG4gICAgZnVuY3Rpb24gcmVsYXRpdmVUaW1lKG51bWJlciwgd2l0aG91dFN1ZmZpeCwgc3RyaW5nLCBpc0Z1dHVyZSkge1xuICAgICAgICB2YXIgb3V0cHV0ID0gdGhpcy5fcmVsYXRpdmVUaW1lW3N0cmluZ107XG4gICAgICAgIHJldHVybiBpc0Z1bmN0aW9uKG91dHB1dClcbiAgICAgICAgICAgID8gb3V0cHV0KG51bWJlciwgd2l0aG91dFN1ZmZpeCwgc3RyaW5nLCBpc0Z1dHVyZSlcbiAgICAgICAgICAgIDogb3V0cHV0LnJlcGxhY2UoLyVkL2ksIG51bWJlcik7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gcGFzdEZ1dHVyZShkaWZmLCBvdXRwdXQpIHtcbiAgICAgICAgdmFyIGZvcm1hdCA9IHRoaXMuX3JlbGF0aXZlVGltZVtkaWZmID4gMCA/ICdmdXR1cmUnIDogJ3Bhc3QnXTtcbiAgICAgICAgcmV0dXJuIGlzRnVuY3Rpb24oZm9ybWF0KSA/IGZvcm1hdChvdXRwdXQpIDogZm9ybWF0LnJlcGxhY2UoLyVzL2ksIG91dHB1dCk7XG4gICAgfVxuXG4gICAgdmFyIGFsaWFzZXMgPSB7fTtcblxuICAgIGZ1bmN0aW9uIGFkZFVuaXRBbGlhcyh1bml0LCBzaG9ydGhhbmQpIHtcbiAgICAgICAgdmFyIGxvd2VyQ2FzZSA9IHVuaXQudG9Mb3dlckNhc2UoKTtcbiAgICAgICAgYWxpYXNlc1tsb3dlckNhc2VdID0gYWxpYXNlc1tsb3dlckNhc2UgKyAncyddID0gYWxpYXNlc1tzaG9ydGhhbmRdID0gdW5pdDtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBub3JtYWxpemVVbml0cyh1bml0cykge1xuICAgICAgICByZXR1cm4gdHlwZW9mIHVuaXRzID09PSAnc3RyaW5nJ1xuICAgICAgICAgICAgPyBhbGlhc2VzW3VuaXRzXSB8fCBhbGlhc2VzW3VuaXRzLnRvTG93ZXJDYXNlKCldXG4gICAgICAgICAgICA6IHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBub3JtYWxpemVPYmplY3RVbml0cyhpbnB1dE9iamVjdCkge1xuICAgICAgICB2YXIgbm9ybWFsaXplZElucHV0ID0ge30sXG4gICAgICAgICAgICBub3JtYWxpemVkUHJvcCxcbiAgICAgICAgICAgIHByb3A7XG5cbiAgICAgICAgZm9yIChwcm9wIGluIGlucHV0T2JqZWN0KSB7XG4gICAgICAgICAgICBpZiAoaGFzT3duUHJvcChpbnB1dE9iamVjdCwgcHJvcCkpIHtcbiAgICAgICAgICAgICAgICBub3JtYWxpemVkUHJvcCA9IG5vcm1hbGl6ZVVuaXRzKHByb3ApO1xuICAgICAgICAgICAgICAgIGlmIChub3JtYWxpemVkUHJvcCkge1xuICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkSW5wdXRbbm9ybWFsaXplZFByb3BdID0gaW5wdXRPYmplY3RbcHJvcF07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG5vcm1hbGl6ZWRJbnB1dDtcbiAgICB9XG5cbiAgICB2YXIgcHJpb3JpdGllcyA9IHt9O1xuXG4gICAgZnVuY3Rpb24gYWRkVW5pdFByaW9yaXR5KHVuaXQsIHByaW9yaXR5KSB7XG4gICAgICAgIHByaW9yaXRpZXNbdW5pdF0gPSBwcmlvcml0eTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBnZXRQcmlvcml0aXplZFVuaXRzKHVuaXRzT2JqKSB7XG4gICAgICAgIHZhciB1bml0cyA9IFtdLFxuICAgICAgICAgICAgdTtcbiAgICAgICAgZm9yICh1IGluIHVuaXRzT2JqKSB7XG4gICAgICAgICAgICBpZiAoaGFzT3duUHJvcCh1bml0c09iaiwgdSkpIHtcbiAgICAgICAgICAgICAgICB1bml0cy5wdXNoKHsgdW5pdDogdSwgcHJpb3JpdHk6IHByaW9yaXRpZXNbdV0gfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgdW5pdHMuc29ydChmdW5jdGlvbiAoYSwgYikge1xuICAgICAgICAgICAgcmV0dXJuIGEucHJpb3JpdHkgLSBiLnByaW9yaXR5O1xuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIHVuaXRzO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGlzTGVhcFllYXIoeWVhcikge1xuICAgICAgICByZXR1cm4gKHllYXIgJSA0ID09PSAwICYmIHllYXIgJSAxMDAgIT09IDApIHx8IHllYXIgJSA0MDAgPT09IDA7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gYWJzRmxvb3IobnVtYmVyKSB7XG4gICAgICAgIGlmIChudW1iZXIgPCAwKSB7XG4gICAgICAgICAgICAvLyAtMCAtPiAwXG4gICAgICAgICAgICByZXR1cm4gTWF0aC5jZWlsKG51bWJlcikgfHwgMDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBNYXRoLmZsb29yKG51bWJlcik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiB0b0ludChhcmd1bWVudEZvckNvZXJjaW9uKSB7XG4gICAgICAgIHZhciBjb2VyY2VkTnVtYmVyID0gK2FyZ3VtZW50Rm9yQ29lcmNpb24sXG4gICAgICAgICAgICB2YWx1ZSA9IDA7XG5cbiAgICAgICAgaWYgKGNvZXJjZWROdW1iZXIgIT09IDAgJiYgaXNGaW5pdGUoY29lcmNlZE51bWJlcikpIHtcbiAgICAgICAgICAgIHZhbHVlID0gYWJzRmxvb3IoY29lcmNlZE51bWJlcik7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdmFsdWU7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gbWFrZUdldFNldCh1bml0LCBrZWVwVGltZSkge1xuICAgICAgICByZXR1cm4gZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICBpZiAodmFsdWUgIT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIHNldCQxKHRoaXMsIHVuaXQsIHZhbHVlKTtcbiAgICAgICAgICAgICAgICBob29rcy51cGRhdGVPZmZzZXQodGhpcywga2VlcFRpbWUpO1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZ2V0KHRoaXMsIHVuaXQpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGdldChtb20sIHVuaXQpIHtcbiAgICAgICAgcmV0dXJuIG1vbS5pc1ZhbGlkKClcbiAgICAgICAgICAgID8gbW9tLl9kWydnZXQnICsgKG1vbS5faXNVVEMgPyAnVVRDJyA6ICcnKSArIHVuaXRdKClcbiAgICAgICAgICAgIDogTmFOO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHNldCQxKG1vbSwgdW5pdCwgdmFsdWUpIHtcbiAgICAgICAgaWYgKG1vbS5pc1ZhbGlkKCkgJiYgIWlzTmFOKHZhbHVlKSkge1xuICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgIHVuaXQgPT09ICdGdWxsWWVhcicgJiZcbiAgICAgICAgICAgICAgICBpc0xlYXBZZWFyKG1vbS55ZWFyKCkpICYmXG4gICAgICAgICAgICAgICAgbW9tLm1vbnRoKCkgPT09IDEgJiZcbiAgICAgICAgICAgICAgICBtb20uZGF0ZSgpID09PSAyOVxuICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgdmFsdWUgPSB0b0ludCh2YWx1ZSk7XG4gICAgICAgICAgICAgICAgbW9tLl9kWydzZXQnICsgKG1vbS5faXNVVEMgPyAnVVRDJyA6ICcnKSArIHVuaXRdKFxuICAgICAgICAgICAgICAgICAgICB2YWx1ZSxcbiAgICAgICAgICAgICAgICAgICAgbW9tLm1vbnRoKCksXG4gICAgICAgICAgICAgICAgICAgIGRheXNJbk1vbnRoKHZhbHVlLCBtb20ubW9udGgoKSlcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBtb20uX2RbJ3NldCcgKyAobW9tLl9pc1VUQyA/ICdVVEMnIDogJycpICsgdW5pdF0odmFsdWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gTU9NRU5UU1xuXG4gICAgZnVuY3Rpb24gc3RyaW5nR2V0KHVuaXRzKSB7XG4gICAgICAgIHVuaXRzID0gbm9ybWFsaXplVW5pdHModW5pdHMpO1xuICAgICAgICBpZiAoaXNGdW5jdGlvbih0aGlzW3VuaXRzXSkpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzW3VuaXRzXSgpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHN0cmluZ1NldCh1bml0cywgdmFsdWUpIHtcbiAgICAgICAgaWYgKHR5cGVvZiB1bml0cyA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgIHVuaXRzID0gbm9ybWFsaXplT2JqZWN0VW5pdHModW5pdHMpO1xuICAgICAgICAgICAgdmFyIHByaW9yaXRpemVkID0gZ2V0UHJpb3JpdGl6ZWRVbml0cyh1bml0cyksXG4gICAgICAgICAgICAgICAgaTtcbiAgICAgICAgICAgIGZvciAoaSA9IDA7IGkgPCBwcmlvcml0aXplZC5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIHRoaXNbcHJpb3JpdGl6ZWRbaV0udW5pdF0odW5pdHNbcHJpb3JpdGl6ZWRbaV0udW5pdF0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdW5pdHMgPSBub3JtYWxpemVVbml0cyh1bml0cyk7XG4gICAgICAgICAgICBpZiAoaXNGdW5jdGlvbih0aGlzW3VuaXRzXSkpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpc1t1bml0c10odmFsdWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIHZhciBtYXRjaDEgPSAvXFxkLywgLy8gICAgICAgMCAtIDlcbiAgICAgICAgbWF0Y2gyID0gL1xcZFxcZC8sIC8vICAgICAgMDAgLSA5OVxuICAgICAgICBtYXRjaDMgPSAvXFxkezN9LywgLy8gICAgIDAwMCAtIDk5OVxuICAgICAgICBtYXRjaDQgPSAvXFxkezR9LywgLy8gICAgMDAwMCAtIDk5OTlcbiAgICAgICAgbWF0Y2g2ID0gL1srLV0/XFxkezZ9LywgLy8gLTk5OTk5OSAtIDk5OTk5OVxuICAgICAgICBtYXRjaDF0bzIgPSAvXFxkXFxkPy8sIC8vICAgICAgIDAgLSA5OVxuICAgICAgICBtYXRjaDN0bzQgPSAvXFxkXFxkXFxkXFxkPy8sIC8vICAgICA5OTkgLSA5OTk5XG4gICAgICAgIG1hdGNoNXRvNiA9IC9cXGRcXGRcXGRcXGRcXGRcXGQ/LywgLy8gICA5OTk5OSAtIDk5OTk5OVxuICAgICAgICBtYXRjaDF0bzMgPSAvXFxkezEsM30vLCAvLyAgICAgICAwIC0gOTk5XG4gICAgICAgIG1hdGNoMXRvNCA9IC9cXGR7MSw0fS8sIC8vICAgICAgIDAgLSA5OTk5XG4gICAgICAgIG1hdGNoMXRvNiA9IC9bKy1dP1xcZHsxLDZ9LywgLy8gLTk5OTk5OSAtIDk5OTk5OVxuICAgICAgICBtYXRjaFVuc2lnbmVkID0gL1xcZCsvLCAvLyAgICAgICAwIC0gaW5mXG4gICAgICAgIG1hdGNoU2lnbmVkID0gL1srLV0/XFxkKy8sIC8vICAgIC1pbmYgLSBpbmZcbiAgICAgICAgbWF0Y2hPZmZzZXQgPSAvWnxbKy1dXFxkXFxkOj9cXGRcXGQvZ2ksIC8vICswMDowMCAtMDA6MDAgKzAwMDAgLTAwMDAgb3IgWlxuICAgICAgICBtYXRjaFNob3J0T2Zmc2V0ID0gL1p8WystXVxcZFxcZCg/Ojo/XFxkXFxkKT8vZ2ksIC8vICswMCAtMDAgKzAwOjAwIC0wMDowMCArMDAwMCAtMDAwMCBvciBaXG4gICAgICAgIG1hdGNoVGltZXN0YW1wID0gL1srLV0/XFxkKyhcXC5cXGR7MSwzfSk/LywgLy8gMTIzNDU2Nzg5IDEyMzQ1Njc4OS4xMjNcbiAgICAgICAgLy8gYW55IHdvcmQgKG9yIHR3bykgY2hhcmFjdGVycyBvciBudW1iZXJzIGluY2x1ZGluZyB0d28vdGhyZWUgd29yZCBtb250aCBpbiBhcmFiaWMuXG4gICAgICAgIC8vIGluY2x1ZGVzIHNjb3R0aXNoIGdhZWxpYyB0d28gd29yZCBhbmQgaHlwaGVuYXRlZCBtb250aHNcbiAgICAgICAgbWF0Y2hXb3JkID0gL1swLTldezAsMjU2fVsnYS16XFx1MDBBMC1cXHUwNUZGXFx1MDcwMC1cXHVEN0ZGXFx1RjkwMC1cXHVGRENGXFx1RkRGMC1cXHVGRjA3XFx1RkYxMC1cXHVGRkVGXXsxLDI1Nn18W1xcdTA2MDAtXFx1MDZGRlxcL117MSwyNTZ9KFxccyo/W1xcdTA2MDAtXFx1MDZGRl17MSwyNTZ9KXsxLDJ9L2ksXG4gICAgICAgIHJlZ2V4ZXM7XG5cbiAgICByZWdleGVzID0ge307XG5cbiAgICBmdW5jdGlvbiBhZGRSZWdleFRva2VuKHRva2VuLCByZWdleCwgc3RyaWN0UmVnZXgpIHtcbiAgICAgICAgcmVnZXhlc1t0b2tlbl0gPSBpc0Z1bmN0aW9uKHJlZ2V4KVxuICAgICAgICAgICAgPyByZWdleFxuICAgICAgICAgICAgOiBmdW5jdGlvbiAoaXNTdHJpY3QsIGxvY2FsZURhdGEpIHtcbiAgICAgICAgICAgICAgICAgIHJldHVybiBpc1N0cmljdCAmJiBzdHJpY3RSZWdleCA/IHN0cmljdFJlZ2V4IDogcmVnZXg7XG4gICAgICAgICAgICAgIH07XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gZ2V0UGFyc2VSZWdleEZvclRva2VuKHRva2VuLCBjb25maWcpIHtcbiAgICAgICAgaWYgKCFoYXNPd25Qcm9wKHJlZ2V4ZXMsIHRva2VuKSkge1xuICAgICAgICAgICAgcmV0dXJuIG5ldyBSZWdFeHAodW5lc2NhcGVGb3JtYXQodG9rZW4pKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiByZWdleGVzW3Rva2VuXShjb25maWcuX3N0cmljdCwgY29uZmlnLl9sb2NhbGUpO1xuICAgIH1cblxuICAgIC8vIENvZGUgZnJvbSBodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzM1NjE0OTMvaXMtdGhlcmUtYS1yZWdleHAtZXNjYXBlLWZ1bmN0aW9uLWluLWphdmFzY3JpcHRcbiAgICBmdW5jdGlvbiB1bmVzY2FwZUZvcm1hdChzKSB7XG4gICAgICAgIHJldHVybiByZWdleEVzY2FwZShcbiAgICAgICAgICAgIHNcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgnXFxcXCcsICcnKVxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC9cXFxcKFxcWyl8XFxcXChcXF0pfFxcWyhbXlxcXVxcW10qKVxcXXxcXFxcKC4pL2csIGZ1bmN0aW9uIChcbiAgICAgICAgICAgICAgICAgICAgbWF0Y2hlZCxcbiAgICAgICAgICAgICAgICAgICAgcDEsXG4gICAgICAgICAgICAgICAgICAgIHAyLFxuICAgICAgICAgICAgICAgICAgICBwMyxcbiAgICAgICAgICAgICAgICAgICAgcDRcbiAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHAxIHx8IHAyIHx8IHAzIHx8IHA0O1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gcmVnZXhFc2NhcGUocykge1xuICAgICAgICByZXR1cm4gcy5yZXBsYWNlKC9bLVxcL1xcXFxeJCorPy4oKXxbXFxde31dL2csICdcXFxcJCYnKTtcbiAgICB9XG5cbiAgICB2YXIgdG9rZW5zID0ge307XG5cbiAgICBmdW5jdGlvbiBhZGRQYXJzZVRva2VuKHRva2VuLCBjYWxsYmFjaykge1xuICAgICAgICB2YXIgaSxcbiAgICAgICAgICAgIGZ1bmMgPSBjYWxsYmFjaztcbiAgICAgICAgaWYgKHR5cGVvZiB0b2tlbiA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgIHRva2VuID0gW3Rva2VuXTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoaXNOdW1iZXIoY2FsbGJhY2spKSB7XG4gICAgICAgICAgICBmdW5jID0gZnVuY3Rpb24gKGlucHV0LCBhcnJheSkge1xuICAgICAgICAgICAgICAgIGFycmF5W2NhbGxiYWNrXSA9IHRvSW50KGlucHV0KTtcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgZm9yIChpID0gMDsgaSA8IHRva2VuLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICB0b2tlbnNbdG9rZW5baV1dID0gZnVuYztcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIGFkZFdlZWtQYXJzZVRva2VuKHRva2VuLCBjYWxsYmFjaykge1xuICAgICAgICBhZGRQYXJzZVRva2VuKHRva2VuLCBmdW5jdGlvbiAoaW5wdXQsIGFycmF5LCBjb25maWcsIHRva2VuKSB7XG4gICAgICAgICAgICBjb25maWcuX3cgPSBjb25maWcuX3cgfHwge307XG4gICAgICAgICAgICBjYWxsYmFjayhpbnB1dCwgY29uZmlnLl93LCBjb25maWcsIHRva2VuKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gYWRkVGltZVRvQXJyYXlGcm9tVG9rZW4odG9rZW4sIGlucHV0LCBjb25maWcpIHtcbiAgICAgICAgaWYgKGlucHV0ICE9IG51bGwgJiYgaGFzT3duUHJvcCh0b2tlbnMsIHRva2VuKSkge1xuICAgICAgICAgICAgdG9rZW5zW3Rva2VuXShpbnB1dCwgY29uZmlnLl9hLCBjb25maWcsIHRva2VuKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHZhciBZRUFSID0gMCxcbiAgICAgICAgTU9OVEggPSAxLFxuICAgICAgICBEQVRFID0gMixcbiAgICAgICAgSE9VUiA9IDMsXG4gICAgICAgIE1JTlVURSA9IDQsXG4gICAgICAgIFNFQ09ORCA9IDUsXG4gICAgICAgIE1JTExJU0VDT05EID0gNixcbiAgICAgICAgV0VFSyA9IDcsXG4gICAgICAgIFdFRUtEQVkgPSA4O1xuXG4gICAgZnVuY3Rpb24gbW9kKG4sIHgpIHtcbiAgICAgICAgcmV0dXJuICgobiAlIHgpICsgeCkgJSB4O1xuICAgIH1cblxuICAgIHZhciBpbmRleE9mO1xuXG4gICAgaWYgKEFycmF5LnByb3RvdHlwZS5pbmRleE9mKSB7XG4gICAgICAgIGluZGV4T2YgPSBBcnJheS5wcm90b3R5cGUuaW5kZXhPZjtcbiAgICB9IGVsc2Uge1xuICAgICAgICBpbmRleE9mID0gZnVuY3Rpb24gKG8pIHtcbiAgICAgICAgICAgIC8vIEkga25vd1xuICAgICAgICAgICAgdmFyIGk7XG4gICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwgdGhpcy5sZW5ndGg7ICsraSkge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzW2ldID09PSBvKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiAtMTtcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBkYXlzSW5Nb250aCh5ZWFyLCBtb250aCkge1xuICAgICAgICBpZiAoaXNOYU4oeWVhcikgfHwgaXNOYU4obW9udGgpKSB7XG4gICAgICAgICAgICByZXR1cm4gTmFOO1xuICAgICAgICB9XG4gICAgICAgIHZhciBtb2RNb250aCA9IG1vZChtb250aCwgMTIpO1xuICAgICAgICB5ZWFyICs9IChtb250aCAtIG1vZE1vbnRoKSAvIDEyO1xuICAgICAgICByZXR1cm4gbW9kTW9udGggPT09IDFcbiAgICAgICAgICAgID8gaXNMZWFwWWVhcih5ZWFyKVxuICAgICAgICAgICAgICAgID8gMjlcbiAgICAgICAgICAgICAgICA6IDI4XG4gICAgICAgICAgICA6IDMxIC0gKChtb2RNb250aCAlIDcpICUgMik7XG4gICAgfVxuXG4gICAgLy8gRk9STUFUVElOR1xuXG4gICAgYWRkRm9ybWF0VG9rZW4oJ00nLCBbJ01NJywgMl0sICdNbycsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubW9udGgoKSArIDE7XG4gICAgfSk7XG5cbiAgICBhZGRGb3JtYXRUb2tlbignTU1NJywgMCwgMCwgZnVuY3Rpb24gKGZvcm1hdCkge1xuICAgICAgICByZXR1cm4gdGhpcy5sb2NhbGVEYXRhKCkubW9udGhzU2hvcnQodGhpcywgZm9ybWF0KTtcbiAgICB9KTtcblxuICAgIGFkZEZvcm1hdFRva2VuKCdNTU1NJywgMCwgMCwgZnVuY3Rpb24gKGZvcm1hdCkge1xuICAgICAgICByZXR1cm4gdGhpcy5sb2NhbGVEYXRhKCkubW9udGhzKHRoaXMsIGZvcm1hdCk7XG4gICAgfSk7XG5cbiAgICAvLyBBTElBU0VTXG5cbiAgICBhZGRVbml0QWxpYXMoJ21vbnRoJywgJ00nKTtcblxuICAgIC8vIFBSSU9SSVRZXG5cbiAgICBhZGRVbml0UHJpb3JpdHkoJ21vbnRoJywgOCk7XG5cbiAgICAvLyBQQVJTSU5HXG5cbiAgICBhZGRSZWdleFRva2VuKCdNJywgbWF0Y2gxdG8yKTtcbiAgICBhZGRSZWdleFRva2VuKCdNTScsIG1hdGNoMXRvMiwgbWF0Y2gyKTtcbiAgICBhZGRSZWdleFRva2VuKCdNTU0nLCBmdW5jdGlvbiAoaXNTdHJpY3QsIGxvY2FsZSkge1xuICAgICAgICByZXR1cm4gbG9jYWxlLm1vbnRoc1Nob3J0UmVnZXgoaXNTdHJpY3QpO1xuICAgIH0pO1xuICAgIGFkZFJlZ2V4VG9rZW4oJ01NTU0nLCBmdW5jdGlvbiAoaXNTdHJpY3QsIGxvY2FsZSkge1xuICAgICAgICByZXR1cm4gbG9jYWxlLm1vbnRoc1JlZ2V4KGlzU3RyaWN0KTtcbiAgICB9KTtcblxuICAgIGFkZFBhcnNlVG9rZW4oWydNJywgJ01NJ10sIGZ1bmN0aW9uIChpbnB1dCwgYXJyYXkpIHtcbiAgICAgICAgYXJyYXlbTU9OVEhdID0gdG9JbnQoaW5wdXQpIC0gMTtcbiAgICB9KTtcblxuICAgIGFkZFBhcnNlVG9rZW4oWydNTU0nLCAnTU1NTSddLCBmdW5jdGlvbiAoaW5wdXQsIGFycmF5LCBjb25maWcsIHRva2VuKSB7XG4gICAgICAgIHZhciBtb250aCA9IGNvbmZpZy5fbG9jYWxlLm1vbnRoc1BhcnNlKGlucHV0LCB0b2tlbiwgY29uZmlnLl9zdHJpY3QpO1xuICAgICAgICAvLyBpZiB3ZSBkaWRuJ3QgZmluZCBhIG1vbnRoIG5hbWUsIG1hcmsgdGhlIGRhdGUgYXMgaW52YWxpZC5cbiAgICAgICAgaWYgKG1vbnRoICE9IG51bGwpIHtcbiAgICAgICAgICAgIGFycmF5W01PTlRIXSA9IG1vbnRoO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZ2V0UGFyc2luZ0ZsYWdzKGNvbmZpZykuaW52YWxpZE1vbnRoID0gaW5wdXQ7XG4gICAgICAgIH1cbiAgICB9KTtcblxuICAgIC8vIExPQ0FMRVNcblxuICAgIHZhciBkZWZhdWx0TG9jYWxlTW9udGhzID0gJ0phbnVhcnlfRmVicnVhcnlfTWFyY2hfQXByaWxfTWF5X0p1bmVfSnVseV9BdWd1c3RfU2VwdGVtYmVyX09jdG9iZXJfTm92ZW1iZXJfRGVjZW1iZXInLnNwbGl0KFxuICAgICAgICAgICAgJ18nXG4gICAgICAgICksXG4gICAgICAgIGRlZmF1bHRMb2NhbGVNb250aHNTaG9ydCA9ICdKYW5fRmViX01hcl9BcHJfTWF5X0p1bl9KdWxfQXVnX1NlcF9PY3RfTm92X0RlYycuc3BsaXQoXG4gICAgICAgICAgICAnXydcbiAgICAgICAgKSxcbiAgICAgICAgTU9OVEhTX0lOX0ZPUk1BVCA9IC9EW29EXT8oXFxbW15cXFtcXF1dKlxcXXxcXHMpK01NTU0/LyxcbiAgICAgICAgZGVmYXVsdE1vbnRoc1Nob3J0UmVnZXggPSBtYXRjaFdvcmQsXG4gICAgICAgIGRlZmF1bHRNb250aHNSZWdleCA9IG1hdGNoV29yZDtcblxuICAgIGZ1bmN0aW9uIGxvY2FsZU1vbnRocyhtLCBmb3JtYXQpIHtcbiAgICAgICAgaWYgKCFtKSB7XG4gICAgICAgICAgICByZXR1cm4gaXNBcnJheSh0aGlzLl9tb250aHMpXG4gICAgICAgICAgICAgICAgPyB0aGlzLl9tb250aHNcbiAgICAgICAgICAgICAgICA6IHRoaXMuX21vbnRoc1snc3RhbmRhbG9uZSddO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBpc0FycmF5KHRoaXMuX21vbnRocylcbiAgICAgICAgICAgID8gdGhpcy5fbW9udGhzW20ubW9udGgoKV1cbiAgICAgICAgICAgIDogdGhpcy5fbW9udGhzW1xuICAgICAgICAgICAgICAgICAgKHRoaXMuX21vbnRocy5pc0Zvcm1hdCB8fCBNT05USFNfSU5fRk9STUFUKS50ZXN0KGZvcm1hdClcbiAgICAgICAgICAgICAgICAgICAgICA/ICdmb3JtYXQnXG4gICAgICAgICAgICAgICAgICAgICAgOiAnc3RhbmRhbG9uZSdcbiAgICAgICAgICAgICAgXVttLm1vbnRoKCldO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGxvY2FsZU1vbnRoc1Nob3J0KG0sIGZvcm1hdCkge1xuICAgICAgICBpZiAoIW0pIHtcbiAgICAgICAgICAgIHJldHVybiBpc0FycmF5KHRoaXMuX21vbnRoc1Nob3J0KVxuICAgICAgICAgICAgICAgID8gdGhpcy5fbW9udGhzU2hvcnRcbiAgICAgICAgICAgICAgICA6IHRoaXMuX21vbnRoc1Nob3J0WydzdGFuZGFsb25lJ107XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGlzQXJyYXkodGhpcy5fbW9udGhzU2hvcnQpXG4gICAgICAgICAgICA/IHRoaXMuX21vbnRoc1Nob3J0W20ubW9udGgoKV1cbiAgICAgICAgICAgIDogdGhpcy5fbW9udGhzU2hvcnRbXG4gICAgICAgICAgICAgICAgICBNT05USFNfSU5fRk9STUFULnRlc3QoZm9ybWF0KSA/ICdmb3JtYXQnIDogJ3N0YW5kYWxvbmUnXG4gICAgICAgICAgICAgIF1bbS5tb250aCgpXTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBoYW5kbGVTdHJpY3RQYXJzZShtb250aE5hbWUsIGZvcm1hdCwgc3RyaWN0KSB7XG4gICAgICAgIHZhciBpLFxuICAgICAgICAgICAgaWksXG4gICAgICAgICAgICBtb20sXG4gICAgICAgICAgICBsbGMgPSBtb250aE5hbWUudG9Mb2NhbGVMb3dlckNhc2UoKTtcbiAgICAgICAgaWYgKCF0aGlzLl9tb250aHNQYXJzZSkge1xuICAgICAgICAgICAgLy8gdGhpcyBpcyBub3QgdXNlZFxuICAgICAgICAgICAgdGhpcy5fbW9udGhzUGFyc2UgPSBbXTtcbiAgICAgICAgICAgIHRoaXMuX2xvbmdNb250aHNQYXJzZSA9IFtdO1xuICAgICAgICAgICAgdGhpcy5fc2hvcnRNb250aHNQYXJzZSA9IFtdO1xuICAgICAgICAgICAgZm9yIChpID0gMDsgaSA8IDEyOyArK2kpIHtcbiAgICAgICAgICAgICAgICBtb20gPSBjcmVhdGVVVEMoWzIwMDAsIGldKTtcbiAgICAgICAgICAgICAgICB0aGlzLl9zaG9ydE1vbnRoc1BhcnNlW2ldID0gdGhpcy5tb250aHNTaG9ydChcbiAgICAgICAgICAgICAgICAgICAgbW9tLFxuICAgICAgICAgICAgICAgICAgICAnJ1xuICAgICAgICAgICAgICAgICkudG9Mb2NhbGVMb3dlckNhc2UoKTtcbiAgICAgICAgICAgICAgICB0aGlzLl9sb25nTW9udGhzUGFyc2VbaV0gPSB0aGlzLm1vbnRocyhtb20sICcnKS50b0xvY2FsZUxvd2VyQ2FzZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHN0cmljdCkge1xuICAgICAgICAgICAgaWYgKGZvcm1hdCA9PT0gJ01NTScpIHtcbiAgICAgICAgICAgICAgICBpaSA9IGluZGV4T2YuY2FsbCh0aGlzLl9zaG9ydE1vbnRoc1BhcnNlLCBsbGMpO1xuICAgICAgICAgICAgICAgIHJldHVybiBpaSAhPT0gLTEgPyBpaSA6IG51bGw7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGlpID0gaW5kZXhPZi5jYWxsKHRoaXMuX2xvbmdNb250aHNQYXJzZSwgbGxjKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gaWkgIT09IC0xID8gaWkgOiBudWxsO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaWYgKGZvcm1hdCA9PT0gJ01NTScpIHtcbiAgICAgICAgICAgICAgICBpaSA9IGluZGV4T2YuY2FsbCh0aGlzLl9zaG9ydE1vbnRoc1BhcnNlLCBsbGMpO1xuICAgICAgICAgICAgICAgIGlmIChpaSAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGlpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpaSA9IGluZGV4T2YuY2FsbCh0aGlzLl9sb25nTW9udGhzUGFyc2UsIGxsYyk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGlpICE9PSAtMSA/IGlpIDogbnVsbDtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgaWkgPSBpbmRleE9mLmNhbGwodGhpcy5fbG9uZ01vbnRoc1BhcnNlLCBsbGMpO1xuICAgICAgICAgICAgICAgIGlmIChpaSAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGlpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpaSA9IGluZGV4T2YuY2FsbCh0aGlzLl9zaG9ydE1vbnRoc1BhcnNlLCBsbGMpO1xuICAgICAgICAgICAgICAgIHJldHVybiBpaSAhPT0gLTEgPyBpaSA6IG51bGw7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiBsb2NhbGVNb250aHNQYXJzZShtb250aE5hbWUsIGZvcm1hdCwgc3RyaWN0KSB7XG4gICAgICAgIHZhciBpLCBtb20sIHJlZ2V4O1xuXG4gICAgICAgIGlmICh0aGlzLl9tb250aHNQYXJzZUV4YWN0KSB7XG4gICAgICAgICAgICByZXR1cm4gaGFuZGxlU3RyaWN0UGFyc2UuY2FsbCh0aGlzLCBtb250aE5hbWUsIGZvcm1hdCwgc3RyaWN0KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghdGhpcy5fbW9udGhzUGFyc2UpIHtcbiAgICAgICAgICAgIHRoaXMuX21vbnRoc1BhcnNlID0gW107XG4gICAgICAgICAgICB0aGlzLl9sb25nTW9udGhzUGFyc2UgPSBbXTtcbiAgICAgICAgICAgIHRoaXMuX3Nob3J0TW9udGhzUGFyc2UgPSBbXTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFRPRE86IGFkZCBzb3J0aW5nXG4gICAgICAgIC8vIFNvcnRpbmcgbWFrZXMgc3VyZSBpZiBvbmUgbW9udGggKG9yIGFiYnIpIGlzIGEgcHJlZml4IG9mIGFub3RoZXJcbiAgICAgICAgLy8gc2VlIHNvcnRpbmcgaW4gY29tcHV0ZU1vbnRoc1BhcnNlXG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCAxMjsgaSsrKSB7XG4gICAgICAgICAgICAvLyBtYWtlIHRoZSByZWdleCBpZiB3ZSBkb24ndCBoYXZlIGl0IGFscmVhZHlcbiAgICAgICAgICAgIG1vbSA9IGNyZWF0ZVVUQyhbMjAwMCwgaV0pO1xuICAgICAgICAgICAgaWYgKHN0cmljdCAmJiAhdGhpcy5fbG9uZ01vbnRoc1BhcnNlW2ldKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5fbG9uZ01vbnRoc1BhcnNlW2ldID0gbmV3IFJlZ0V4cChcbiAgICAgICAgICAgICAgICAgICAgJ14nICsgdGhpcy5tb250aHMobW9tLCAnJykucmVwbGFjZSgnLicsICcnKSArICckJyxcbiAgICAgICAgICAgICAgICAgICAgJ2knXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB0aGlzLl9zaG9ydE1vbnRoc1BhcnNlW2ldID0gbmV3IFJlZ0V4cChcbiAgICAgICAgICAgICAgICAgICAgJ14nICsgdGhpcy5tb250aHNTaG9ydChtb20sICcnKS5yZXBsYWNlKCcuJywgJycpICsgJyQnLFxuICAgICAgICAgICAgICAgICAgICAnaSdcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFzdHJpY3QgJiYgIXRoaXMuX21vbnRoc1BhcnNlW2ldKSB7XG4gICAgICAgICAgICAgICAgcmVnZXggPVxuICAgICAgICAgICAgICAgICAgICAnXicgKyB0aGlzLm1vbnRocyhtb20sICcnKSArICd8XicgKyB0aGlzLm1vbnRoc1Nob3J0KG1vbSwgJycpO1xuICAgICAgICAgICAgICAgIHRoaXMuX21vbnRoc1BhcnNlW2ldID0gbmV3IFJlZ0V4cChyZWdleC5yZXBsYWNlKCcuJywgJycpLCAnaScpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gdGVzdCB0aGUgcmVnZXhcbiAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICBzdHJpY3QgJiZcbiAgICAgICAgICAgICAgICBmb3JtYXQgPT09ICdNTU1NJyAmJlxuICAgICAgICAgICAgICAgIHRoaXMuX2xvbmdNb250aHNQYXJzZVtpXS50ZXN0KG1vbnRoTmFtZSlcbiAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgIHJldHVybiBpO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChcbiAgICAgICAgICAgICAgICBzdHJpY3QgJiZcbiAgICAgICAgICAgICAgICBmb3JtYXQgPT09ICdNTU0nICYmXG4gICAgICAgICAgICAgICAgdGhpcy5fc2hvcnRNb250aHNQYXJzZVtpXS50ZXN0KG1vbnRoTmFtZSlcbiAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgIHJldHVybiBpO1xuICAgICAgICAgICAgfSBlbHNlIGlmICghc3RyaWN0ICYmIHRoaXMuX21vbnRoc1BhcnNlW2ldLnRlc3QobW9udGhOYW1lKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gTU9NRU5UU1xuXG4gICAgZnVuY3Rpb24gc2V0TW9udGgobW9tLCB2YWx1ZSkge1xuICAgICAgICB2YXIgZGF5T2ZNb250aDtcblxuICAgICAgICBpZiAoIW1vbS5pc1ZhbGlkKCkpIHtcbiAgICAgICAgICAgIC8vIE5vIG9wXG4gICAgICAgICAgICByZXR1cm4gbW9tO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgIGlmICgvXlxcZCskLy50ZXN0KHZhbHVlKSkge1xuICAgICAgICAgICAgICAgIHZhbHVlID0gdG9JbnQodmFsdWUpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB2YWx1ZSA9IG1vbS5sb2NhbGVEYXRhKCkubW9udGhzUGFyc2UodmFsdWUpO1xuICAgICAgICAgICAgICAgIC8vIFRPRE86IEFub3RoZXIgc2lsZW50IGZhaWx1cmU/XG4gICAgICAgICAgICAgICAgaWYgKCFpc051bWJlcih2YWx1ZSkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG1vbTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBkYXlPZk1vbnRoID0gTWF0aC5taW4obW9tLmRhdGUoKSwgZGF5c0luTW9udGgobW9tLnllYXIoKSwgdmFsdWUpKTtcbiAgICAgICAgbW9tLl9kWydzZXQnICsgKG1vbS5faXNVVEMgPyAnVVRDJyA6ICcnKSArICdNb250aCddKHZhbHVlLCBkYXlPZk1vbnRoKTtcbiAgICAgICAgcmV0dXJuIG1vbTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBnZXRTZXRNb250aCh2YWx1ZSkge1xuICAgICAgICBpZiAodmFsdWUgIT0gbnVsbCkge1xuICAgICAgICAgICAgc2V0TW9udGgodGhpcywgdmFsdWUpO1xuICAgICAgICAgICAgaG9va3MudXBkYXRlT2Zmc2V0KHRoaXMsIHRydWUpO1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gZ2V0KHRoaXMsICdNb250aCcpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gZ2V0RGF5c0luTW9udGgoKSB7XG4gICAgICAgIHJldHVybiBkYXlzSW5Nb250aCh0aGlzLnllYXIoKSwgdGhpcy5tb250aCgpKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBtb250aHNTaG9ydFJlZ2V4KGlzU3RyaWN0KSB7XG4gICAgICAgIGlmICh0aGlzLl9tb250aHNQYXJzZUV4YWN0KSB7XG4gICAgICAgICAgICBpZiAoIWhhc093blByb3AodGhpcywgJ19tb250aHNSZWdleCcpKSB7XG4gICAgICAgICAgICAgICAgY29tcHV0ZU1vbnRoc1BhcnNlLmNhbGwodGhpcyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoaXNTdHJpY3QpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5fbW9udGhzU2hvcnRTdHJpY3RSZWdleDtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuX21vbnRoc1Nob3J0UmVnZXg7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBpZiAoIWhhc093blByb3AodGhpcywgJ19tb250aHNTaG9ydFJlZ2V4JykpIHtcbiAgICAgICAgICAgICAgICB0aGlzLl9tb250aHNTaG9ydFJlZ2V4ID0gZGVmYXVsdE1vbnRoc1Nob3J0UmVnZXg7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fbW9udGhzU2hvcnRTdHJpY3RSZWdleCAmJiBpc1N0cmljdFxuICAgICAgICAgICAgICAgID8gdGhpcy5fbW9udGhzU2hvcnRTdHJpY3RSZWdleFxuICAgICAgICAgICAgICAgIDogdGhpcy5fbW9udGhzU2hvcnRSZWdleDtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIG1vbnRoc1JlZ2V4KGlzU3RyaWN0KSB7XG4gICAgICAgIGlmICh0aGlzLl9tb250aHNQYXJzZUV4YWN0KSB7XG4gICAgICAgICAgICBpZiAoIWhhc093blByb3AodGhpcywgJ19tb250aHNSZWdleCcpKSB7XG4gICAgICAgICAgICAgICAgY29tcHV0ZU1vbnRoc1BhcnNlLmNhbGwodGhpcyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoaXNTdHJpY3QpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5fbW9udGhzU3RyaWN0UmVnZXg7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLl9tb250aHNSZWdleDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGlmICghaGFzT3duUHJvcCh0aGlzLCAnX21vbnRoc1JlZ2V4JykpIHtcbiAgICAgICAgICAgICAgICB0aGlzLl9tb250aHNSZWdleCA9IGRlZmF1bHRNb250aHNSZWdleDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9tb250aHNTdHJpY3RSZWdleCAmJiBpc1N0cmljdFxuICAgICAgICAgICAgICAgID8gdGhpcy5fbW9udGhzU3RyaWN0UmVnZXhcbiAgICAgICAgICAgICAgICA6IHRoaXMuX21vbnRoc1JlZ2V4O1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gY29tcHV0ZU1vbnRoc1BhcnNlKCkge1xuICAgICAgICBmdW5jdGlvbiBjbXBMZW5SZXYoYSwgYikge1xuICAgICAgICAgICAgcmV0dXJuIGIubGVuZ3RoIC0gYS5sZW5ndGg7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgc2hvcnRQaWVjZXMgPSBbXSxcbiAgICAgICAgICAgIGxvbmdQaWVjZXMgPSBbXSxcbiAgICAgICAgICAgIG1peGVkUGllY2VzID0gW10sXG4gICAgICAgICAgICBpLFxuICAgICAgICAgICAgbW9tO1xuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgMTI7IGkrKykge1xuICAgICAgICAgICAgLy8gbWFrZSB0aGUgcmVnZXggaWYgd2UgZG9uJ3QgaGF2ZSBpdCBhbHJlYWR5XG4gICAgICAgICAgICBtb20gPSBjcmVhdGVVVEMoWzIwMDAsIGldKTtcbiAgICAgICAgICAgIHNob3J0UGllY2VzLnB1c2godGhpcy5tb250aHNTaG9ydChtb20sICcnKSk7XG4gICAgICAgICAgICBsb25nUGllY2VzLnB1c2godGhpcy5tb250aHMobW9tLCAnJykpO1xuICAgICAgICAgICAgbWl4ZWRQaWVjZXMucHVzaCh0aGlzLm1vbnRocyhtb20sICcnKSk7XG4gICAgICAgICAgICBtaXhlZFBpZWNlcy5wdXNoKHRoaXMubW9udGhzU2hvcnQobW9tLCAnJykpO1xuICAgICAgICB9XG4gICAgICAgIC8vIFNvcnRpbmcgbWFrZXMgc3VyZSBpZiBvbmUgbW9udGggKG9yIGFiYnIpIGlzIGEgcHJlZml4IG9mIGFub3RoZXIgaXRcbiAgICAgICAgLy8gd2lsbCBtYXRjaCB0aGUgbG9uZ2VyIHBpZWNlLlxuICAgICAgICBzaG9ydFBpZWNlcy5zb3J0KGNtcExlblJldik7XG4gICAgICAgIGxvbmdQaWVjZXMuc29ydChjbXBMZW5SZXYpO1xuICAgICAgICBtaXhlZFBpZWNlcy5zb3J0KGNtcExlblJldik7XG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCAxMjsgaSsrKSB7XG4gICAgICAgICAgICBzaG9ydFBpZWNlc1tpXSA9IHJlZ2V4RXNjYXBlKHNob3J0UGllY2VzW2ldKTtcbiAgICAgICAgICAgIGxvbmdQaWVjZXNbaV0gPSByZWdleEVzY2FwZShsb25nUGllY2VzW2ldKTtcbiAgICAgICAgfVxuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgMjQ7IGkrKykge1xuICAgICAgICAgICAgbWl4ZWRQaWVjZXNbaV0gPSByZWdleEVzY2FwZShtaXhlZFBpZWNlc1tpXSk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLl9tb250aHNSZWdleCA9IG5ldyBSZWdFeHAoJ14oJyArIG1peGVkUGllY2VzLmpvaW4oJ3wnKSArICcpJywgJ2knKTtcbiAgICAgICAgdGhpcy5fbW9udGhzU2hvcnRSZWdleCA9IHRoaXMuX21vbnRoc1JlZ2V4O1xuICAgICAgICB0aGlzLl9tb250aHNTdHJpY3RSZWdleCA9IG5ldyBSZWdFeHAoXG4gICAgICAgICAgICAnXignICsgbG9uZ1BpZWNlcy5qb2luKCd8JykgKyAnKScsXG4gICAgICAgICAgICAnaSdcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5fbW9udGhzU2hvcnRTdHJpY3RSZWdleCA9IG5ldyBSZWdFeHAoXG4gICAgICAgICAgICAnXignICsgc2hvcnRQaWVjZXMuam9pbignfCcpICsgJyknLFxuICAgICAgICAgICAgJ2knXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gRk9STUFUVElOR1xuXG4gICAgYWRkRm9ybWF0VG9rZW4oJ1knLCAwLCAwLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciB5ID0gdGhpcy55ZWFyKCk7XG4gICAgICAgIHJldHVybiB5IDw9IDk5OTkgPyB6ZXJvRmlsbCh5LCA0KSA6ICcrJyArIHk7XG4gICAgfSk7XG5cbiAgICBhZGRGb3JtYXRUb2tlbigwLCBbJ1lZJywgMl0sIDAsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMueWVhcigpICUgMTAwO1xuICAgIH0pO1xuXG4gICAgYWRkRm9ybWF0VG9rZW4oMCwgWydZWVlZJywgNF0sIDAsICd5ZWFyJyk7XG4gICAgYWRkRm9ybWF0VG9rZW4oMCwgWydZWVlZWScsIDVdLCAwLCAneWVhcicpO1xuICAgIGFkZEZvcm1hdFRva2VuKDAsIFsnWVlZWVlZJywgNiwgdHJ1ZV0sIDAsICd5ZWFyJyk7XG5cbiAgICAvLyBBTElBU0VTXG5cbiAgICBhZGRVbml0QWxpYXMoJ3llYXInLCAneScpO1xuXG4gICAgLy8gUFJJT1JJVElFU1xuXG4gICAgYWRkVW5pdFByaW9yaXR5KCd5ZWFyJywgMSk7XG5cbiAgICAvLyBQQVJTSU5HXG5cbiAgICBhZGRSZWdleFRva2VuKCdZJywgbWF0Y2hTaWduZWQpO1xuICAgIGFkZFJlZ2V4VG9rZW4oJ1lZJywgbWF0Y2gxdG8yLCBtYXRjaDIpO1xuICAgIGFkZFJlZ2V4VG9rZW4oJ1lZWVknLCBtYXRjaDF0bzQsIG1hdGNoNCk7XG4gICAgYWRkUmVnZXhUb2tlbignWVlZWVknLCBtYXRjaDF0bzYsIG1hdGNoNik7XG4gICAgYWRkUmVnZXhUb2tlbignWVlZWVlZJywgbWF0Y2gxdG82LCBtYXRjaDYpO1xuXG4gICAgYWRkUGFyc2VUb2tlbihbJ1lZWVlZJywgJ1lZWVlZWSddLCBZRUFSKTtcbiAgICBhZGRQYXJzZVRva2VuKCdZWVlZJywgZnVuY3Rpb24gKGlucHV0LCBhcnJheSkge1xuICAgICAgICBhcnJheVtZRUFSXSA9XG4gICAgICAgICAgICBpbnB1dC5sZW5ndGggPT09IDIgPyBob29rcy5wYXJzZVR3b0RpZ2l0WWVhcihpbnB1dCkgOiB0b0ludChpbnB1dCk7XG4gICAgfSk7XG4gICAgYWRkUGFyc2VUb2tlbignWVknLCBmdW5jdGlvbiAoaW5wdXQsIGFycmF5KSB7XG4gICAgICAgIGFycmF5W1lFQVJdID0gaG9va3MucGFyc2VUd29EaWdpdFllYXIoaW5wdXQpO1xuICAgIH0pO1xuICAgIGFkZFBhcnNlVG9rZW4oJ1knLCBmdW5jdGlvbiAoaW5wdXQsIGFycmF5KSB7XG4gICAgICAgIGFycmF5W1lFQVJdID0gcGFyc2VJbnQoaW5wdXQsIDEwKTtcbiAgICB9KTtcblxuICAgIC8vIEhFTFBFUlNcblxuICAgIGZ1bmN0aW9uIGRheXNJblllYXIoeWVhcikge1xuICAgICAgICByZXR1cm4gaXNMZWFwWWVhcih5ZWFyKSA/IDM2NiA6IDM2NTtcbiAgICB9XG5cbiAgICAvLyBIT09LU1xuXG4gICAgaG9va3MucGFyc2VUd29EaWdpdFllYXIgPSBmdW5jdGlvbiAoaW5wdXQpIHtcbiAgICAgICAgcmV0dXJuIHRvSW50KGlucHV0KSArICh0b0ludChpbnB1dCkgPiA2OCA/IDE5MDAgOiAyMDAwKTtcbiAgICB9O1xuXG4gICAgLy8gTU9NRU5UU1xuXG4gICAgdmFyIGdldFNldFllYXIgPSBtYWtlR2V0U2V0KCdGdWxsWWVhcicsIHRydWUpO1xuXG4gICAgZnVuY3Rpb24gZ2V0SXNMZWFwWWVhcigpIHtcbiAgICAgICAgcmV0dXJuIGlzTGVhcFllYXIodGhpcy55ZWFyKCkpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGNyZWF0ZURhdGUoeSwgbSwgZCwgaCwgTSwgcywgbXMpIHtcbiAgICAgICAgLy8gY2FuJ3QganVzdCBhcHBseSgpIHRvIGNyZWF0ZSBhIGRhdGU6XG4gICAgICAgIC8vIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcS8xODEzNDhcbiAgICAgICAgdmFyIGRhdGU7XG4gICAgICAgIC8vIHRoZSBkYXRlIGNvbnN0cnVjdG9yIHJlbWFwcyB5ZWFycyAwLTk5IHRvIDE5MDAtMTk5OVxuICAgICAgICBpZiAoeSA8IDEwMCAmJiB5ID49IDApIHtcbiAgICAgICAgICAgIC8vIHByZXNlcnZlIGxlYXAgeWVhcnMgdXNpbmcgYSBmdWxsIDQwMCB5ZWFyIGN5Y2xlLCB0aGVuIHJlc2V0XG4gICAgICAgICAgICBkYXRlID0gbmV3IERhdGUoeSArIDQwMCwgbSwgZCwgaCwgTSwgcywgbXMpO1xuICAgICAgICAgICAgaWYgKGlzRmluaXRlKGRhdGUuZ2V0RnVsbFllYXIoKSkpIHtcbiAgICAgICAgICAgICAgICBkYXRlLnNldEZ1bGxZZWFyKHkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZGF0ZSA9IG5ldyBEYXRlKHksIG0sIGQsIGgsIE0sIHMsIG1zKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBkYXRlO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGNyZWF0ZVVUQ0RhdGUoeSkge1xuICAgICAgICB2YXIgZGF0ZSwgYXJncztcbiAgICAgICAgLy8gdGhlIERhdGUuVVRDIGZ1bmN0aW9uIHJlbWFwcyB5ZWFycyAwLTk5IHRvIDE5MDAtMTk5OVxuICAgICAgICBpZiAoeSA8IDEwMCAmJiB5ID49IDApIHtcbiAgICAgICAgICAgIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMpO1xuICAgICAgICAgICAgLy8gcHJlc2VydmUgbGVhcCB5ZWFycyB1c2luZyBhIGZ1bGwgNDAwIHllYXIgY3ljbGUsIHRoZW4gcmVzZXRcbiAgICAgICAgICAgIGFyZ3NbMF0gPSB5ICsgNDAwO1xuICAgICAgICAgICAgZGF0ZSA9IG5ldyBEYXRlKERhdGUuVVRDLmFwcGx5KG51bGwsIGFyZ3MpKTtcbiAgICAgICAgICAgIGlmIChpc0Zpbml0ZShkYXRlLmdldFVUQ0Z1bGxZZWFyKCkpKSB7XG4gICAgICAgICAgICAgICAgZGF0ZS5zZXRVVENGdWxsWWVhcih5KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGRhdGUgPSBuZXcgRGF0ZShEYXRlLlVUQy5hcHBseShudWxsLCBhcmd1bWVudHMpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBkYXRlO1xuICAgIH1cblxuICAgIC8vIHN0YXJ0LW9mLWZpcnN0LXdlZWsgLSBzdGFydC1vZi15ZWFyXG4gICAgZnVuY3Rpb24gZmlyc3RXZWVrT2Zmc2V0KHllYXIsIGRvdywgZG95KSB7XG4gICAgICAgIHZhciAvLyBmaXJzdC13ZWVrIGRheSAtLSB3aGljaCBqYW51YXJ5IGlzIGFsd2F5cyBpbiB0aGUgZmlyc3Qgd2VlayAoNCBmb3IgaXNvLCAxIGZvciBvdGhlcilcbiAgICAgICAgICAgIGZ3ZCA9IDcgKyBkb3cgLSBkb3ksXG4gICAgICAgICAgICAvLyBmaXJzdC13ZWVrIGRheSBsb2NhbCB3ZWVrZGF5IC0tIHdoaWNoIGxvY2FsIHdlZWtkYXkgaXMgZndkXG4gICAgICAgICAgICBmd2RsdyA9ICg3ICsgY3JlYXRlVVRDRGF0ZSh5ZWFyLCAwLCBmd2QpLmdldFVUQ0RheSgpIC0gZG93KSAlIDc7XG5cbiAgICAgICAgcmV0dXJuIC1md2RsdyArIGZ3ZCAtIDE7XG4gICAgfVxuXG4gICAgLy8gaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvSVNPX3dlZWtfZGF0ZSNDYWxjdWxhdGluZ19hX2RhdGVfZ2l2ZW5fdGhlX3llYXIuMkNfd2Vla19udW1iZXJfYW5kX3dlZWtkYXlcbiAgICBmdW5jdGlvbiBkYXlPZlllYXJGcm9tV2Vla3MoeWVhciwgd2Vlaywgd2Vla2RheSwgZG93LCBkb3kpIHtcbiAgICAgICAgdmFyIGxvY2FsV2Vla2RheSA9ICg3ICsgd2Vla2RheSAtIGRvdykgJSA3LFxuICAgICAgICAgICAgd2Vla09mZnNldCA9IGZpcnN0V2Vla09mZnNldCh5ZWFyLCBkb3csIGRveSksXG4gICAgICAgICAgICBkYXlPZlllYXIgPSAxICsgNyAqICh3ZWVrIC0gMSkgKyBsb2NhbFdlZWtkYXkgKyB3ZWVrT2Zmc2V0LFxuICAgICAgICAgICAgcmVzWWVhcixcbiAgICAgICAgICAgIHJlc0RheU9mWWVhcjtcblxuICAgICAgICBpZiAoZGF5T2ZZZWFyIDw9IDApIHtcbiAgICAgICAgICAgIHJlc1llYXIgPSB5ZWFyIC0gMTtcbiAgICAgICAgICAgIHJlc0RheU9mWWVhciA9IGRheXNJblllYXIocmVzWWVhcikgKyBkYXlPZlllYXI7XG4gICAgICAgIH0gZWxzZSBpZiAoZGF5T2ZZZWFyID4gZGF5c0luWWVhcih5ZWFyKSkge1xuICAgICAgICAgICAgcmVzWWVhciA9IHllYXIgKyAxO1xuICAgICAgICAgICAgcmVzRGF5T2ZZZWFyID0gZGF5T2ZZZWFyIC0gZGF5c0luWWVhcih5ZWFyKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJlc1llYXIgPSB5ZWFyO1xuICAgICAgICAgICAgcmVzRGF5T2ZZZWFyID0gZGF5T2ZZZWFyO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHllYXI6IHJlc1llYXIsXG4gICAgICAgICAgICBkYXlPZlllYXI6IHJlc0RheU9mWWVhcixcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiB3ZWVrT2ZZZWFyKG1vbSwgZG93LCBkb3kpIHtcbiAgICAgICAgdmFyIHdlZWtPZmZzZXQgPSBmaXJzdFdlZWtPZmZzZXQobW9tLnllYXIoKSwgZG93LCBkb3kpLFxuICAgICAgICAgICAgd2VlayA9IE1hdGguZmxvb3IoKG1vbS5kYXlPZlllYXIoKSAtIHdlZWtPZmZzZXQgLSAxKSAvIDcpICsgMSxcbiAgICAgICAgICAgIHJlc1dlZWssXG4gICAgICAgICAgICByZXNZZWFyO1xuXG4gICAgICAgIGlmICh3ZWVrIDwgMSkge1xuICAgICAgICAgICAgcmVzWWVhciA9IG1vbS55ZWFyKCkgLSAxO1xuICAgICAgICAgICAgcmVzV2VlayA9IHdlZWsgKyB3ZWVrc0luWWVhcihyZXNZZWFyLCBkb3csIGRveSk7XG4gICAgICAgIH0gZWxzZSBpZiAod2VlayA+IHdlZWtzSW5ZZWFyKG1vbS55ZWFyKCksIGRvdywgZG95KSkge1xuICAgICAgICAgICAgcmVzV2VlayA9IHdlZWsgLSB3ZWVrc0luWWVhcihtb20ueWVhcigpLCBkb3csIGRveSk7XG4gICAgICAgICAgICByZXNZZWFyID0gbW9tLnllYXIoKSArIDE7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXNZZWFyID0gbW9tLnllYXIoKTtcbiAgICAgICAgICAgIHJlc1dlZWsgPSB3ZWVrO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHdlZWs6IHJlc1dlZWssXG4gICAgICAgICAgICB5ZWFyOiByZXNZZWFyLFxuICAgICAgICB9O1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHdlZWtzSW5ZZWFyKHllYXIsIGRvdywgZG95KSB7XG4gICAgICAgIHZhciB3ZWVrT2Zmc2V0ID0gZmlyc3RXZWVrT2Zmc2V0KHllYXIsIGRvdywgZG95KSxcbiAgICAgICAgICAgIHdlZWtPZmZzZXROZXh0ID0gZmlyc3RXZWVrT2Zmc2V0KHllYXIgKyAxLCBkb3csIGRveSk7XG4gICAgICAgIHJldHVybiAoZGF5c0luWWVhcih5ZWFyKSAtIHdlZWtPZmZzZXQgKyB3ZWVrT2Zmc2V0TmV4dCkgLyA3O1xuICAgIH1cblxuICAgIC8vIEZPUk1BVFRJTkdcblxuICAgIGFkZEZvcm1hdFRva2VuKCd3JywgWyd3dycsIDJdLCAnd28nLCAnd2VlaycpO1xuICAgIGFkZEZvcm1hdFRva2VuKCdXJywgWydXVycsIDJdLCAnV28nLCAnaXNvV2VlaycpO1xuXG4gICAgLy8gQUxJQVNFU1xuXG4gICAgYWRkVW5pdEFsaWFzKCd3ZWVrJywgJ3cnKTtcbiAgICBhZGRVbml0QWxpYXMoJ2lzb1dlZWsnLCAnVycpO1xuXG4gICAgLy8gUFJJT1JJVElFU1xuXG4gICAgYWRkVW5pdFByaW9yaXR5KCd3ZWVrJywgNSk7XG4gICAgYWRkVW5pdFByaW9yaXR5KCdpc29XZWVrJywgNSk7XG5cbiAgICAvLyBQQVJTSU5HXG5cbiAgICBhZGRSZWdleFRva2VuKCd3JywgbWF0Y2gxdG8yKTtcbiAgICBhZGRSZWdleFRva2VuKCd3dycsIG1hdGNoMXRvMiwgbWF0Y2gyKTtcbiAgICBhZGRSZWdleFRva2VuKCdXJywgbWF0Y2gxdG8yKTtcbiAgICBhZGRSZWdleFRva2VuKCdXVycsIG1hdGNoMXRvMiwgbWF0Y2gyKTtcblxuICAgIGFkZFdlZWtQYXJzZVRva2VuKFsndycsICd3dycsICdXJywgJ1dXJ10sIGZ1bmN0aW9uIChcbiAgICAgICAgaW5wdXQsXG4gICAgICAgIHdlZWssXG4gICAgICAgIGNvbmZpZyxcbiAgICAgICAgdG9rZW5cbiAgICApIHtcbiAgICAgICAgd2Vla1t0b2tlbi5zdWJzdHIoMCwgMSldID0gdG9JbnQoaW5wdXQpO1xuICAgIH0pO1xuXG4gICAgLy8gSEVMUEVSU1xuXG4gICAgLy8gTE9DQUxFU1xuXG4gICAgZnVuY3Rpb24gbG9jYWxlV2Vlayhtb20pIHtcbiAgICAgICAgcmV0dXJuIHdlZWtPZlllYXIobW9tLCB0aGlzLl93ZWVrLmRvdywgdGhpcy5fd2Vlay5kb3kpLndlZWs7XG4gICAgfVxuXG4gICAgdmFyIGRlZmF1bHRMb2NhbGVXZWVrID0ge1xuICAgICAgICBkb3c6IDAsIC8vIFN1bmRheSBpcyB0aGUgZmlyc3QgZGF5IG9mIHRoZSB3ZWVrLlxuICAgICAgICBkb3k6IDYsIC8vIFRoZSB3ZWVrIHRoYXQgY29udGFpbnMgSmFuIDZ0aCBpcyB0aGUgZmlyc3Qgd2VlayBvZiB0aGUgeWVhci5cbiAgICB9O1xuXG4gICAgZnVuY3Rpb24gbG9jYWxlRmlyc3REYXlPZldlZWsoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl93ZWVrLmRvdztcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBsb2NhbGVGaXJzdERheU9mWWVhcigpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3dlZWsuZG95O1xuICAgIH1cblxuICAgIC8vIE1PTUVOVFNcblxuICAgIGZ1bmN0aW9uIGdldFNldFdlZWsoaW5wdXQpIHtcbiAgICAgICAgdmFyIHdlZWsgPSB0aGlzLmxvY2FsZURhdGEoKS53ZWVrKHRoaXMpO1xuICAgICAgICByZXR1cm4gaW5wdXQgPT0gbnVsbCA/IHdlZWsgOiB0aGlzLmFkZCgoaW5wdXQgLSB3ZWVrKSAqIDcsICdkJyk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gZ2V0U2V0SVNPV2VlayhpbnB1dCkge1xuICAgICAgICB2YXIgd2VlayA9IHdlZWtPZlllYXIodGhpcywgMSwgNCkud2VlaztcbiAgICAgICAgcmV0dXJuIGlucHV0ID09IG51bGwgPyB3ZWVrIDogdGhpcy5hZGQoKGlucHV0IC0gd2VlaykgKiA3LCAnZCcpO1xuICAgIH1cblxuICAgIC8vIEZPUk1BVFRJTkdcblxuICAgIGFkZEZvcm1hdFRva2VuKCdkJywgMCwgJ2RvJywgJ2RheScpO1xuXG4gICAgYWRkRm9ybWF0VG9rZW4oJ2RkJywgMCwgMCwgZnVuY3Rpb24gKGZvcm1hdCkge1xuICAgICAgICByZXR1cm4gdGhpcy5sb2NhbGVEYXRhKCkud2Vla2RheXNNaW4odGhpcywgZm9ybWF0KTtcbiAgICB9KTtcblxuICAgIGFkZEZvcm1hdFRva2VuKCdkZGQnLCAwLCAwLCBmdW5jdGlvbiAoZm9ybWF0KSB7XG4gICAgICAgIHJldHVybiB0aGlzLmxvY2FsZURhdGEoKS53ZWVrZGF5c1Nob3J0KHRoaXMsIGZvcm1hdCk7XG4gICAgfSk7XG5cbiAgICBhZGRGb3JtYXRUb2tlbignZGRkZCcsIDAsIDAsIGZ1bmN0aW9uIChmb3JtYXQpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubG9jYWxlRGF0YSgpLndlZWtkYXlzKHRoaXMsIGZvcm1hdCk7XG4gICAgfSk7XG5cbiAgICBhZGRGb3JtYXRUb2tlbignZScsIDAsIDAsICd3ZWVrZGF5Jyk7XG4gICAgYWRkRm9ybWF0VG9rZW4oJ0UnLCAwLCAwLCAnaXNvV2Vla2RheScpO1xuXG4gICAgLy8gQUxJQVNFU1xuXG4gICAgYWRkVW5pdEFsaWFzKCdkYXknLCAnZCcpO1xuICAgIGFkZFVuaXRBbGlhcygnd2Vla2RheScsICdlJyk7XG4gICAgYWRkVW5pdEFsaWFzKCdpc29XZWVrZGF5JywgJ0UnKTtcblxuICAgIC8vIFBSSU9SSVRZXG4gICAgYWRkVW5pdFByaW9yaXR5KCdkYXknLCAxMSk7XG4gICAgYWRkVW5pdFByaW9yaXR5KCd3ZWVrZGF5JywgMTEpO1xuICAgIGFkZFVuaXRQcmlvcml0eSgnaXNvV2Vla2RheScsIDExKTtcblxuICAgIC8vIFBBUlNJTkdcblxuICAgIGFkZFJlZ2V4VG9rZW4oJ2QnLCBtYXRjaDF0bzIpO1xuICAgIGFkZFJlZ2V4VG9rZW4oJ2UnLCBtYXRjaDF0bzIpO1xuICAgIGFkZFJlZ2V4VG9rZW4oJ0UnLCBtYXRjaDF0bzIpO1xuICAgIGFkZFJlZ2V4VG9rZW4oJ2RkJywgZnVuY3Rpb24gKGlzU3RyaWN0LCBsb2NhbGUpIHtcbiAgICAgICAgcmV0dXJuIGxvY2FsZS53ZWVrZGF5c01pblJlZ2V4KGlzU3RyaWN0KTtcbiAgICB9KTtcbiAgICBhZGRSZWdleFRva2VuKCdkZGQnLCBmdW5jdGlvbiAoaXNTdHJpY3QsIGxvY2FsZSkge1xuICAgICAgICByZXR1cm4gbG9jYWxlLndlZWtkYXlzU2hvcnRSZWdleChpc1N0cmljdCk7XG4gICAgfSk7XG4gICAgYWRkUmVnZXhUb2tlbignZGRkZCcsIGZ1bmN0aW9uIChpc1N0cmljdCwgbG9jYWxlKSB7XG4gICAgICAgIHJldHVybiBsb2NhbGUud2Vla2RheXNSZWdleChpc1N0cmljdCk7XG4gICAgfSk7XG5cbiAgICBhZGRXZWVrUGFyc2VUb2tlbihbJ2RkJywgJ2RkZCcsICdkZGRkJ10sIGZ1bmN0aW9uIChpbnB1dCwgd2VlaywgY29uZmlnLCB0b2tlbikge1xuICAgICAgICB2YXIgd2Vla2RheSA9IGNvbmZpZy5fbG9jYWxlLndlZWtkYXlzUGFyc2UoaW5wdXQsIHRva2VuLCBjb25maWcuX3N0cmljdCk7XG4gICAgICAgIC8vIGlmIHdlIGRpZG4ndCBnZXQgYSB3ZWVrZGF5IG5hbWUsIG1hcmsgdGhlIGRhdGUgYXMgaW52YWxpZFxuICAgICAgICBpZiAod2Vla2RheSAhPSBudWxsKSB7XG4gICAgICAgICAgICB3ZWVrLmQgPSB3ZWVrZGF5O1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZ2V0UGFyc2luZ0ZsYWdzKGNvbmZpZykuaW52YWxpZFdlZWtkYXkgPSBpbnB1dDtcbiAgICAgICAgfVxuICAgIH0pO1xuXG4gICAgYWRkV2Vla1BhcnNlVG9rZW4oWydkJywgJ2UnLCAnRSddLCBmdW5jdGlvbiAoaW5wdXQsIHdlZWssIGNvbmZpZywgdG9rZW4pIHtcbiAgICAgICAgd2Vla1t0b2tlbl0gPSB0b0ludChpbnB1dCk7XG4gICAgfSk7XG5cbiAgICAvLyBIRUxQRVJTXG5cbiAgICBmdW5jdGlvbiBwYXJzZVdlZWtkYXkoaW5wdXQsIGxvY2FsZSkge1xuICAgICAgICBpZiAodHlwZW9mIGlucHV0ICE9PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgcmV0dXJuIGlucHV0O1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFpc05hTihpbnB1dCkpIHtcbiAgICAgICAgICAgIHJldHVybiBwYXJzZUludChpbnB1dCwgMTApO1xuICAgICAgICB9XG5cbiAgICAgICAgaW5wdXQgPSBsb2NhbGUud2Vla2RheXNQYXJzZShpbnB1dCk7XG4gICAgICAgIGlmICh0eXBlb2YgaW5wdXQgPT09ICdudW1iZXInKSB7XG4gICAgICAgICAgICByZXR1cm4gaW5wdXQ7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBwYXJzZUlzb1dlZWtkYXkoaW5wdXQsIGxvY2FsZSkge1xuICAgICAgICBpZiAodHlwZW9mIGlucHV0ID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgcmV0dXJuIGxvY2FsZS53ZWVrZGF5c1BhcnNlKGlucHV0KSAlIDcgfHwgNztcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gaXNOYU4oaW5wdXQpID8gbnVsbCA6IGlucHV0O1xuICAgIH1cblxuICAgIC8vIExPQ0FMRVNcbiAgICBmdW5jdGlvbiBzaGlmdFdlZWtkYXlzKHdzLCBuKSB7XG4gICAgICAgIHJldHVybiB3cy5zbGljZShuLCA3KS5jb25jYXQod3Muc2xpY2UoMCwgbikpO1xuICAgIH1cblxuICAgIHZhciBkZWZhdWx0TG9jYWxlV2Vla2RheXMgPSAnU3VuZGF5X01vbmRheV9UdWVzZGF5X1dlZG5lc2RheV9UaHVyc2RheV9GcmlkYXlfU2F0dXJkYXknLnNwbGl0KFxuICAgICAgICAgICAgJ18nXG4gICAgICAgICksXG4gICAgICAgIGRlZmF1bHRMb2NhbGVXZWVrZGF5c1Nob3J0ID0gJ1N1bl9Nb25fVHVlX1dlZF9UaHVfRnJpX1NhdCcuc3BsaXQoJ18nKSxcbiAgICAgICAgZGVmYXVsdExvY2FsZVdlZWtkYXlzTWluID0gJ1N1X01vX1R1X1dlX1RoX0ZyX1NhJy5zcGxpdCgnXycpLFxuICAgICAgICBkZWZhdWx0V2Vla2RheXNSZWdleCA9IG1hdGNoV29yZCxcbiAgICAgICAgZGVmYXVsdFdlZWtkYXlzU2hvcnRSZWdleCA9IG1hdGNoV29yZCxcbiAgICAgICAgZGVmYXVsdFdlZWtkYXlzTWluUmVnZXggPSBtYXRjaFdvcmQ7XG5cbiAgICBmdW5jdGlvbiBsb2NhbGVXZWVrZGF5cyhtLCBmb3JtYXQpIHtcbiAgICAgICAgdmFyIHdlZWtkYXlzID0gaXNBcnJheSh0aGlzLl93ZWVrZGF5cylcbiAgICAgICAgICAgID8gdGhpcy5fd2Vla2RheXNcbiAgICAgICAgICAgIDogdGhpcy5fd2Vla2RheXNbXG4gICAgICAgICAgICAgICAgICBtICYmIG0gIT09IHRydWUgJiYgdGhpcy5fd2Vla2RheXMuaXNGb3JtYXQudGVzdChmb3JtYXQpXG4gICAgICAgICAgICAgICAgICAgICAgPyAnZm9ybWF0J1xuICAgICAgICAgICAgICAgICAgICAgIDogJ3N0YW5kYWxvbmUnXG4gICAgICAgICAgICAgIF07XG4gICAgICAgIHJldHVybiBtID09PSB0cnVlXG4gICAgICAgICAgICA/IHNoaWZ0V2Vla2RheXMod2Vla2RheXMsIHRoaXMuX3dlZWsuZG93KVxuICAgICAgICAgICAgOiBtXG4gICAgICAgICAgICA/IHdlZWtkYXlzW20uZGF5KCldXG4gICAgICAgICAgICA6IHdlZWtkYXlzO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGxvY2FsZVdlZWtkYXlzU2hvcnQobSkge1xuICAgICAgICByZXR1cm4gbSA9PT0gdHJ1ZVxuICAgICAgICAgICAgPyBzaGlmdFdlZWtkYXlzKHRoaXMuX3dlZWtkYXlzU2hvcnQsIHRoaXMuX3dlZWsuZG93KVxuICAgICAgICAgICAgOiBtXG4gICAgICAgICAgICA/IHRoaXMuX3dlZWtkYXlzU2hvcnRbbS5kYXkoKV1cbiAgICAgICAgICAgIDogdGhpcy5fd2Vla2RheXNTaG9ydDtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBsb2NhbGVXZWVrZGF5c01pbihtKSB7XG4gICAgICAgIHJldHVybiBtID09PSB0cnVlXG4gICAgICAgICAgICA/IHNoaWZ0V2Vla2RheXModGhpcy5fd2Vla2RheXNNaW4sIHRoaXMuX3dlZWsuZG93KVxuICAgICAgICAgICAgOiBtXG4gICAgICAgICAgICA/IHRoaXMuX3dlZWtkYXlzTWluW20uZGF5KCldXG4gICAgICAgICAgICA6IHRoaXMuX3dlZWtkYXlzTWluO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGhhbmRsZVN0cmljdFBhcnNlJDEod2Vla2RheU5hbWUsIGZvcm1hdCwgc3RyaWN0KSB7XG4gICAgICAgIHZhciBpLFxuICAgICAgICAgICAgaWksXG4gICAgICAgICAgICBtb20sXG4gICAgICAgICAgICBsbGMgPSB3ZWVrZGF5TmFtZS50b0xvY2FsZUxvd2VyQ2FzZSgpO1xuICAgICAgICBpZiAoIXRoaXMuX3dlZWtkYXlzUGFyc2UpIHtcbiAgICAgICAgICAgIHRoaXMuX3dlZWtkYXlzUGFyc2UgPSBbXTtcbiAgICAgICAgICAgIHRoaXMuX3Nob3J0V2Vla2RheXNQYXJzZSA9IFtdO1xuICAgICAgICAgICAgdGhpcy5fbWluV2Vla2RheXNQYXJzZSA9IFtdO1xuXG4gICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwgNzsgKytpKSB7XG4gICAgICAgICAgICAgICAgbW9tID0gY3JlYXRlVVRDKFsyMDAwLCAxXSkuZGF5KGkpO1xuICAgICAgICAgICAgICAgIHRoaXMuX21pbldlZWtkYXlzUGFyc2VbaV0gPSB0aGlzLndlZWtkYXlzTWluKFxuICAgICAgICAgICAgICAgICAgICBtb20sXG4gICAgICAgICAgICAgICAgICAgICcnXG4gICAgICAgICAgICAgICAgKS50b0xvY2FsZUxvd2VyQ2FzZSgpO1xuICAgICAgICAgICAgICAgIHRoaXMuX3Nob3J0V2Vla2RheXNQYXJzZVtpXSA9IHRoaXMud2Vla2RheXNTaG9ydChcbiAgICAgICAgICAgICAgICAgICAgbW9tLFxuICAgICAgICAgICAgICAgICAgICAnJ1xuICAgICAgICAgICAgICAgICkudG9Mb2NhbGVMb3dlckNhc2UoKTtcbiAgICAgICAgICAgICAgICB0aGlzLl93ZWVrZGF5c1BhcnNlW2ldID0gdGhpcy53ZWVrZGF5cyhtb20sICcnKS50b0xvY2FsZUxvd2VyQ2FzZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHN0cmljdCkge1xuICAgICAgICAgICAgaWYgKGZvcm1hdCA9PT0gJ2RkZGQnKSB7XG4gICAgICAgICAgICAgICAgaWkgPSBpbmRleE9mLmNhbGwodGhpcy5fd2Vla2RheXNQYXJzZSwgbGxjKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gaWkgIT09IC0xID8gaWkgOiBudWxsO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChmb3JtYXQgPT09ICdkZGQnKSB7XG4gICAgICAgICAgICAgICAgaWkgPSBpbmRleE9mLmNhbGwodGhpcy5fc2hvcnRXZWVrZGF5c1BhcnNlLCBsbGMpO1xuICAgICAgICAgICAgICAgIHJldHVybiBpaSAhPT0gLTEgPyBpaSA6IG51bGw7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGlpID0gaW5kZXhPZi5jYWxsKHRoaXMuX21pbldlZWtkYXlzUGFyc2UsIGxsYyk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGlpICE9PSAtMSA/IGlpIDogbnVsbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGlmIChmb3JtYXQgPT09ICdkZGRkJykge1xuICAgICAgICAgICAgICAgIGlpID0gaW5kZXhPZi5jYWxsKHRoaXMuX3dlZWtkYXlzUGFyc2UsIGxsYyk7XG4gICAgICAgICAgICAgICAgaWYgKGlpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gaWk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlpID0gaW5kZXhPZi5jYWxsKHRoaXMuX3Nob3J0V2Vla2RheXNQYXJzZSwgbGxjKTtcbiAgICAgICAgICAgICAgICBpZiAoaWkgIT09IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBpaTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWkgPSBpbmRleE9mLmNhbGwodGhpcy5fbWluV2Vla2RheXNQYXJzZSwgbGxjKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gaWkgIT09IC0xID8gaWkgOiBudWxsO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChmb3JtYXQgPT09ICdkZGQnKSB7XG4gICAgICAgICAgICAgICAgaWkgPSBpbmRleE9mLmNhbGwodGhpcy5fc2hvcnRXZWVrZGF5c1BhcnNlLCBsbGMpO1xuICAgICAgICAgICAgICAgIGlmIChpaSAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGlpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpaSA9IGluZGV4T2YuY2FsbCh0aGlzLl93ZWVrZGF5c1BhcnNlLCBsbGMpO1xuICAgICAgICAgICAgICAgIGlmIChpaSAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGlpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpaSA9IGluZGV4T2YuY2FsbCh0aGlzLl9taW5XZWVrZGF5c1BhcnNlLCBsbGMpO1xuICAgICAgICAgICAgICAgIHJldHVybiBpaSAhPT0gLTEgPyBpaSA6IG51bGw7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGlpID0gaW5kZXhPZi5jYWxsKHRoaXMuX21pbldlZWtkYXlzUGFyc2UsIGxsYyk7XG4gICAgICAgICAgICAgICAgaWYgKGlpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gaWk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlpID0gaW5kZXhPZi5jYWxsKHRoaXMuX3dlZWtkYXlzUGFyc2UsIGxsYyk7XG4gICAgICAgICAgICAgICAgaWYgKGlpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gaWk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlpID0gaW5kZXhPZi5jYWxsKHRoaXMuX3Nob3J0V2Vla2RheXNQYXJzZSwgbGxjKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gaWkgIT09IC0xID8gaWkgOiBudWxsO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gbG9jYWxlV2Vla2RheXNQYXJzZSh3ZWVrZGF5TmFtZSwgZm9ybWF0LCBzdHJpY3QpIHtcbiAgICAgICAgdmFyIGksIG1vbSwgcmVnZXg7XG5cbiAgICAgICAgaWYgKHRoaXMuX3dlZWtkYXlzUGFyc2VFeGFjdCkge1xuICAgICAgICAgICAgcmV0dXJuIGhhbmRsZVN0cmljdFBhcnNlJDEuY2FsbCh0aGlzLCB3ZWVrZGF5TmFtZSwgZm9ybWF0LCBzdHJpY3QpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCF0aGlzLl93ZWVrZGF5c1BhcnNlKSB7XG4gICAgICAgICAgICB0aGlzLl93ZWVrZGF5c1BhcnNlID0gW107XG4gICAgICAgICAgICB0aGlzLl9taW5XZWVrZGF5c1BhcnNlID0gW107XG4gICAgICAgICAgICB0aGlzLl9zaG9ydFdlZWtkYXlzUGFyc2UgPSBbXTtcbiAgICAgICAgICAgIHRoaXMuX2Z1bGxXZWVrZGF5c1BhcnNlID0gW107XG4gICAgICAgIH1cblxuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgNzsgaSsrKSB7XG4gICAgICAgICAgICAvLyBtYWtlIHRoZSByZWdleCBpZiB3ZSBkb24ndCBoYXZlIGl0IGFscmVhZHlcblxuICAgICAgICAgICAgbW9tID0gY3JlYXRlVVRDKFsyMDAwLCAxXSkuZGF5KGkpO1xuICAgICAgICAgICAgaWYgKHN0cmljdCAmJiAhdGhpcy5fZnVsbFdlZWtkYXlzUGFyc2VbaV0pIHtcbiAgICAgICAgICAgICAgICB0aGlzLl9mdWxsV2Vla2RheXNQYXJzZVtpXSA9IG5ldyBSZWdFeHAoXG4gICAgICAgICAgICAgICAgICAgICdeJyArIHRoaXMud2Vla2RheXMobW9tLCAnJykucmVwbGFjZSgnLicsICdcXFxcLj8nKSArICckJyxcbiAgICAgICAgICAgICAgICAgICAgJ2knXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB0aGlzLl9zaG9ydFdlZWtkYXlzUGFyc2VbaV0gPSBuZXcgUmVnRXhwKFxuICAgICAgICAgICAgICAgICAgICAnXicgKyB0aGlzLndlZWtkYXlzU2hvcnQobW9tLCAnJykucmVwbGFjZSgnLicsICdcXFxcLj8nKSArICckJyxcbiAgICAgICAgICAgICAgICAgICAgJ2knXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB0aGlzLl9taW5XZWVrZGF5c1BhcnNlW2ldID0gbmV3IFJlZ0V4cChcbiAgICAgICAgICAgICAgICAgICAgJ14nICsgdGhpcy53ZWVrZGF5c01pbihtb20sICcnKS5yZXBsYWNlKCcuJywgJ1xcXFwuPycpICsgJyQnLFxuICAgICAgICAgICAgICAgICAgICAnaSdcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCF0aGlzLl93ZWVrZGF5c1BhcnNlW2ldKSB7XG4gICAgICAgICAgICAgICAgcmVnZXggPVxuICAgICAgICAgICAgICAgICAgICAnXicgK1xuICAgICAgICAgICAgICAgICAgICB0aGlzLndlZWtkYXlzKG1vbSwgJycpICtcbiAgICAgICAgICAgICAgICAgICAgJ3xeJyArXG4gICAgICAgICAgICAgICAgICAgIHRoaXMud2Vla2RheXNTaG9ydChtb20sICcnKSArXG4gICAgICAgICAgICAgICAgICAgICd8XicgK1xuICAgICAgICAgICAgICAgICAgICB0aGlzLndlZWtkYXlzTWluKG1vbSwgJycpO1xuICAgICAgICAgICAgICAgIHRoaXMuX3dlZWtkYXlzUGFyc2VbaV0gPSBuZXcgUmVnRXhwKHJlZ2V4LnJlcGxhY2UoJy4nLCAnJyksICdpJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyB0ZXN0IHRoZSByZWdleFxuICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgIHN0cmljdCAmJlxuICAgICAgICAgICAgICAgIGZvcm1hdCA9PT0gJ2RkZGQnICYmXG4gICAgICAgICAgICAgICAgdGhpcy5fZnVsbFdlZWtkYXlzUGFyc2VbaV0udGVzdCh3ZWVrZGF5TmFtZSlcbiAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgIHJldHVybiBpO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChcbiAgICAgICAgICAgICAgICBzdHJpY3QgJiZcbiAgICAgICAgICAgICAgICBmb3JtYXQgPT09ICdkZGQnICYmXG4gICAgICAgICAgICAgICAgdGhpcy5fc2hvcnRXZWVrZGF5c1BhcnNlW2ldLnRlc3Qod2Vla2RheU5hbWUpXG4gICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gaTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoXG4gICAgICAgICAgICAgICAgc3RyaWN0ICYmXG4gICAgICAgICAgICAgICAgZm9ybWF0ID09PSAnZGQnICYmXG4gICAgICAgICAgICAgICAgdGhpcy5fbWluV2Vla2RheXNQYXJzZVtpXS50ZXN0KHdlZWtkYXlOYW1lKVxuICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKCFzdHJpY3QgJiYgdGhpcy5fd2Vla2RheXNQYXJzZVtpXS50ZXN0KHdlZWtkYXlOYW1lKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gTU9NRU5UU1xuXG4gICAgZnVuY3Rpb24gZ2V0U2V0RGF5T2ZXZWVrKGlucHV0KSB7XG4gICAgICAgIGlmICghdGhpcy5pc1ZhbGlkKCkpIHtcbiAgICAgICAgICAgIHJldHVybiBpbnB1dCAhPSBudWxsID8gdGhpcyA6IE5hTjtcbiAgICAgICAgfVxuICAgICAgICB2YXIgZGF5ID0gdGhpcy5faXNVVEMgPyB0aGlzLl9kLmdldFVUQ0RheSgpIDogdGhpcy5fZC5nZXREYXkoKTtcbiAgICAgICAgaWYgKGlucHV0ICE9IG51bGwpIHtcbiAgICAgICAgICAgIGlucHV0ID0gcGFyc2VXZWVrZGF5KGlucHV0LCB0aGlzLmxvY2FsZURhdGEoKSk7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5hZGQoaW5wdXQgLSBkYXksICdkJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gZGF5O1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gZ2V0U2V0TG9jYWxlRGF5T2ZXZWVrKGlucHV0KSB7XG4gICAgICAgIGlmICghdGhpcy5pc1ZhbGlkKCkpIHtcbiAgICAgICAgICAgIHJldHVybiBpbnB1dCAhPSBudWxsID8gdGhpcyA6IE5hTjtcbiAgICAgICAgfVxuICAgICAgICB2YXIgd2Vla2RheSA9ICh0aGlzLmRheSgpICsgNyAtIHRoaXMubG9jYWxlRGF0YSgpLl93ZWVrLmRvdykgJSA3O1xuICAgICAgICByZXR1cm4gaW5wdXQgPT0gbnVsbCA/IHdlZWtkYXkgOiB0aGlzLmFkZChpbnB1dCAtIHdlZWtkYXksICdkJyk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gZ2V0U2V0SVNPRGF5T2ZXZWVrKGlucHV0KSB7XG4gICAgICAgIGlmICghdGhpcy5pc1ZhbGlkKCkpIHtcbiAgICAgICAgICAgIHJldHVybiBpbnB1dCAhPSBudWxsID8gdGhpcyA6IE5hTjtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGJlaGF2ZXMgdGhlIHNhbWUgYXMgbW9tZW50I2RheSBleGNlcHRcbiAgICAgICAgLy8gYXMgYSBnZXR0ZXIsIHJldHVybnMgNyBpbnN0ZWFkIG9mIDAgKDEtNyByYW5nZSBpbnN0ZWFkIG9mIDAtNilcbiAgICAgICAgLy8gYXMgYSBzZXR0ZXIsIHN1bmRheSBzaG91bGQgYmVsb25nIHRvIHRoZSBwcmV2aW91cyB3ZWVrLlxuXG4gICAgICAgIGlmIChpbnB1dCAhPSBudWxsKSB7XG4gICAgICAgICAgICB2YXIgd2Vla2RheSA9IHBhcnNlSXNvV2Vla2RheShpbnB1dCwgdGhpcy5sb2NhbGVEYXRhKCkpO1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuZGF5KHRoaXMuZGF5KCkgJSA3ID8gd2Vla2RheSA6IHdlZWtkYXkgLSA3KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmRheSgpIHx8IDc7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiB3ZWVrZGF5c1JlZ2V4KGlzU3RyaWN0KSB7XG4gICAgICAgIGlmICh0aGlzLl93ZWVrZGF5c1BhcnNlRXhhY3QpIHtcbiAgICAgICAgICAgIGlmICghaGFzT3duUHJvcCh0aGlzLCAnX3dlZWtkYXlzUmVnZXgnKSkge1xuICAgICAgICAgICAgICAgIGNvbXB1dGVXZWVrZGF5c1BhcnNlLmNhbGwodGhpcyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoaXNTdHJpY3QpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5fd2Vla2RheXNTdHJpY3RSZWdleDtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3dlZWtkYXlzUmVnZXg7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBpZiAoIWhhc093blByb3AodGhpcywgJ193ZWVrZGF5c1JlZ2V4JykpIHtcbiAgICAgICAgICAgICAgICB0aGlzLl93ZWVrZGF5c1JlZ2V4ID0gZGVmYXVsdFdlZWtkYXlzUmVnZXg7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fd2Vla2RheXNTdHJpY3RSZWdleCAmJiBpc1N0cmljdFxuICAgICAgICAgICAgICAgID8gdGhpcy5fd2Vla2RheXNTdHJpY3RSZWdleFxuICAgICAgICAgICAgICAgIDogdGhpcy5fd2Vla2RheXNSZWdleDtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIHdlZWtkYXlzU2hvcnRSZWdleChpc1N0cmljdCkge1xuICAgICAgICBpZiAodGhpcy5fd2Vla2RheXNQYXJzZUV4YWN0KSB7XG4gICAgICAgICAgICBpZiAoIWhhc093blByb3AodGhpcywgJ193ZWVrZGF5c1JlZ2V4JykpIHtcbiAgICAgICAgICAgICAgICBjb21wdXRlV2Vla2RheXNQYXJzZS5jYWxsKHRoaXMpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGlzU3RyaWN0KSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3dlZWtkYXlzU2hvcnRTdHJpY3RSZWdleDtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3dlZWtkYXlzU2hvcnRSZWdleDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGlmICghaGFzT3duUHJvcCh0aGlzLCAnX3dlZWtkYXlzU2hvcnRSZWdleCcpKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5fd2Vla2RheXNTaG9ydFJlZ2V4ID0gZGVmYXVsdFdlZWtkYXlzU2hvcnRSZWdleDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB0aGlzLl93ZWVrZGF5c1Nob3J0U3RyaWN0UmVnZXggJiYgaXNTdHJpY3RcbiAgICAgICAgICAgICAgICA/IHRoaXMuX3dlZWtkYXlzU2hvcnRTdHJpY3RSZWdleFxuICAgICAgICAgICAgICAgIDogdGhpcy5fd2Vla2RheXNTaG9ydFJlZ2V4O1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gd2Vla2RheXNNaW5SZWdleChpc1N0cmljdCkge1xuICAgICAgICBpZiAodGhpcy5fd2Vla2RheXNQYXJzZUV4YWN0KSB7XG4gICAgICAgICAgICBpZiAoIWhhc093blByb3AodGhpcywgJ193ZWVrZGF5c1JlZ2V4JykpIHtcbiAgICAgICAgICAgICAgICBjb21wdXRlV2Vla2RheXNQYXJzZS5jYWxsKHRoaXMpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGlzU3RyaWN0KSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3dlZWtkYXlzTWluU3RyaWN0UmVnZXg7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLl93ZWVrZGF5c01pblJlZ2V4O1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaWYgKCFoYXNPd25Qcm9wKHRoaXMsICdfd2Vla2RheXNNaW5SZWdleCcpKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5fd2Vla2RheXNNaW5SZWdleCA9IGRlZmF1bHRXZWVrZGF5c01pblJlZ2V4O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3dlZWtkYXlzTWluU3RyaWN0UmVnZXggJiYgaXNTdHJpY3RcbiAgICAgICAgICAgICAgICA/IHRoaXMuX3dlZWtkYXlzTWluU3RyaWN0UmVnZXhcbiAgICAgICAgICAgICAgICA6IHRoaXMuX3dlZWtkYXlzTWluUmVnZXg7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiBjb21wdXRlV2Vla2RheXNQYXJzZSgpIHtcbiAgICAgICAgZnVuY3Rpb24gY21wTGVuUmV2KGEsIGIpIHtcbiAgICAgICAgICAgIHJldHVybiBiLmxlbmd0aCAtIGEubGVuZ3RoO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIG1pblBpZWNlcyA9IFtdLFxuICAgICAgICAgICAgc2hvcnRQaWVjZXMgPSBbXSxcbiAgICAgICAgICAgIGxvbmdQaWVjZXMgPSBbXSxcbiAgICAgICAgICAgIG1peGVkUGllY2VzID0gW10sXG4gICAgICAgICAgICBpLFxuICAgICAgICAgICAgbW9tLFxuICAgICAgICAgICAgbWlucCxcbiAgICAgICAgICAgIHNob3J0cCxcbiAgICAgICAgICAgIGxvbmdwO1xuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgNzsgaSsrKSB7XG4gICAgICAgICAgICAvLyBtYWtlIHRoZSByZWdleCBpZiB3ZSBkb24ndCBoYXZlIGl0IGFscmVhZHlcbiAgICAgICAgICAgIG1vbSA9IGNyZWF0ZVVUQyhbMjAwMCwgMV0pLmRheShpKTtcbiAgICAgICAgICAgIG1pbnAgPSByZWdleEVzY2FwZSh0aGlzLndlZWtkYXlzTWluKG1vbSwgJycpKTtcbiAgICAgICAgICAgIHNob3J0cCA9IHJlZ2V4RXNjYXBlKHRoaXMud2Vla2RheXNTaG9ydChtb20sICcnKSk7XG4gICAgICAgICAgICBsb25ncCA9IHJlZ2V4RXNjYXBlKHRoaXMud2Vla2RheXMobW9tLCAnJykpO1xuICAgICAgICAgICAgbWluUGllY2VzLnB1c2gobWlucCk7XG4gICAgICAgICAgICBzaG9ydFBpZWNlcy5wdXNoKHNob3J0cCk7XG4gICAgICAgICAgICBsb25nUGllY2VzLnB1c2gobG9uZ3ApO1xuICAgICAgICAgICAgbWl4ZWRQaWVjZXMucHVzaChtaW5wKTtcbiAgICAgICAgICAgIG1peGVkUGllY2VzLnB1c2goc2hvcnRwKTtcbiAgICAgICAgICAgIG1peGVkUGllY2VzLnB1c2gobG9uZ3ApO1xuICAgICAgICB9XG4gICAgICAgIC8vIFNvcnRpbmcgbWFrZXMgc3VyZSBpZiBvbmUgd2Vla2RheSAob3IgYWJicikgaXMgYSBwcmVmaXggb2YgYW5vdGhlciBpdFxuICAgICAgICAvLyB3aWxsIG1hdGNoIHRoZSBsb25nZXIgcGllY2UuXG4gICAgICAgIG1pblBpZWNlcy5zb3J0KGNtcExlblJldik7XG4gICAgICAgIHNob3J0UGllY2VzLnNvcnQoY21wTGVuUmV2KTtcbiAgICAgICAgbG9uZ1BpZWNlcy5zb3J0KGNtcExlblJldik7XG4gICAgICAgIG1peGVkUGllY2VzLnNvcnQoY21wTGVuUmV2KTtcblxuICAgICAgICB0aGlzLl93ZWVrZGF5c1JlZ2V4ID0gbmV3IFJlZ0V4cCgnXignICsgbWl4ZWRQaWVjZXMuam9pbignfCcpICsgJyknLCAnaScpO1xuICAgICAgICB0aGlzLl93ZWVrZGF5c1Nob3J0UmVnZXggPSB0aGlzLl93ZWVrZGF5c1JlZ2V4O1xuICAgICAgICB0aGlzLl93ZWVrZGF5c01pblJlZ2V4ID0gdGhpcy5fd2Vla2RheXNSZWdleDtcblxuICAgICAgICB0aGlzLl93ZWVrZGF5c1N0cmljdFJlZ2V4ID0gbmV3IFJlZ0V4cChcbiAgICAgICAgICAgICdeKCcgKyBsb25nUGllY2VzLmpvaW4oJ3wnKSArICcpJyxcbiAgICAgICAgICAgICdpJ1xuICAgICAgICApO1xuICAgICAgICB0aGlzLl93ZWVrZGF5c1Nob3J0U3RyaWN0UmVnZXggPSBuZXcgUmVnRXhwKFxuICAgICAgICAgICAgJ14oJyArIHNob3J0UGllY2VzLmpvaW4oJ3wnKSArICcpJyxcbiAgICAgICAgICAgICdpJ1xuICAgICAgICApO1xuICAgICAgICB0aGlzLl93ZWVrZGF5c01pblN0cmljdFJlZ2V4ID0gbmV3IFJlZ0V4cChcbiAgICAgICAgICAgICdeKCcgKyBtaW5QaWVjZXMuam9pbignfCcpICsgJyknLFxuICAgICAgICAgICAgJ2knXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gRk9STUFUVElOR1xuXG4gICAgZnVuY3Rpb24gaEZvcm1hdCgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuaG91cnMoKSAlIDEyIHx8IDEyO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGtGb3JtYXQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmhvdXJzKCkgfHwgMjQ7XG4gICAgfVxuXG4gICAgYWRkRm9ybWF0VG9rZW4oJ0gnLCBbJ0hIJywgMl0sIDAsICdob3VyJyk7XG4gICAgYWRkRm9ybWF0VG9rZW4oJ2gnLCBbJ2hoJywgMl0sIDAsIGhGb3JtYXQpO1xuICAgIGFkZEZvcm1hdFRva2VuKCdrJywgWydraycsIDJdLCAwLCBrRm9ybWF0KTtcblxuICAgIGFkZEZvcm1hdFRva2VuKCdobW0nLCAwLCAwLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiAnJyArIGhGb3JtYXQuYXBwbHkodGhpcykgKyB6ZXJvRmlsbCh0aGlzLm1pbnV0ZXMoKSwgMik7XG4gICAgfSk7XG5cbiAgICBhZGRGb3JtYXRUb2tlbignaG1tc3MnLCAwLCAwLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICAnJyArXG4gICAgICAgICAgICBoRm9ybWF0LmFwcGx5KHRoaXMpICtcbiAgICAgICAgICAgIHplcm9GaWxsKHRoaXMubWludXRlcygpLCAyKSArXG4gICAgICAgICAgICB6ZXJvRmlsbCh0aGlzLnNlY29uZHMoKSwgMilcbiAgICAgICAgKTtcbiAgICB9KTtcblxuICAgIGFkZEZvcm1hdFRva2VuKCdIbW0nLCAwLCAwLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiAnJyArIHRoaXMuaG91cnMoKSArIHplcm9GaWxsKHRoaXMubWludXRlcygpLCAyKTtcbiAgICB9KTtcblxuICAgIGFkZEZvcm1hdFRva2VuKCdIbW1zcycsIDAsIDAsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgICcnICtcbiAgICAgICAgICAgIHRoaXMuaG91cnMoKSArXG4gICAgICAgICAgICB6ZXJvRmlsbCh0aGlzLm1pbnV0ZXMoKSwgMikgK1xuICAgICAgICAgICAgemVyb0ZpbGwodGhpcy5zZWNvbmRzKCksIDIpXG4gICAgICAgICk7XG4gICAgfSk7XG5cbiAgICBmdW5jdGlvbiBtZXJpZGllbSh0b2tlbiwgbG93ZXJjYXNlKSB7XG4gICAgICAgIGFkZEZvcm1hdFRva2VuKHRva2VuLCAwLCAwLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5sb2NhbGVEYXRhKCkubWVyaWRpZW0oXG4gICAgICAgICAgICAgICAgdGhpcy5ob3VycygpLFxuICAgICAgICAgICAgICAgIHRoaXMubWludXRlcygpLFxuICAgICAgICAgICAgICAgIGxvd2VyY2FzZVxuICAgICAgICAgICAgKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgbWVyaWRpZW0oJ2EnLCB0cnVlKTtcbiAgICBtZXJpZGllbSgnQScsIGZhbHNlKTtcblxuICAgIC8vIEFMSUFTRVNcblxuICAgIGFkZFVuaXRBbGlhcygnaG91cicsICdoJyk7XG5cbiAgICAvLyBQUklPUklUWVxuICAgIGFkZFVuaXRQcmlvcml0eSgnaG91cicsIDEzKTtcblxuICAgIC8vIFBBUlNJTkdcblxuICAgIGZ1bmN0aW9uIG1hdGNoTWVyaWRpZW0oaXNTdHJpY3QsIGxvY2FsZSkge1xuICAgICAgICByZXR1cm4gbG9jYWxlLl9tZXJpZGllbVBhcnNlO1xuICAgIH1cblxuICAgIGFkZFJlZ2V4VG9rZW4oJ2EnLCBtYXRjaE1lcmlkaWVtKTtcbiAgICBhZGRSZWdleFRva2VuKCdBJywgbWF0Y2hNZXJpZGllbSk7XG4gICAgYWRkUmVnZXhUb2tlbignSCcsIG1hdGNoMXRvMik7XG4gICAgYWRkUmVnZXhUb2tlbignaCcsIG1hdGNoMXRvMik7XG4gICAgYWRkUmVnZXhUb2tlbignaycsIG1hdGNoMXRvMik7XG4gICAgYWRkUmVnZXhUb2tlbignSEgnLCBtYXRjaDF0bzIsIG1hdGNoMik7XG4gICAgYWRkUmVnZXhUb2tlbignaGgnLCBtYXRjaDF0bzIsIG1hdGNoMik7XG4gICAgYWRkUmVnZXhUb2tlbigna2snLCBtYXRjaDF0bzIsIG1hdGNoMik7XG5cbiAgICBhZGRSZWdleFRva2VuKCdobW0nLCBtYXRjaDN0bzQpO1xuICAgIGFkZFJlZ2V4VG9rZW4oJ2htbXNzJywgbWF0Y2g1dG82KTtcbiAgICBhZGRSZWdleFRva2VuKCdIbW0nLCBtYXRjaDN0bzQpO1xuICAgIGFkZFJlZ2V4VG9rZW4oJ0htbXNzJywgbWF0Y2g1dG82KTtcblxuICAgIGFkZFBhcnNlVG9rZW4oWydIJywgJ0hIJ10sIEhPVVIpO1xuICAgIGFkZFBhcnNlVG9rZW4oWydrJywgJ2trJ10sIGZ1bmN0aW9uIChpbnB1dCwgYXJyYXksIGNvbmZpZykge1xuICAgICAgICB2YXIga0lucHV0ID0gdG9JbnQoaW5wdXQpO1xuICAgICAgICBhcnJheVtIT1VSXSA9IGtJbnB1dCA9PT0gMjQgPyAwIDoga0lucHV0O1xuICAgIH0pO1xuICAgIGFkZFBhcnNlVG9rZW4oWydhJywgJ0EnXSwgZnVuY3Rpb24gKGlucHV0LCBhcnJheSwgY29uZmlnKSB7XG4gICAgICAgIGNvbmZpZy5faXNQbSA9IGNvbmZpZy5fbG9jYWxlLmlzUE0oaW5wdXQpO1xuICAgICAgICBjb25maWcuX21lcmlkaWVtID0gaW5wdXQ7XG4gICAgfSk7XG4gICAgYWRkUGFyc2VUb2tlbihbJ2gnLCAnaGgnXSwgZnVuY3Rpb24gKGlucHV0LCBhcnJheSwgY29uZmlnKSB7XG4gICAgICAgIGFycmF5W0hPVVJdID0gdG9JbnQoaW5wdXQpO1xuICAgICAgICBnZXRQYXJzaW5nRmxhZ3MoY29uZmlnKS5iaWdIb3VyID0gdHJ1ZTtcbiAgICB9KTtcbiAgICBhZGRQYXJzZVRva2VuKCdobW0nLCBmdW5jdGlvbiAoaW5wdXQsIGFycmF5LCBjb25maWcpIHtcbiAgICAgICAgdmFyIHBvcyA9IGlucHV0Lmxlbmd0aCAtIDI7XG4gICAgICAgIGFycmF5W0hPVVJdID0gdG9JbnQoaW5wdXQuc3Vic3RyKDAsIHBvcykpO1xuICAgICAgICBhcnJheVtNSU5VVEVdID0gdG9JbnQoaW5wdXQuc3Vic3RyKHBvcykpO1xuICAgICAgICBnZXRQYXJzaW5nRmxhZ3MoY29uZmlnKS5iaWdIb3VyID0gdHJ1ZTtcbiAgICB9KTtcbiAgICBhZGRQYXJzZVRva2VuKCdobW1zcycsIGZ1bmN0aW9uIChpbnB1dCwgYXJyYXksIGNvbmZpZykge1xuICAgICAgICB2YXIgcG9zMSA9IGlucHV0Lmxlbmd0aCAtIDQsXG4gICAgICAgICAgICBwb3MyID0gaW5wdXQubGVuZ3RoIC0gMjtcbiAgICAgICAgYXJyYXlbSE9VUl0gPSB0b0ludChpbnB1dC5zdWJzdHIoMCwgcG9zMSkpO1xuICAgICAgICBhcnJheVtNSU5VVEVdID0gdG9JbnQoaW5wdXQuc3Vic3RyKHBvczEsIDIpKTtcbiAgICAgICAgYXJyYXlbU0VDT05EXSA9IHRvSW50KGlucHV0LnN1YnN0cihwb3MyKSk7XG4gICAgICAgIGdldFBhcnNpbmdGbGFncyhjb25maWcpLmJpZ0hvdXIgPSB0cnVlO1xuICAgIH0pO1xuICAgIGFkZFBhcnNlVG9rZW4oJ0htbScsIGZ1bmN0aW9uIChpbnB1dCwgYXJyYXksIGNvbmZpZykge1xuICAgICAgICB2YXIgcG9zID0gaW5wdXQubGVuZ3RoIC0gMjtcbiAgICAgICAgYXJyYXlbSE9VUl0gPSB0b0ludChpbnB1dC5zdWJzdHIoMCwgcG9zKSk7XG4gICAgICAgIGFycmF5W01JTlVURV0gPSB0b0ludChpbnB1dC5zdWJzdHIocG9zKSk7XG4gICAgfSk7XG4gICAgYWRkUGFyc2VUb2tlbignSG1tc3MnLCBmdW5jdGlvbiAoaW5wdXQsIGFycmF5LCBjb25maWcpIHtcbiAgICAgICAgdmFyIHBvczEgPSBpbnB1dC5sZW5ndGggLSA0LFxuICAgICAgICAgICAgcG9zMiA9IGlucHV0Lmxlbmd0aCAtIDI7XG4gICAgICAgIGFycmF5W0hPVVJdID0gdG9JbnQoaW5wdXQuc3Vic3RyKDAsIHBvczEpKTtcbiAgICAgICAgYXJyYXlbTUlOVVRFXSA9IHRvSW50KGlucHV0LnN1YnN0cihwb3MxLCAyKSk7XG4gICAgICAgIGFycmF5W1NFQ09ORF0gPSB0b0ludChpbnB1dC5zdWJzdHIocG9zMikpO1xuICAgIH0pO1xuXG4gICAgLy8gTE9DQUxFU1xuXG4gICAgZnVuY3Rpb24gbG9jYWxlSXNQTShpbnB1dCkge1xuICAgICAgICAvLyBJRTggUXVpcmtzIE1vZGUgJiBJRTcgU3RhbmRhcmRzIE1vZGUgZG8gbm90IGFsbG93IGFjY2Vzc2luZyBzdHJpbmdzIGxpa2UgYXJyYXlzXG4gICAgICAgIC8vIFVzaW5nIGNoYXJBdCBzaG91bGQgYmUgbW9yZSBjb21wYXRpYmxlLlxuICAgICAgICByZXR1cm4gKGlucHV0ICsgJycpLnRvTG93ZXJDYXNlKCkuY2hhckF0KDApID09PSAncCc7XG4gICAgfVxuXG4gICAgdmFyIGRlZmF1bHRMb2NhbGVNZXJpZGllbVBhcnNlID0gL1thcF1cXC4/bT9cXC4/L2ksXG4gICAgICAgIC8vIFNldHRpbmcgdGhlIGhvdXIgc2hvdWxkIGtlZXAgdGhlIHRpbWUsIGJlY2F1c2UgdGhlIHVzZXIgZXhwbGljaXRseVxuICAgICAgICAvLyBzcGVjaWZpZWQgd2hpY2ggaG91ciB0aGV5IHdhbnQuIFNvIHRyeWluZyB0byBtYWludGFpbiB0aGUgc2FtZSBob3VyIChpblxuICAgICAgICAvLyBhIG5ldyB0aW1lem9uZSkgbWFrZXMgc2Vuc2UuIEFkZGluZy9zdWJ0cmFjdGluZyBob3VycyBkb2VzIG5vdCBmb2xsb3dcbiAgICAgICAgLy8gdGhpcyBydWxlLlxuICAgICAgICBnZXRTZXRIb3VyID0gbWFrZUdldFNldCgnSG91cnMnLCB0cnVlKTtcblxuICAgIGZ1bmN0aW9uIGxvY2FsZU1lcmlkaWVtKGhvdXJzLCBtaW51dGVzLCBpc0xvd2VyKSB7XG4gICAgICAgIGlmIChob3VycyA+IDExKSB7XG4gICAgICAgICAgICByZXR1cm4gaXNMb3dlciA/ICdwbScgOiAnUE0nO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIGlzTG93ZXIgPyAnYW0nIDogJ0FNJztcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHZhciBiYXNlQ29uZmlnID0ge1xuICAgICAgICBjYWxlbmRhcjogZGVmYXVsdENhbGVuZGFyLFxuICAgICAgICBsb25nRGF0ZUZvcm1hdDogZGVmYXVsdExvbmdEYXRlRm9ybWF0LFxuICAgICAgICBpbnZhbGlkRGF0ZTogZGVmYXVsdEludmFsaWREYXRlLFxuICAgICAgICBvcmRpbmFsOiBkZWZhdWx0T3JkaW5hbCxcbiAgICAgICAgZGF5T2ZNb250aE9yZGluYWxQYXJzZTogZGVmYXVsdERheU9mTW9udGhPcmRpbmFsUGFyc2UsXG4gICAgICAgIHJlbGF0aXZlVGltZTogZGVmYXVsdFJlbGF0aXZlVGltZSxcblxuICAgICAgICBtb250aHM6IGRlZmF1bHRMb2NhbGVNb250aHMsXG4gICAgICAgIG1vbnRoc1Nob3J0OiBkZWZhdWx0TG9jYWxlTW9udGhzU2hvcnQsXG5cbiAgICAgICAgd2VlazogZGVmYXVsdExvY2FsZVdlZWssXG5cbiAgICAgICAgd2Vla2RheXM6IGRlZmF1bHRMb2NhbGVXZWVrZGF5cyxcbiAgICAgICAgd2Vla2RheXNNaW46IGRlZmF1bHRMb2NhbGVXZWVrZGF5c01pbixcbiAgICAgICAgd2Vla2RheXNTaG9ydDogZGVmYXVsdExvY2FsZVdlZWtkYXlzU2hvcnQsXG5cbiAgICAgICAgbWVyaWRpZW1QYXJzZTogZGVmYXVsdExvY2FsZU1lcmlkaWVtUGFyc2UsXG4gICAgfTtcblxuICAgIC8vIGludGVybmFsIHN0b3JhZ2UgZm9yIGxvY2FsZSBjb25maWcgZmlsZXNcbiAgICB2YXIgbG9jYWxlcyA9IHt9LFxuICAgICAgICBsb2NhbGVGYW1pbGllcyA9IHt9LFxuICAgICAgICBnbG9iYWxMb2NhbGU7XG5cbiAgICBmdW5jdGlvbiBjb21tb25QcmVmaXgoYXJyMSwgYXJyMikge1xuICAgICAgICB2YXIgaSxcbiAgICAgICAgICAgIG1pbmwgPSBNYXRoLm1pbihhcnIxLmxlbmd0aCwgYXJyMi5sZW5ndGgpO1xuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgbWlubDsgaSArPSAxKSB7XG4gICAgICAgICAgICBpZiAoYXJyMVtpXSAhPT0gYXJyMltpXSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBtaW5sO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIG5vcm1hbGl6ZUxvY2FsZShrZXkpIHtcbiAgICAgICAgcmV0dXJuIGtleSA/IGtleS50b0xvd2VyQ2FzZSgpLnJlcGxhY2UoJ18nLCAnLScpIDoga2V5O1xuICAgIH1cblxuICAgIC8vIHBpY2sgdGhlIGxvY2FsZSBmcm9tIHRoZSBhcnJheVxuICAgIC8vIHRyeSBbJ2VuLWF1JywgJ2VuLWdiJ10gYXMgJ2VuLWF1JywgJ2VuLWdiJywgJ2VuJywgYXMgaW4gbW92ZSB0aHJvdWdoIHRoZSBsaXN0IHRyeWluZyBlYWNoXG4gICAgLy8gc3Vic3RyaW5nIGZyb20gbW9zdCBzcGVjaWZpYyB0byBsZWFzdCwgYnV0IG1vdmUgdG8gdGhlIG5leHQgYXJyYXkgaXRlbSBpZiBpdCdzIGEgbW9yZSBzcGVjaWZpYyB2YXJpYW50IHRoYW4gdGhlIGN1cnJlbnQgcm9vdFxuICAgIGZ1bmN0aW9uIGNob29zZUxvY2FsZShuYW1lcykge1xuICAgICAgICB2YXIgaSA9IDAsXG4gICAgICAgICAgICBqLFxuICAgICAgICAgICAgbmV4dCxcbiAgICAgICAgICAgIGxvY2FsZSxcbiAgICAgICAgICAgIHNwbGl0O1xuXG4gICAgICAgIHdoaWxlIChpIDwgbmFtZXMubGVuZ3RoKSB7XG4gICAgICAgICAgICBzcGxpdCA9IG5vcm1hbGl6ZUxvY2FsZShuYW1lc1tpXSkuc3BsaXQoJy0nKTtcbiAgICAgICAgICAgIGogPSBzcGxpdC5sZW5ndGg7XG4gICAgICAgICAgICBuZXh0ID0gbm9ybWFsaXplTG9jYWxlKG5hbWVzW2kgKyAxXSk7XG4gICAgICAgICAgICBuZXh0ID0gbmV4dCA/IG5leHQuc3BsaXQoJy0nKSA6IG51bGw7XG4gICAgICAgICAgICB3aGlsZSAoaiA+IDApIHtcbiAgICAgICAgICAgICAgICBsb2NhbGUgPSBsb2FkTG9jYWxlKHNwbGl0LnNsaWNlKDAsIGopLmpvaW4oJy0nKSk7XG4gICAgICAgICAgICAgICAgaWYgKGxvY2FsZSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gbG9jYWxlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgICAgIG5leHQgJiZcbiAgICAgICAgICAgICAgICAgICAgbmV4dC5sZW5ndGggPj0gaiAmJlxuICAgICAgICAgICAgICAgICAgICBjb21tb25QcmVmaXgoc3BsaXQsIG5leHQpID49IGogLSAxXG4gICAgICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vdGhlIG5leHQgYXJyYXkgaXRlbSBpcyBiZXR0ZXIgdGhhbiBhIHNoYWxsb3dlciBzdWJzdHJpbmcgb2YgdGhpcyBvbmVcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGotLTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGkrKztcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZ2xvYmFsTG9jYWxlO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGxvYWRMb2NhbGUobmFtZSkge1xuICAgICAgICB2YXIgb2xkTG9jYWxlID0gbnVsbCxcbiAgICAgICAgICAgIGFsaWFzZWRSZXF1aXJlO1xuICAgICAgICAvLyBUT0RPOiBGaW5kIGEgYmV0dGVyIHdheSB0byByZWdpc3RlciBhbmQgbG9hZCBhbGwgdGhlIGxvY2FsZXMgaW4gTm9kZVxuICAgICAgICBpZiAoXG4gICAgICAgICAgICBsb2NhbGVzW25hbWVdID09PSB1bmRlZmluZWQgJiZcbiAgICAgICAgICAgIHR5cGVvZiBtb2R1bGUgIT09ICd1bmRlZmluZWQnICYmXG4gICAgICAgICAgICBtb2R1bGUgJiZcbiAgICAgICAgICAgIG1vZHVsZS5leHBvcnRzXG4gICAgICAgICkge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBvbGRMb2NhbGUgPSBnbG9iYWxMb2NhbGUuX2FiYnI7XG4gICAgICAgICAgICAgICAgYWxpYXNlZFJlcXVpcmUgPSByZXF1aXJlO1xuICAgICAgICAgICAgICAgIGFsaWFzZWRSZXF1aXJlKCcuL2xvY2FsZS8nICsgbmFtZSk7XG4gICAgICAgICAgICAgICAgZ2V0U2V0R2xvYmFsTG9jYWxlKG9sZExvY2FsZSk7XG4gICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgICAgLy8gbWFyayBhcyBub3QgZm91bmQgdG8gYXZvaWQgcmVwZWF0aW5nIGV4cGVuc2l2ZSBmaWxlIHJlcXVpcmUgY2FsbCBjYXVzaW5nIGhpZ2ggQ1BVXG4gICAgICAgICAgICAgICAgLy8gd2hlbiB0cnlpbmcgdG8gZmluZCBlbi1VUywgZW5fVVMsIGVuLXVzIGZvciBldmVyeSBmb3JtYXQgY2FsbFxuICAgICAgICAgICAgICAgIGxvY2FsZXNbbmFtZV0gPSBudWxsOyAvLyBudWxsIG1lYW5zIG5vdCBmb3VuZFxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBsb2NhbGVzW25hbWVdO1xuICAgIH1cblxuICAgIC8vIFRoaXMgZnVuY3Rpb24gd2lsbCBsb2FkIGxvY2FsZSBhbmQgdGhlbiBzZXQgdGhlIGdsb2JhbCBsb2NhbGUuICBJZlxuICAgIC8vIG5vIGFyZ3VtZW50cyBhcmUgcGFzc2VkIGluLCBpdCB3aWxsIHNpbXBseSByZXR1cm4gdGhlIGN1cnJlbnQgZ2xvYmFsXG4gICAgLy8gbG9jYWxlIGtleS5cbiAgICBmdW5jdGlvbiBnZXRTZXRHbG9iYWxMb2NhbGUoa2V5LCB2YWx1ZXMpIHtcbiAgICAgICAgdmFyIGRhdGE7XG4gICAgICAgIGlmIChrZXkpIHtcbiAgICAgICAgICAgIGlmIChpc1VuZGVmaW5lZCh2YWx1ZXMpKSB7XG4gICAgICAgICAgICAgICAgZGF0YSA9IGdldExvY2FsZShrZXkpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBkYXRhID0gZGVmaW5lTG9jYWxlKGtleSwgdmFsdWVzKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKGRhdGEpIHtcbiAgICAgICAgICAgICAgICAvLyBtb21lbnQuZHVyYXRpb24uX2xvY2FsZSA9IG1vbWVudC5fbG9jYWxlID0gZGF0YTtcbiAgICAgICAgICAgICAgICBnbG9iYWxMb2NhbGUgPSBkYXRhO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIGNvbnNvbGUgIT09ICd1bmRlZmluZWQnICYmIGNvbnNvbGUud2Fybikge1xuICAgICAgICAgICAgICAgICAgICAvL3dhcm4gdXNlciBpZiBhcmd1bWVudHMgYXJlIHBhc3NlZCBidXQgdGhlIGxvY2FsZSBjb3VsZCBub3QgYmUgc2V0XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgICAgICAgICAgICAgICAgICdMb2NhbGUgJyArIGtleSArICcgbm90IGZvdW5kLiBEaWQgeW91IGZvcmdldCB0byBsb2FkIGl0PydcbiAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZ2xvYmFsTG9jYWxlLl9hYmJyO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGRlZmluZUxvY2FsZShuYW1lLCBjb25maWcpIHtcbiAgICAgICAgaWYgKGNvbmZpZyAhPT0gbnVsbCkge1xuICAgICAgICAgICAgdmFyIGxvY2FsZSxcbiAgICAgICAgICAgICAgICBwYXJlbnRDb25maWcgPSBiYXNlQ29uZmlnO1xuICAgICAgICAgICAgY29uZmlnLmFiYnIgPSBuYW1lO1xuICAgICAgICAgICAgaWYgKGxvY2FsZXNbbmFtZV0gIT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIGRlcHJlY2F0ZVNpbXBsZShcbiAgICAgICAgICAgICAgICAgICAgJ2RlZmluZUxvY2FsZU92ZXJyaWRlJyxcbiAgICAgICAgICAgICAgICAgICAgJ3VzZSBtb21lbnQudXBkYXRlTG9jYWxlKGxvY2FsZU5hbWUsIGNvbmZpZykgdG8gY2hhbmdlICcgK1xuICAgICAgICAgICAgICAgICAgICAgICAgJ2FuIGV4aXN0aW5nIGxvY2FsZS4gbW9tZW50LmRlZmluZUxvY2FsZShsb2NhbGVOYW1lLCAnICtcbiAgICAgICAgICAgICAgICAgICAgICAgICdjb25maWcpIHNob3VsZCBvbmx5IGJlIHVzZWQgZm9yIGNyZWF0aW5nIGEgbmV3IGxvY2FsZSAnICtcbiAgICAgICAgICAgICAgICAgICAgICAgICdTZWUgaHR0cDovL21vbWVudGpzLmNvbS9ndWlkZXMvIy93YXJuaW5ncy9kZWZpbmUtbG9jYWxlLyBmb3IgbW9yZSBpbmZvLidcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIHBhcmVudENvbmZpZyA9IGxvY2FsZXNbbmFtZV0uX2NvbmZpZztcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoY29uZmlnLnBhcmVudExvY2FsZSAhPSBudWxsKSB7XG4gICAgICAgICAgICAgICAgaWYgKGxvY2FsZXNbY29uZmlnLnBhcmVudExvY2FsZV0gIT0gbnVsbCkge1xuICAgICAgICAgICAgICAgICAgICBwYXJlbnRDb25maWcgPSBsb2NhbGVzW2NvbmZpZy5wYXJlbnRMb2NhbGVdLl9jb25maWc7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgbG9jYWxlID0gbG9hZExvY2FsZShjb25maWcucGFyZW50TG9jYWxlKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGxvY2FsZSAhPSBudWxsKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBwYXJlbnRDb25maWcgPSBsb2NhbGUuX2NvbmZpZztcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghbG9jYWxlRmFtaWxpZXNbY29uZmlnLnBhcmVudExvY2FsZV0pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2NhbGVGYW1pbGllc1tjb25maWcucGFyZW50TG9jYWxlXSA9IFtdO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgbG9jYWxlRmFtaWxpZXNbY29uZmlnLnBhcmVudExvY2FsZV0ucHVzaCh7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZTogbmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25maWc6IGNvbmZpZyxcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBsb2NhbGVzW25hbWVdID0gbmV3IExvY2FsZShtZXJnZUNvbmZpZ3MocGFyZW50Q29uZmlnLCBjb25maWcpKTtcblxuICAgICAgICAgICAgaWYgKGxvY2FsZUZhbWlsaWVzW25hbWVdKSB7XG4gICAgICAgICAgICAgICAgbG9jYWxlRmFtaWxpZXNbbmFtZV0uZm9yRWFjaChmdW5jdGlvbiAoeCkge1xuICAgICAgICAgICAgICAgICAgICBkZWZpbmVMb2NhbGUoeC5uYW1lLCB4LmNvbmZpZyk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIGJhY2t3YXJkcyBjb21wYXQgZm9yIG5vdzogYWxzbyBzZXQgdGhlIGxvY2FsZVxuICAgICAgICAgICAgLy8gbWFrZSBzdXJlIHdlIHNldCB0aGUgbG9jYWxlIEFGVEVSIGFsbCBjaGlsZCBsb2NhbGVzIGhhdmUgYmVlblxuICAgICAgICAgICAgLy8gY3JlYXRlZCwgc28gd2Ugd29uJ3QgZW5kIHVwIHdpdGggdGhlIGNoaWxkIGxvY2FsZSBzZXQuXG4gICAgICAgICAgICBnZXRTZXRHbG9iYWxMb2NhbGUobmFtZSk7XG5cbiAgICAgICAgICAgIHJldHVybiBsb2NhbGVzW25hbWVdO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gdXNlZnVsIGZvciB0ZXN0aW5nXG4gICAgICAgICAgICBkZWxldGUgbG9jYWxlc1tuYW1lXTtcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gdXBkYXRlTG9jYWxlKG5hbWUsIGNvbmZpZykge1xuICAgICAgICBpZiAoY29uZmlnICE9IG51bGwpIHtcbiAgICAgICAgICAgIHZhciBsb2NhbGUsXG4gICAgICAgICAgICAgICAgdG1wTG9jYWxlLFxuICAgICAgICAgICAgICAgIHBhcmVudENvbmZpZyA9IGJhc2VDb25maWc7XG5cbiAgICAgICAgICAgIGlmIChsb2NhbGVzW25hbWVdICE9IG51bGwgJiYgbG9jYWxlc1tuYW1lXS5wYXJlbnRMb2NhbGUgIT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIC8vIFVwZGF0ZSBleGlzdGluZyBjaGlsZCBsb2NhbGUgaW4tcGxhY2UgdG8gYXZvaWQgbWVtb3J5LWxlYWtzXG4gICAgICAgICAgICAgICAgbG9jYWxlc1tuYW1lXS5zZXQobWVyZ2VDb25maWdzKGxvY2FsZXNbbmFtZV0uX2NvbmZpZywgY29uZmlnKSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIC8vIE1FUkdFXG4gICAgICAgICAgICAgICAgdG1wTG9jYWxlID0gbG9hZExvY2FsZShuYW1lKTtcbiAgICAgICAgICAgICAgICBpZiAodG1wTG9jYWxlICE9IG51bGwpIHtcbiAgICAgICAgICAgICAgICAgICAgcGFyZW50Q29uZmlnID0gdG1wTG9jYWxlLl9jb25maWc7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNvbmZpZyA9IG1lcmdlQ29uZmlncyhwYXJlbnRDb25maWcsIGNvbmZpZyk7XG4gICAgICAgICAgICAgICAgaWYgKHRtcExvY2FsZSA9PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIHVwZGF0ZUxvY2FsZSBpcyBjYWxsZWQgZm9yIGNyZWF0aW5nIGEgbmV3IGxvY2FsZVxuICAgICAgICAgICAgICAgICAgICAvLyBTZXQgYWJiciBzbyBpdCB3aWxsIGhhdmUgYSBuYW1lIChnZXR0ZXJzIHJldHVyblxuICAgICAgICAgICAgICAgICAgICAvLyB1bmRlZmluZWQgb3RoZXJ3aXNlKS5cbiAgICAgICAgICAgICAgICAgICAgY29uZmlnLmFiYnIgPSBuYW1lO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBsb2NhbGUgPSBuZXcgTG9jYWxlKGNvbmZpZyk7XG4gICAgICAgICAgICAgICAgbG9jYWxlLnBhcmVudExvY2FsZSA9IGxvY2FsZXNbbmFtZV07XG4gICAgICAgICAgICAgICAgbG9jYWxlc1tuYW1lXSA9IGxvY2FsZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gYmFja3dhcmRzIGNvbXBhdCBmb3Igbm93OiBhbHNvIHNldCB0aGUgbG9jYWxlXG4gICAgICAgICAgICBnZXRTZXRHbG9iYWxMb2NhbGUobmFtZSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBwYXNzIG51bGwgZm9yIGNvbmZpZyB0byB1bnVwZGF0ZSwgdXNlZnVsIGZvciB0ZXN0c1xuICAgICAgICAgICAgaWYgKGxvY2FsZXNbbmFtZV0gIT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIGlmIChsb2NhbGVzW25hbWVdLnBhcmVudExvY2FsZSAhPSBudWxsKSB7XG4gICAgICAgICAgICAgICAgICAgIGxvY2FsZXNbbmFtZV0gPSBsb2NhbGVzW25hbWVdLnBhcmVudExvY2FsZTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKG5hbWUgPT09IGdldFNldEdsb2JhbExvY2FsZSgpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBnZXRTZXRHbG9iYWxMb2NhbGUobmFtZSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGxvY2FsZXNbbmFtZV0gIT0gbnVsbCkge1xuICAgICAgICAgICAgICAgICAgICBkZWxldGUgbG9jYWxlc1tuYW1lXTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGxvY2FsZXNbbmFtZV07XG4gICAgfVxuXG4gICAgLy8gcmV0dXJucyBsb2NhbGUgZGF0YVxuICAgIGZ1bmN0aW9uIGdldExvY2FsZShrZXkpIHtcbiAgICAgICAgdmFyIGxvY2FsZTtcblxuICAgICAgICBpZiAoa2V5ICYmIGtleS5fbG9jYWxlICYmIGtleS5fbG9jYWxlLl9hYmJyKSB7XG4gICAgICAgICAgICBrZXkgPSBrZXkuX2xvY2FsZS5fYWJicjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICgha2V5KSB7XG4gICAgICAgICAgICByZXR1cm4gZ2xvYmFsTG9jYWxlO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFpc0FycmF5KGtleSkpIHtcbiAgICAgICAgICAgIC8vc2hvcnQtY2lyY3VpdCBldmVyeXRoaW5nIGVsc2VcbiAgICAgICAgICAgIGxvY2FsZSA9IGxvYWRMb2NhbGUoa2V5KTtcbiAgICAgICAgICAgIGlmIChsb2NhbGUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gbG9jYWxlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAga2V5ID0gW2tleV07XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gY2hvb3NlTG9jYWxlKGtleSk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gbGlzdExvY2FsZXMoKSB7XG4gICAgICAgIHJldHVybiBrZXlzKGxvY2FsZXMpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGNoZWNrT3ZlcmZsb3cobSkge1xuICAgICAgICB2YXIgb3ZlcmZsb3csXG4gICAgICAgICAgICBhID0gbS5fYTtcblxuICAgICAgICBpZiAoYSAmJiBnZXRQYXJzaW5nRmxhZ3MobSkub3ZlcmZsb3cgPT09IC0yKSB7XG4gICAgICAgICAgICBvdmVyZmxvdyA9XG4gICAgICAgICAgICAgICAgYVtNT05USF0gPCAwIHx8IGFbTU9OVEhdID4gMTFcbiAgICAgICAgICAgICAgICAgICAgPyBNT05USFxuICAgICAgICAgICAgICAgICAgICA6IGFbREFURV0gPCAxIHx8IGFbREFURV0gPiBkYXlzSW5Nb250aChhW1lFQVJdLCBhW01PTlRIXSlcbiAgICAgICAgICAgICAgICAgICAgPyBEQVRFXG4gICAgICAgICAgICAgICAgICAgIDogYVtIT1VSXSA8IDAgfHxcbiAgICAgICAgICAgICAgICAgICAgICBhW0hPVVJdID4gMjQgfHxcbiAgICAgICAgICAgICAgICAgICAgICAoYVtIT1VSXSA9PT0gMjQgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgICAgKGFbTUlOVVRFXSAhPT0gMCB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYVtTRUNPTkRdICE9PSAwIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhW01JTExJU0VDT05EXSAhPT0gMCkpXG4gICAgICAgICAgICAgICAgICAgID8gSE9VUlxuICAgICAgICAgICAgICAgICAgICA6IGFbTUlOVVRFXSA8IDAgfHwgYVtNSU5VVEVdID4gNTlcbiAgICAgICAgICAgICAgICAgICAgPyBNSU5VVEVcbiAgICAgICAgICAgICAgICAgICAgOiBhW1NFQ09ORF0gPCAwIHx8IGFbU0VDT05EXSA+IDU5XG4gICAgICAgICAgICAgICAgICAgID8gU0VDT05EXG4gICAgICAgICAgICAgICAgICAgIDogYVtNSUxMSVNFQ09ORF0gPCAwIHx8IGFbTUlMTElTRUNPTkRdID4gOTk5XG4gICAgICAgICAgICAgICAgICAgID8gTUlMTElTRUNPTkRcbiAgICAgICAgICAgICAgICAgICAgOiAtMTtcblxuICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgIGdldFBhcnNpbmdGbGFncyhtKS5fb3ZlcmZsb3dEYXlPZlllYXIgJiZcbiAgICAgICAgICAgICAgICAob3ZlcmZsb3cgPCBZRUFSIHx8IG92ZXJmbG93ID4gREFURSlcbiAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgIG92ZXJmbG93ID0gREFURTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChnZXRQYXJzaW5nRmxhZ3MobSkuX292ZXJmbG93V2Vla3MgJiYgb3ZlcmZsb3cgPT09IC0xKSB7XG4gICAgICAgICAgICAgICAgb3ZlcmZsb3cgPSBXRUVLO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGdldFBhcnNpbmdGbGFncyhtKS5fb3ZlcmZsb3dXZWVrZGF5ICYmIG92ZXJmbG93ID09PSAtMSkge1xuICAgICAgICAgICAgICAgIG92ZXJmbG93ID0gV0VFS0RBWTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgZ2V0UGFyc2luZ0ZsYWdzKG0pLm92ZXJmbG93ID0gb3ZlcmZsb3c7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gbTtcbiAgICB9XG5cbiAgICAvLyBpc28gODYwMSByZWdleFxuICAgIC8vIDAwMDAtMDAtMDAgMDAwMC1XMDAgb3IgMDAwMC1XMDAtMCArIFQgKyAwMCBvciAwMDowMCBvciAwMDowMDowMCBvciAwMDowMDowMC4wMDAgKyArMDA6MDAgb3IgKzAwMDAgb3IgKzAwKVxuICAgIHZhciBleHRlbmRlZElzb1JlZ2V4ID0gL15cXHMqKCg/OlsrLV1cXGR7Nn18XFxkezR9KS0oPzpcXGRcXGQtXFxkXFxkfFdcXGRcXGQtXFxkfFdcXGRcXGR8XFxkXFxkXFxkfFxcZFxcZCkpKD86KFR8ICkoXFxkXFxkKD86OlxcZFxcZCg/OjpcXGRcXGQoPzpbLixdXFxkKyk/KT8pPykoWystXVxcZFxcZCg/Ojo/XFxkXFxkKT98XFxzKlopPyk/JC8sXG4gICAgICAgIGJhc2ljSXNvUmVnZXggPSAvXlxccyooKD86WystXVxcZHs2fXxcXGR7NH0pKD86XFxkXFxkXFxkXFxkfFdcXGRcXGRcXGR8V1xcZFxcZHxcXGRcXGRcXGR8XFxkXFxkfCkpKD86KFR8ICkoXFxkXFxkKD86XFxkXFxkKD86XFxkXFxkKD86Wy4sXVxcZCspPyk/KT8pKFsrLV1cXGRcXGQoPzo6P1xcZFxcZCk/fFxccypaKT8pPyQvLFxuICAgICAgICB0elJlZ2V4ID0gL1p8WystXVxcZFxcZCg/Ojo/XFxkXFxkKT8vLFxuICAgICAgICBpc29EYXRlcyA9IFtcbiAgICAgICAgICAgIFsnWVlZWVlZLU1NLUREJywgL1srLV1cXGR7Nn0tXFxkXFxkLVxcZFxcZC9dLFxuICAgICAgICAgICAgWydZWVlZLU1NLUREJywgL1xcZHs0fS1cXGRcXGQtXFxkXFxkL10sXG4gICAgICAgICAgICBbJ0dHR0ctW1ddV1ctRScsIC9cXGR7NH0tV1xcZFxcZC1cXGQvXSxcbiAgICAgICAgICAgIFsnR0dHRy1bV11XVycsIC9cXGR7NH0tV1xcZFxcZC8sIGZhbHNlXSxcbiAgICAgICAgICAgIFsnWVlZWS1EREQnLCAvXFxkezR9LVxcZHszfS9dLFxuICAgICAgICAgICAgWydZWVlZLU1NJywgL1xcZHs0fS1cXGRcXGQvLCBmYWxzZV0sXG4gICAgICAgICAgICBbJ1lZWVlZWU1NREQnLCAvWystXVxcZHsxMH0vXSxcbiAgICAgICAgICAgIFsnWVlZWU1NREQnLCAvXFxkezh9L10sXG4gICAgICAgICAgICBbJ0dHR0dbV11XV0UnLCAvXFxkezR9V1xcZHszfS9dLFxuICAgICAgICAgICAgWydHR0dHW1ddV1cnLCAvXFxkezR9V1xcZHsyfS8sIGZhbHNlXSxcbiAgICAgICAgICAgIFsnWVlZWURERCcsIC9cXGR7N30vXSxcbiAgICAgICAgICAgIFsnWVlZWU1NJywgL1xcZHs2fS8sIGZhbHNlXSxcbiAgICAgICAgICAgIFsnWVlZWScsIC9cXGR7NH0vLCBmYWxzZV0sXG4gICAgICAgIF0sXG4gICAgICAgIC8vIGlzbyB0aW1lIGZvcm1hdHMgYW5kIHJlZ2V4ZXNcbiAgICAgICAgaXNvVGltZXMgPSBbXG4gICAgICAgICAgICBbJ0hIOm1tOnNzLlNTU1MnLCAvXFxkXFxkOlxcZFxcZDpcXGRcXGRcXC5cXGQrL10sXG4gICAgICAgICAgICBbJ0hIOm1tOnNzLFNTU1MnLCAvXFxkXFxkOlxcZFxcZDpcXGRcXGQsXFxkKy9dLFxuICAgICAgICAgICAgWydISDptbTpzcycsIC9cXGRcXGQ6XFxkXFxkOlxcZFxcZC9dLFxuICAgICAgICAgICAgWydISDptbScsIC9cXGRcXGQ6XFxkXFxkL10sXG4gICAgICAgICAgICBbJ0hIbW1zcy5TU1NTJywgL1xcZFxcZFxcZFxcZFxcZFxcZFxcLlxcZCsvXSxcbiAgICAgICAgICAgIFsnSEhtbXNzLFNTU1MnLCAvXFxkXFxkXFxkXFxkXFxkXFxkLFxcZCsvXSxcbiAgICAgICAgICAgIFsnSEhtbXNzJywgL1xcZFxcZFxcZFxcZFxcZFxcZC9dLFxuICAgICAgICAgICAgWydISG1tJywgL1xcZFxcZFxcZFxcZC9dLFxuICAgICAgICAgICAgWydISCcsIC9cXGRcXGQvXSxcbiAgICAgICAgXSxcbiAgICAgICAgYXNwTmV0SnNvblJlZ2V4ID0gL15cXC8/RGF0ZVxcKCgtP1xcZCspL2ksXG4gICAgICAgIC8vIFJGQyAyODIyIHJlZ2V4OiBGb3IgZGV0YWlscyBzZWUgaHR0cHM6Ly90b29scy5pZXRmLm9yZy9odG1sL3JmYzI4MjIjc2VjdGlvbi0zLjNcbiAgICAgICAgcmZjMjgyMiA9IC9eKD86KE1vbnxUdWV8V2VkfFRodXxGcml8U2F0fFN1biksP1xccyk/KFxcZHsxLDJ9KVxccyhKYW58RmVifE1hcnxBcHJ8TWF5fEp1bnxKdWx8QXVnfFNlcHxPY3R8Tm92fERlYylcXHMoXFxkezIsNH0pXFxzKFxcZFxcZCk6KFxcZFxcZCkoPzo6KFxcZFxcZCkpP1xccyg/OihVVHxHTVR8W0VDTVBdW1NEXVQpfChbWnpdKXwoWystXVxcZHs0fSkpJC8sXG4gICAgICAgIG9ic09mZnNldHMgPSB7XG4gICAgICAgICAgICBVVDogMCxcbiAgICAgICAgICAgIEdNVDogMCxcbiAgICAgICAgICAgIEVEVDogLTQgKiA2MCxcbiAgICAgICAgICAgIEVTVDogLTUgKiA2MCxcbiAgICAgICAgICAgIENEVDogLTUgKiA2MCxcbiAgICAgICAgICAgIENTVDogLTYgKiA2MCxcbiAgICAgICAgICAgIE1EVDogLTYgKiA2MCxcbiAgICAgICAgICAgIE1TVDogLTcgKiA2MCxcbiAgICAgICAgICAgIFBEVDogLTcgKiA2MCxcbiAgICAgICAgICAgIFBTVDogLTggKiA2MCxcbiAgICAgICAgfTtcblxuICAgIC8vIGRhdGUgZnJvbSBpc28gZm9ybWF0XG4gICAgZnVuY3Rpb24gY29uZmlnRnJvbUlTTyhjb25maWcpIHtcbiAgICAgICAgdmFyIGksXG4gICAgICAgICAgICBsLFxuICAgICAgICAgICAgc3RyaW5nID0gY29uZmlnLl9pLFxuICAgICAgICAgICAgbWF0Y2ggPSBleHRlbmRlZElzb1JlZ2V4LmV4ZWMoc3RyaW5nKSB8fCBiYXNpY0lzb1JlZ2V4LmV4ZWMoc3RyaW5nKSxcbiAgICAgICAgICAgIGFsbG93VGltZSxcbiAgICAgICAgICAgIGRhdGVGb3JtYXQsXG4gICAgICAgICAgICB0aW1lRm9ybWF0LFxuICAgICAgICAgICAgdHpGb3JtYXQ7XG5cbiAgICAgICAgaWYgKG1hdGNoKSB7XG4gICAgICAgICAgICBnZXRQYXJzaW5nRmxhZ3MoY29uZmlnKS5pc28gPSB0cnVlO1xuXG4gICAgICAgICAgICBmb3IgKGkgPSAwLCBsID0gaXNvRGF0ZXMubGVuZ3RoOyBpIDwgbDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgaWYgKGlzb0RhdGVzW2ldWzFdLmV4ZWMobWF0Y2hbMV0pKSB7XG4gICAgICAgICAgICAgICAgICAgIGRhdGVGb3JtYXQgPSBpc29EYXRlc1tpXVswXTtcbiAgICAgICAgICAgICAgICAgICAgYWxsb3dUaW1lID0gaXNvRGF0ZXNbaV1bMl0gIT09IGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoZGF0ZUZvcm1hdCA9PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgY29uZmlnLl9pc1ZhbGlkID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKG1hdGNoWzNdKSB7XG4gICAgICAgICAgICAgICAgZm9yIChpID0gMCwgbCA9IGlzb1RpbWVzLmxlbmd0aDsgaSA8IGw7IGkrKykge1xuICAgICAgICAgICAgICAgICAgICBpZiAoaXNvVGltZXNbaV1bMV0uZXhlYyhtYXRjaFszXSkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIG1hdGNoWzJdIHNob3VsZCBiZSAnVCcgb3Igc3BhY2VcbiAgICAgICAgICAgICAgICAgICAgICAgIHRpbWVGb3JtYXQgPSAobWF0Y2hbMl0gfHwgJyAnKSArIGlzb1RpbWVzW2ldWzBdO1xuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKHRpbWVGb3JtYXQgPT0gbnVsbCkge1xuICAgICAgICAgICAgICAgICAgICBjb25maWcuX2lzVmFsaWQgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICghYWxsb3dUaW1lICYmIHRpbWVGb3JtYXQgIT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIGNvbmZpZy5faXNWYWxpZCA9IGZhbHNlO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChtYXRjaFs0XSkge1xuICAgICAgICAgICAgICAgIGlmICh0elJlZ2V4LmV4ZWMobWF0Y2hbNF0pKSB7XG4gICAgICAgICAgICAgICAgICAgIHR6Rm9ybWF0ID0gJ1onO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbmZpZy5faXNWYWxpZCA9IGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uZmlnLl9mID0gZGF0ZUZvcm1hdCArICh0aW1lRm9ybWF0IHx8ICcnKSArICh0ekZvcm1hdCB8fCAnJyk7XG4gICAgICAgICAgICBjb25maWdGcm9tU3RyaW5nQW5kRm9ybWF0KGNvbmZpZyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25maWcuX2lzVmFsaWQgPSBmYWxzZTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIGV4dHJhY3RGcm9tUkZDMjgyMlN0cmluZ3MoXG4gICAgICAgIHllYXJTdHIsXG4gICAgICAgIG1vbnRoU3RyLFxuICAgICAgICBkYXlTdHIsXG4gICAgICAgIGhvdXJTdHIsXG4gICAgICAgIG1pbnV0ZVN0cixcbiAgICAgICAgc2Vjb25kU3RyXG4gICAgKSB7XG4gICAgICAgIHZhciByZXN1bHQgPSBbXG4gICAgICAgICAgICB1bnRydW5jYXRlWWVhcih5ZWFyU3RyKSxcbiAgICAgICAgICAgIGRlZmF1bHRMb2NhbGVNb250aHNTaG9ydC5pbmRleE9mKG1vbnRoU3RyKSxcbiAgICAgICAgICAgIHBhcnNlSW50KGRheVN0ciwgMTApLFxuICAgICAgICAgICAgcGFyc2VJbnQoaG91clN0ciwgMTApLFxuICAgICAgICAgICAgcGFyc2VJbnQobWludXRlU3RyLCAxMCksXG4gICAgICAgIF07XG5cbiAgICAgICAgaWYgKHNlY29uZFN0cikge1xuICAgICAgICAgICAgcmVzdWx0LnB1c2gocGFyc2VJbnQoc2Vjb25kU3RyLCAxMCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiB1bnRydW5jYXRlWWVhcih5ZWFyU3RyKSB7XG4gICAgICAgIHZhciB5ZWFyID0gcGFyc2VJbnQoeWVhclN0ciwgMTApO1xuICAgICAgICBpZiAoeWVhciA8PSA0OSkge1xuICAgICAgICAgICAgcmV0dXJuIDIwMDAgKyB5ZWFyO1xuICAgICAgICB9IGVsc2UgaWYgKHllYXIgPD0gOTk5KSB7XG4gICAgICAgICAgICByZXR1cm4gMTkwMCArIHllYXI7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHllYXI7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gcHJlcHJvY2Vzc1JGQzI4MjIocykge1xuICAgICAgICAvLyBSZW1vdmUgY29tbWVudHMgYW5kIGZvbGRpbmcgd2hpdGVzcGFjZSBhbmQgcmVwbGFjZSBtdWx0aXBsZS1zcGFjZXMgd2l0aCBhIHNpbmdsZSBzcGFjZVxuICAgICAgICByZXR1cm4gc1xuICAgICAgICAgICAgLnJlcGxhY2UoL1xcKFteKV0qXFwpfFtcXG5cXHRdL2csICcgJylcbiAgICAgICAgICAgIC5yZXBsYWNlKC8oXFxzXFxzKykvZywgJyAnKVxuICAgICAgICAgICAgLnJlcGxhY2UoL15cXHNcXHMqLywgJycpXG4gICAgICAgICAgICAucmVwbGFjZSgvXFxzXFxzKiQvLCAnJyk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gY2hlY2tXZWVrZGF5KHdlZWtkYXlTdHIsIHBhcnNlZElucHV0LCBjb25maWcpIHtcbiAgICAgICAgaWYgKHdlZWtkYXlTdHIpIHtcbiAgICAgICAgICAgIC8vIFRPRE86IFJlcGxhY2UgdGhlIHZhbmlsbGEgSlMgRGF0ZSBvYmplY3Qgd2l0aCBhbiBpbmRlcGVuZGVudCBkYXktb2Ytd2VlayBjaGVjay5cbiAgICAgICAgICAgIHZhciB3ZWVrZGF5UHJvdmlkZWQgPSBkZWZhdWx0TG9jYWxlV2Vla2RheXNTaG9ydC5pbmRleE9mKHdlZWtkYXlTdHIpLFxuICAgICAgICAgICAgICAgIHdlZWtkYXlBY3R1YWwgPSBuZXcgRGF0ZShcbiAgICAgICAgICAgICAgICAgICAgcGFyc2VkSW5wdXRbMF0sXG4gICAgICAgICAgICAgICAgICAgIHBhcnNlZElucHV0WzFdLFxuICAgICAgICAgICAgICAgICAgICBwYXJzZWRJbnB1dFsyXVxuICAgICAgICAgICAgICAgICkuZ2V0RGF5KCk7XG4gICAgICAgICAgICBpZiAod2Vla2RheVByb3ZpZGVkICE9PSB3ZWVrZGF5QWN0dWFsKSB7XG4gICAgICAgICAgICAgICAgZ2V0UGFyc2luZ0ZsYWdzKGNvbmZpZykud2Vla2RheU1pc21hdGNoID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICBjb25maWcuX2lzVmFsaWQgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gY2FsY3VsYXRlT2Zmc2V0KG9ic09mZnNldCwgbWlsaXRhcnlPZmZzZXQsIG51bU9mZnNldCkge1xuICAgICAgICBpZiAob2JzT2Zmc2V0KSB7XG4gICAgICAgICAgICByZXR1cm4gb2JzT2Zmc2V0c1tvYnNPZmZzZXRdO1xuICAgICAgICB9IGVsc2UgaWYgKG1pbGl0YXJ5T2Zmc2V0KSB7XG4gICAgICAgICAgICAvLyB0aGUgb25seSBhbGxvd2VkIG1pbGl0YXJ5IHR6IGlzIFpcbiAgICAgICAgICAgIHJldHVybiAwO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdmFyIGhtID0gcGFyc2VJbnQobnVtT2Zmc2V0LCAxMCksXG4gICAgICAgICAgICAgICAgbSA9IGhtICUgMTAwLFxuICAgICAgICAgICAgICAgIGggPSAoaG0gLSBtKSAvIDEwMDtcbiAgICAgICAgICAgIHJldHVybiBoICogNjAgKyBtO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gZGF0ZSBhbmQgdGltZSBmcm9tIHJlZiAyODIyIGZvcm1hdFxuICAgIGZ1bmN0aW9uIGNvbmZpZ0Zyb21SRkMyODIyKGNvbmZpZykge1xuICAgICAgICB2YXIgbWF0Y2ggPSByZmMyODIyLmV4ZWMocHJlcHJvY2Vzc1JGQzI4MjIoY29uZmlnLl9pKSksXG4gICAgICAgICAgICBwYXJzZWRBcnJheTtcbiAgICAgICAgaWYgKG1hdGNoKSB7XG4gICAgICAgICAgICBwYXJzZWRBcnJheSA9IGV4dHJhY3RGcm9tUkZDMjgyMlN0cmluZ3MoXG4gICAgICAgICAgICAgICAgbWF0Y2hbNF0sXG4gICAgICAgICAgICAgICAgbWF0Y2hbM10sXG4gICAgICAgICAgICAgICAgbWF0Y2hbMl0sXG4gICAgICAgICAgICAgICAgbWF0Y2hbNV0sXG4gICAgICAgICAgICAgICAgbWF0Y2hbNl0sXG4gICAgICAgICAgICAgICAgbWF0Y2hbN11cbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBpZiAoIWNoZWNrV2Vla2RheShtYXRjaFsxXSwgcGFyc2VkQXJyYXksIGNvbmZpZykpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNvbmZpZy5fYSA9IHBhcnNlZEFycmF5O1xuICAgICAgICAgICAgY29uZmlnLl90em0gPSBjYWxjdWxhdGVPZmZzZXQobWF0Y2hbOF0sIG1hdGNoWzldLCBtYXRjaFsxMF0pO1xuXG4gICAgICAgICAgICBjb25maWcuX2QgPSBjcmVhdGVVVENEYXRlLmFwcGx5KG51bGwsIGNvbmZpZy5fYSk7XG4gICAgICAgICAgICBjb25maWcuX2Quc2V0VVRDTWludXRlcyhjb25maWcuX2QuZ2V0VVRDTWludXRlcygpIC0gY29uZmlnLl90em0pO1xuXG4gICAgICAgICAgICBnZXRQYXJzaW5nRmxhZ3MoY29uZmlnKS5yZmMyODIyID0gdHJ1ZTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvbmZpZy5faXNWYWxpZCA9IGZhbHNlO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gZGF0ZSBmcm9tIDEpIEFTUC5ORVQsIDIpIElTTywgMykgUkZDIDI4MjIgZm9ybWF0cywgb3IgNCkgb3B0aW9uYWwgZmFsbGJhY2sgaWYgcGFyc2luZyBpc24ndCBzdHJpY3RcbiAgICBmdW5jdGlvbiBjb25maWdGcm9tU3RyaW5nKGNvbmZpZykge1xuICAgICAgICB2YXIgbWF0Y2hlZCA9IGFzcE5ldEpzb25SZWdleC5leGVjKGNvbmZpZy5faSk7XG4gICAgICAgIGlmIChtYXRjaGVkICE9PSBudWxsKSB7XG4gICAgICAgICAgICBjb25maWcuX2QgPSBuZXcgRGF0ZSgrbWF0Y2hlZFsxXSk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25maWdGcm9tSVNPKGNvbmZpZyk7XG4gICAgICAgIGlmIChjb25maWcuX2lzVmFsaWQgPT09IGZhbHNlKSB7XG4gICAgICAgICAgICBkZWxldGUgY29uZmlnLl9pc1ZhbGlkO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uZmlnRnJvbVJGQzI4MjIoY29uZmlnKTtcbiAgICAgICAgaWYgKGNvbmZpZy5faXNWYWxpZCA9PT0gZmFsc2UpIHtcbiAgICAgICAgICAgIGRlbGV0ZSBjb25maWcuX2lzVmFsaWQ7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoY29uZmlnLl9zdHJpY3QpIHtcbiAgICAgICAgICAgIGNvbmZpZy5faXNWYWxpZCA9IGZhbHNlO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gRmluYWwgYXR0ZW1wdCwgdXNlIElucHV0IEZhbGxiYWNrXG4gICAgICAgICAgICBob29rcy5jcmVhdGVGcm9tSW5wdXRGYWxsYmFjayhjb25maWcpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgaG9va3MuY3JlYXRlRnJvbUlucHV0RmFsbGJhY2sgPSBkZXByZWNhdGUoXG4gICAgICAgICd2YWx1ZSBwcm92aWRlZCBpcyBub3QgaW4gYSByZWNvZ25pemVkIFJGQzI4MjIgb3IgSVNPIGZvcm1hdC4gbW9tZW50IGNvbnN0cnVjdGlvbiBmYWxscyBiYWNrIHRvIGpzIERhdGUoKSwgJyArXG4gICAgICAgICAgICAnd2hpY2ggaXMgbm90IHJlbGlhYmxlIGFjcm9zcyBhbGwgYnJvd3NlcnMgYW5kIHZlcnNpb25zLiBOb24gUkZDMjgyMi9JU08gZGF0ZSBmb3JtYXRzIGFyZSAnICtcbiAgICAgICAgICAgICdkaXNjb3VyYWdlZCBhbmQgd2lsbCBiZSByZW1vdmVkIGluIGFuIHVwY29taW5nIG1ham9yIHJlbGVhc2UuIFBsZWFzZSByZWZlciB0byAnICtcbiAgICAgICAgICAgICdodHRwOi8vbW9tZW50anMuY29tL2d1aWRlcy8jL3dhcm5pbmdzL2pzLWRhdGUvIGZvciBtb3JlIGluZm8uJyxcbiAgICAgICAgZnVuY3Rpb24gKGNvbmZpZykge1xuICAgICAgICAgICAgY29uZmlnLl9kID0gbmV3IERhdGUoY29uZmlnLl9pICsgKGNvbmZpZy5fdXNlVVRDID8gJyBVVEMnIDogJycpKTtcbiAgICAgICAgfVxuICAgICk7XG5cbiAgICAvLyBQaWNrIHRoZSBmaXJzdCBkZWZpbmVkIG9mIHR3byBvciB0aHJlZSBhcmd1bWVudHMuXG4gICAgZnVuY3Rpb24gZGVmYXVsdHMoYSwgYiwgYykge1xuICAgICAgICBpZiAoYSAhPSBudWxsKSB7XG4gICAgICAgICAgICByZXR1cm4gYTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoYiAhPSBudWxsKSB7XG4gICAgICAgICAgICByZXR1cm4gYjtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gYztcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBjdXJyZW50RGF0ZUFycmF5KGNvbmZpZykge1xuICAgICAgICAvLyBob29rcyBpcyBhY3R1YWxseSB0aGUgZXhwb3J0ZWQgbW9tZW50IG9iamVjdFxuICAgICAgICB2YXIgbm93VmFsdWUgPSBuZXcgRGF0ZShob29rcy5ub3coKSk7XG4gICAgICAgIGlmIChjb25maWcuX3VzZVVUQykge1xuICAgICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgICAgICBub3dWYWx1ZS5nZXRVVENGdWxsWWVhcigpLFxuICAgICAgICAgICAgICAgIG5vd1ZhbHVlLmdldFVUQ01vbnRoKCksXG4gICAgICAgICAgICAgICAgbm93VmFsdWUuZ2V0VVRDRGF0ZSgpLFxuICAgICAgICAgICAgXTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gW25vd1ZhbHVlLmdldEZ1bGxZZWFyKCksIG5vd1ZhbHVlLmdldE1vbnRoKCksIG5vd1ZhbHVlLmdldERhdGUoKV07XG4gICAgfVxuXG4gICAgLy8gY29udmVydCBhbiBhcnJheSB0byBhIGRhdGUuXG4gICAgLy8gdGhlIGFycmF5IHNob3VsZCBtaXJyb3IgdGhlIHBhcmFtZXRlcnMgYmVsb3dcbiAgICAvLyBub3RlOiBhbGwgdmFsdWVzIHBhc3QgdGhlIHllYXIgYXJlIG9wdGlvbmFsIGFuZCB3aWxsIGRlZmF1bHQgdG8gdGhlIGxvd2VzdCBwb3NzaWJsZSB2YWx1ZS5cbiAgICAvLyBbeWVhciwgbW9udGgsIGRheSAsIGhvdXIsIG1pbnV0ZSwgc2Vjb25kLCBtaWxsaXNlY29uZF1cbiAgICBmdW5jdGlvbiBjb25maWdGcm9tQXJyYXkoY29uZmlnKSB7XG4gICAgICAgIHZhciBpLFxuICAgICAgICAgICAgZGF0ZSxcbiAgICAgICAgICAgIGlucHV0ID0gW10sXG4gICAgICAgICAgICBjdXJyZW50RGF0ZSxcbiAgICAgICAgICAgIGV4cGVjdGVkV2Vla2RheSxcbiAgICAgICAgICAgIHllYXJUb1VzZTtcblxuICAgICAgICBpZiAoY29uZmlnLl9kKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjdXJyZW50RGF0ZSA9IGN1cnJlbnREYXRlQXJyYXkoY29uZmlnKTtcblxuICAgICAgICAvL2NvbXB1dGUgZGF5IG9mIHRoZSB5ZWFyIGZyb20gd2Vla3MgYW5kIHdlZWtkYXlzXG4gICAgICAgIGlmIChjb25maWcuX3cgJiYgY29uZmlnLl9hW0RBVEVdID09IG51bGwgJiYgY29uZmlnLl9hW01PTlRIXSA9PSBudWxsKSB7XG4gICAgICAgICAgICBkYXlPZlllYXJGcm9tV2Vla0luZm8oY29uZmlnKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vaWYgdGhlIGRheSBvZiB0aGUgeWVhciBpcyBzZXQsIGZpZ3VyZSBvdXQgd2hhdCBpdCBpc1xuICAgICAgICBpZiAoY29uZmlnLl9kYXlPZlllYXIgIT0gbnVsbCkge1xuICAgICAgICAgICAgeWVhclRvVXNlID0gZGVmYXVsdHMoY29uZmlnLl9hW1lFQVJdLCBjdXJyZW50RGF0ZVtZRUFSXSk7XG5cbiAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICBjb25maWcuX2RheU9mWWVhciA+IGRheXNJblllYXIoeWVhclRvVXNlKSB8fFxuICAgICAgICAgICAgICAgIGNvbmZpZy5fZGF5T2ZZZWFyID09PSAwXG4gICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICBnZXRQYXJzaW5nRmxhZ3MoY29uZmlnKS5fb3ZlcmZsb3dEYXlPZlllYXIgPSB0cnVlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBkYXRlID0gY3JlYXRlVVRDRGF0ZSh5ZWFyVG9Vc2UsIDAsIGNvbmZpZy5fZGF5T2ZZZWFyKTtcbiAgICAgICAgICAgIGNvbmZpZy5fYVtNT05USF0gPSBkYXRlLmdldFVUQ01vbnRoKCk7XG4gICAgICAgICAgICBjb25maWcuX2FbREFURV0gPSBkYXRlLmdldFVUQ0RhdGUoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIERlZmF1bHQgdG8gY3VycmVudCBkYXRlLlxuICAgICAgICAvLyAqIGlmIG5vIHllYXIsIG1vbnRoLCBkYXkgb2YgbW9udGggYXJlIGdpdmVuLCBkZWZhdWx0IHRvIHRvZGF5XG4gICAgICAgIC8vICogaWYgZGF5IG9mIG1vbnRoIGlzIGdpdmVuLCBkZWZhdWx0IG1vbnRoIGFuZCB5ZWFyXG4gICAgICAgIC8vICogaWYgbW9udGggaXMgZ2l2ZW4sIGRlZmF1bHQgb25seSB5ZWFyXG4gICAgICAgIC8vICogaWYgeWVhciBpcyBnaXZlbiwgZG9uJ3QgZGVmYXVsdCBhbnl0aGluZ1xuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgMyAmJiBjb25maWcuX2FbaV0gPT0gbnVsbDsgKytpKSB7XG4gICAgICAgICAgICBjb25maWcuX2FbaV0gPSBpbnB1dFtpXSA9IGN1cnJlbnREYXRlW2ldO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gWmVybyBvdXQgd2hhdGV2ZXIgd2FzIG5vdCBkZWZhdWx0ZWQsIGluY2x1ZGluZyB0aW1lXG4gICAgICAgIGZvciAoOyBpIDwgNzsgaSsrKSB7XG4gICAgICAgICAgICBjb25maWcuX2FbaV0gPSBpbnB1dFtpXSA9XG4gICAgICAgICAgICAgICAgY29uZmlnLl9hW2ldID09IG51bGwgPyAoaSA9PT0gMiA/IDEgOiAwKSA6IGNvbmZpZy5fYVtpXTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIENoZWNrIGZvciAyNDowMDowMC4wMDBcbiAgICAgICAgaWYgKFxuICAgICAgICAgICAgY29uZmlnLl9hW0hPVVJdID09PSAyNCAmJlxuICAgICAgICAgICAgY29uZmlnLl9hW01JTlVURV0gPT09IDAgJiZcbiAgICAgICAgICAgIGNvbmZpZy5fYVtTRUNPTkRdID09PSAwICYmXG4gICAgICAgICAgICBjb25maWcuX2FbTUlMTElTRUNPTkRdID09PSAwXG4gICAgICAgICkge1xuICAgICAgICAgICAgY29uZmlnLl9uZXh0RGF5ID0gdHJ1ZTtcbiAgICAgICAgICAgIGNvbmZpZy5fYVtIT1VSXSA9IDA7XG4gICAgICAgIH1cblxuICAgICAgICBjb25maWcuX2QgPSAoY29uZmlnLl91c2VVVEMgPyBjcmVhdGVVVENEYXRlIDogY3JlYXRlRGF0ZSkuYXBwbHkoXG4gICAgICAgICAgICBudWxsLFxuICAgICAgICAgICAgaW5wdXRcbiAgICAgICAgKTtcbiAgICAgICAgZXhwZWN0ZWRXZWVrZGF5ID0gY29uZmlnLl91c2VVVENcbiAgICAgICAgICAgID8gY29uZmlnLl9kLmdldFVUQ0RheSgpXG4gICAgICAgICAgICA6IGNvbmZpZy5fZC5nZXREYXkoKTtcblxuICAgICAgICAvLyBBcHBseSB0aW1lem9uZSBvZmZzZXQgZnJvbSBpbnB1dC4gVGhlIGFjdHVhbCB1dGNPZmZzZXQgY2FuIGJlIGNoYW5nZWRcbiAgICAgICAgLy8gd2l0aCBwYXJzZVpvbmUuXG4gICAgICAgIGlmIChjb25maWcuX3R6bSAhPSBudWxsKSB7XG4gICAgICAgICAgICBjb25maWcuX2Quc2V0VVRDTWludXRlcyhjb25maWcuX2QuZ2V0VVRDTWludXRlcygpIC0gY29uZmlnLl90em0pO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGNvbmZpZy5fbmV4dERheSkge1xuICAgICAgICAgICAgY29uZmlnLl9hW0hPVVJdID0gMjQ7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBjaGVjayBmb3IgbWlzbWF0Y2hpbmcgZGF5IG9mIHdlZWtcbiAgICAgICAgaWYgKFxuICAgICAgICAgICAgY29uZmlnLl93ICYmXG4gICAgICAgICAgICB0eXBlb2YgY29uZmlnLl93LmQgIT09ICd1bmRlZmluZWQnICYmXG4gICAgICAgICAgICBjb25maWcuX3cuZCAhPT0gZXhwZWN0ZWRXZWVrZGF5XG4gICAgICAgICkge1xuICAgICAgICAgICAgZ2V0UGFyc2luZ0ZsYWdzKGNvbmZpZykud2Vla2RheU1pc21hdGNoID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIGRheU9mWWVhckZyb21XZWVrSW5mbyhjb25maWcpIHtcbiAgICAgICAgdmFyIHcsIHdlZWtZZWFyLCB3ZWVrLCB3ZWVrZGF5LCBkb3csIGRveSwgdGVtcCwgd2Vla2RheU92ZXJmbG93LCBjdXJXZWVrO1xuXG4gICAgICAgIHcgPSBjb25maWcuX3c7XG4gICAgICAgIGlmICh3LkdHICE9IG51bGwgfHwgdy5XICE9IG51bGwgfHwgdy5FICE9IG51bGwpIHtcbiAgICAgICAgICAgIGRvdyA9IDE7XG4gICAgICAgICAgICBkb3kgPSA0O1xuXG4gICAgICAgICAgICAvLyBUT0RPOiBXZSBuZWVkIHRvIHRha2UgdGhlIGN1cnJlbnQgaXNvV2Vla1llYXIsIGJ1dCB0aGF0IGRlcGVuZHMgb25cbiAgICAgICAgICAgIC8vIGhvdyB3ZSBpbnRlcnByZXQgbm93IChsb2NhbCwgdXRjLCBmaXhlZCBvZmZzZXQpLiBTbyBjcmVhdGVcbiAgICAgICAgICAgIC8vIGEgbm93IHZlcnNpb24gb2YgY3VycmVudCBjb25maWcgKHRha2UgbG9jYWwvdXRjL29mZnNldCBmbGFncywgYW5kXG4gICAgICAgICAgICAvLyBjcmVhdGUgbm93KS5cbiAgICAgICAgICAgIHdlZWtZZWFyID0gZGVmYXVsdHMoXG4gICAgICAgICAgICAgICAgdy5HRyxcbiAgICAgICAgICAgICAgICBjb25maWcuX2FbWUVBUl0sXG4gICAgICAgICAgICAgICAgd2Vla09mWWVhcihjcmVhdGVMb2NhbCgpLCAxLCA0KS55ZWFyXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgd2VlayA9IGRlZmF1bHRzKHcuVywgMSk7XG4gICAgICAgICAgICB3ZWVrZGF5ID0gZGVmYXVsdHMody5FLCAxKTtcbiAgICAgICAgICAgIGlmICh3ZWVrZGF5IDwgMSB8fCB3ZWVrZGF5ID4gNykge1xuICAgICAgICAgICAgICAgIHdlZWtkYXlPdmVyZmxvdyA9IHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBkb3cgPSBjb25maWcuX2xvY2FsZS5fd2Vlay5kb3c7XG4gICAgICAgICAgICBkb3kgPSBjb25maWcuX2xvY2FsZS5fd2Vlay5kb3k7XG5cbiAgICAgICAgICAgIGN1cldlZWsgPSB3ZWVrT2ZZZWFyKGNyZWF0ZUxvY2FsKCksIGRvdywgZG95KTtcblxuICAgICAgICAgICAgd2Vla1llYXIgPSBkZWZhdWx0cyh3LmdnLCBjb25maWcuX2FbWUVBUl0sIGN1cldlZWsueWVhcik7XG5cbiAgICAgICAgICAgIC8vIERlZmF1bHQgdG8gY3VycmVudCB3ZWVrLlxuICAgICAgICAgICAgd2VlayA9IGRlZmF1bHRzKHcudywgY3VyV2Vlay53ZWVrKTtcblxuICAgICAgICAgICAgaWYgKHcuZCAhPSBudWxsKSB7XG4gICAgICAgICAgICAgICAgLy8gd2Vla2RheSAtLSBsb3cgZGF5IG51bWJlcnMgYXJlIGNvbnNpZGVyZWQgbmV4dCB3ZWVrXG4gICAgICAgICAgICAgICAgd2Vla2RheSA9IHcuZDtcbiAgICAgICAgICAgICAgICBpZiAod2Vla2RheSA8IDAgfHwgd2Vla2RheSA+IDYpIHtcbiAgICAgICAgICAgICAgICAgICAgd2Vla2RheU92ZXJmbG93ID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2UgaWYgKHcuZSAhPSBudWxsKSB7XG4gICAgICAgICAgICAgICAgLy8gbG9jYWwgd2Vla2RheSAtLSBjb3VudGluZyBzdGFydHMgZnJvbSBiZWdpbm5pbmcgb2Ygd2Vla1xuICAgICAgICAgICAgICAgIHdlZWtkYXkgPSB3LmUgKyBkb3c7XG4gICAgICAgICAgICAgICAgaWYgKHcuZSA8IDAgfHwgdy5lID4gNikge1xuICAgICAgICAgICAgICAgICAgICB3ZWVrZGF5T3ZlcmZsb3cgPSB0cnVlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgLy8gZGVmYXVsdCB0byBiZWdpbm5pbmcgb2Ygd2Vla1xuICAgICAgICAgICAgICAgIHdlZWtkYXkgPSBkb3c7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHdlZWsgPCAxIHx8IHdlZWsgPiB3ZWVrc0luWWVhcih3ZWVrWWVhciwgZG93LCBkb3kpKSB7XG4gICAgICAgICAgICBnZXRQYXJzaW5nRmxhZ3MoY29uZmlnKS5fb3ZlcmZsb3dXZWVrcyA9IHRydWU7XG4gICAgICAgIH0gZWxzZSBpZiAod2Vla2RheU92ZXJmbG93ICE9IG51bGwpIHtcbiAgICAgICAgICAgIGdldFBhcnNpbmdGbGFncyhjb25maWcpLl9vdmVyZmxvd1dlZWtkYXkgPSB0cnVlO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGVtcCA9IGRheU9mWWVhckZyb21XZWVrcyh3ZWVrWWVhciwgd2Vlaywgd2Vla2RheSwgZG93LCBkb3kpO1xuICAgICAgICAgICAgY29uZmlnLl9hW1lFQVJdID0gdGVtcC55ZWFyO1xuICAgICAgICAgICAgY29uZmlnLl9kYXlPZlllYXIgPSB0ZW1wLmRheU9mWWVhcjtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vIGNvbnN0YW50IHRoYXQgcmVmZXJzIHRvIHRoZSBJU08gc3RhbmRhcmRcbiAgICBob29rcy5JU09fODYwMSA9IGZ1bmN0aW9uICgpIHt9O1xuXG4gICAgLy8gY29uc3RhbnQgdGhhdCByZWZlcnMgdG8gdGhlIFJGQyAyODIyIGZvcm1cbiAgICBob29rcy5SRkNfMjgyMiA9IGZ1bmN0aW9uICgpIHt9O1xuXG4gICAgLy8gZGF0ZSBmcm9tIHN0cmluZyBhbmQgZm9ybWF0IHN0cmluZ1xuICAgIGZ1bmN0aW9uIGNvbmZpZ0Zyb21TdHJpbmdBbmRGb3JtYXQoY29uZmlnKSB7XG4gICAgICAgIC8vIFRPRE86IE1vdmUgdGhpcyB0byBhbm90aGVyIHBhcnQgb2YgdGhlIGNyZWF0aW9uIGZsb3cgdG8gcHJldmVudCBjaXJjdWxhciBkZXBzXG4gICAgICAgIGlmIChjb25maWcuX2YgPT09IGhvb2tzLklTT184NjAxKSB7XG4gICAgICAgICAgICBjb25maWdGcm9tSVNPKGNvbmZpZyk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGNvbmZpZy5fZiA9PT0gaG9va3MuUkZDXzI4MjIpIHtcbiAgICAgICAgICAgIGNvbmZpZ0Zyb21SRkMyODIyKGNvbmZpZyk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgY29uZmlnLl9hID0gW107XG4gICAgICAgIGdldFBhcnNpbmdGbGFncyhjb25maWcpLmVtcHR5ID0gdHJ1ZTtcblxuICAgICAgICAvLyBUaGlzIGFycmF5IGlzIHVzZWQgdG8gbWFrZSBhIERhdGUsIGVpdGhlciB3aXRoIGBuZXcgRGF0ZWAgb3IgYERhdGUuVVRDYFxuICAgICAgICB2YXIgc3RyaW5nID0gJycgKyBjb25maWcuX2ksXG4gICAgICAgICAgICBpLFxuICAgICAgICAgICAgcGFyc2VkSW5wdXQsXG4gICAgICAgICAgICB0b2tlbnMsXG4gICAgICAgICAgICB0b2tlbixcbiAgICAgICAgICAgIHNraXBwZWQsXG4gICAgICAgICAgICBzdHJpbmdMZW5ndGggPSBzdHJpbmcubGVuZ3RoLFxuICAgICAgICAgICAgdG90YWxQYXJzZWRJbnB1dExlbmd0aCA9IDAsXG4gICAgICAgICAgICBlcmE7XG5cbiAgICAgICAgdG9rZW5zID1cbiAgICAgICAgICAgIGV4cGFuZEZvcm1hdChjb25maWcuX2YsIGNvbmZpZy5fbG9jYWxlKS5tYXRjaChmb3JtYXR0aW5nVG9rZW5zKSB8fCBbXTtcblxuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgdG9rZW5zLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICB0b2tlbiA9IHRva2Vuc1tpXTtcbiAgICAgICAgICAgIHBhcnNlZElucHV0ID0gKHN0cmluZy5tYXRjaChnZXRQYXJzZVJlZ2V4Rm9yVG9rZW4odG9rZW4sIGNvbmZpZykpIHx8XG4gICAgICAgICAgICAgICAgW10pWzBdO1xuICAgICAgICAgICAgaWYgKHBhcnNlZElucHV0KSB7XG4gICAgICAgICAgICAgICAgc2tpcHBlZCA9IHN0cmluZy5zdWJzdHIoMCwgc3RyaW5nLmluZGV4T2YocGFyc2VkSW5wdXQpKTtcbiAgICAgICAgICAgICAgICBpZiAoc2tpcHBlZC5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIGdldFBhcnNpbmdGbGFncyhjb25maWcpLnVudXNlZElucHV0LnB1c2goc2tpcHBlZCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHN0cmluZyA9IHN0cmluZy5zbGljZShcbiAgICAgICAgICAgICAgICAgICAgc3RyaW5nLmluZGV4T2YocGFyc2VkSW5wdXQpICsgcGFyc2VkSW5wdXQubGVuZ3RoXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB0b3RhbFBhcnNlZElucHV0TGVuZ3RoICs9IHBhcnNlZElucHV0Lmxlbmd0aDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIGRvbid0IHBhcnNlIGlmIGl0J3Mgbm90IGEga25vd24gdG9rZW5cbiAgICAgICAgICAgIGlmIChmb3JtYXRUb2tlbkZ1bmN0aW9uc1t0b2tlbl0pIHtcbiAgICAgICAgICAgICAgICBpZiAocGFyc2VkSW5wdXQpIHtcbiAgICAgICAgICAgICAgICAgICAgZ2V0UGFyc2luZ0ZsYWdzKGNvbmZpZykuZW1wdHkgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBnZXRQYXJzaW5nRmxhZ3MoY29uZmlnKS51bnVzZWRUb2tlbnMucHVzaCh0b2tlbik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGFkZFRpbWVUb0FycmF5RnJvbVRva2VuKHRva2VuLCBwYXJzZWRJbnB1dCwgY29uZmlnKTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoY29uZmlnLl9zdHJpY3QgJiYgIXBhcnNlZElucHV0KSB7XG4gICAgICAgICAgICAgICAgZ2V0UGFyc2luZ0ZsYWdzKGNvbmZpZykudW51c2VkVG9rZW5zLnB1c2godG9rZW4pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gYWRkIHJlbWFpbmluZyB1bnBhcnNlZCBpbnB1dCBsZW5ndGggdG8gdGhlIHN0cmluZ1xuICAgICAgICBnZXRQYXJzaW5nRmxhZ3MoY29uZmlnKS5jaGFyc0xlZnRPdmVyID1cbiAgICAgICAgICAgIHN0cmluZ0xlbmd0aCAtIHRvdGFsUGFyc2VkSW5wdXRMZW5ndGg7XG4gICAgICAgIGlmIChzdHJpbmcubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgZ2V0UGFyc2luZ0ZsYWdzKGNvbmZpZykudW51c2VkSW5wdXQucHVzaChzdHJpbmcpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gY2xlYXIgXzEyaCBmbGFnIGlmIGhvdXIgaXMgPD0gMTJcbiAgICAgICAgaWYgKFxuICAgICAgICAgICAgY29uZmlnLl9hW0hPVVJdIDw9IDEyICYmXG4gICAgICAgICAgICBnZXRQYXJzaW5nRmxhZ3MoY29uZmlnKS5iaWdIb3VyID09PSB0cnVlICYmXG4gICAgICAgICAgICBjb25maWcuX2FbSE9VUl0gPiAwXG4gICAgICAgICkge1xuICAgICAgICAgICAgZ2V0UGFyc2luZ0ZsYWdzKGNvbmZpZykuYmlnSG91ciA9IHVuZGVmaW5lZDtcbiAgICAgICAgfVxuXG4gICAgICAgIGdldFBhcnNpbmdGbGFncyhjb25maWcpLnBhcnNlZERhdGVQYXJ0cyA9IGNvbmZpZy5fYS5zbGljZSgwKTtcbiAgICAgICAgZ2V0UGFyc2luZ0ZsYWdzKGNvbmZpZykubWVyaWRpZW0gPSBjb25maWcuX21lcmlkaWVtO1xuICAgICAgICAvLyBoYW5kbGUgbWVyaWRpZW1cbiAgICAgICAgY29uZmlnLl9hW0hPVVJdID0gbWVyaWRpZW1GaXhXcmFwKFxuICAgICAgICAgICAgY29uZmlnLl9sb2NhbGUsXG4gICAgICAgICAgICBjb25maWcuX2FbSE9VUl0sXG4gICAgICAgICAgICBjb25maWcuX21lcmlkaWVtXG4gICAgICAgICk7XG5cbiAgICAgICAgLy8gaGFuZGxlIGVyYVxuICAgICAgICBlcmEgPSBnZXRQYXJzaW5nRmxhZ3MoY29uZmlnKS5lcmE7XG4gICAgICAgIGlmIChlcmEgIT09IG51bGwpIHtcbiAgICAgICAgICAgIGNvbmZpZy5fYVtZRUFSXSA9IGNvbmZpZy5fbG9jYWxlLmVyYXNDb252ZXJ0WWVhcihlcmEsIGNvbmZpZy5fYVtZRUFSXSk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25maWdGcm9tQXJyYXkoY29uZmlnKTtcbiAgICAgICAgY2hlY2tPdmVyZmxvdyhjb25maWcpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIG1lcmlkaWVtRml4V3JhcChsb2NhbGUsIGhvdXIsIG1lcmlkaWVtKSB7XG4gICAgICAgIHZhciBpc1BtO1xuXG4gICAgICAgIGlmIChtZXJpZGllbSA9PSBudWxsKSB7XG4gICAgICAgICAgICAvLyBub3RoaW5nIHRvIGRvXG4gICAgICAgICAgICByZXR1cm4gaG91cjtcbiAgICAgICAgfVxuICAgICAgICBpZiAobG9jYWxlLm1lcmlkaWVtSG91ciAhPSBudWxsKSB7XG4gICAgICAgICAgICByZXR1cm4gbG9jYWxlLm1lcmlkaWVtSG91cihob3VyLCBtZXJpZGllbSk7XG4gICAgICAgIH0gZWxzZSBpZiAobG9jYWxlLmlzUE0gIT0gbnVsbCkge1xuICAgICAgICAgICAgLy8gRmFsbGJhY2tcbiAgICAgICAgICAgIGlzUG0gPSBsb2NhbGUuaXNQTShtZXJpZGllbSk7XG4gICAgICAgICAgICBpZiAoaXNQbSAmJiBob3VyIDwgMTIpIHtcbiAgICAgICAgICAgICAgICBob3VyICs9IDEyO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFpc1BtICYmIGhvdXIgPT09IDEyKSB7XG4gICAgICAgICAgICAgICAgaG91ciA9IDA7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gaG91cjtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIHRoaXMgaXMgbm90IHN1cHBvc2VkIHRvIGhhcHBlblxuICAgICAgICAgICAgcmV0dXJuIGhvdXI7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBkYXRlIGZyb20gc3RyaW5nIGFuZCBhcnJheSBvZiBmb3JtYXQgc3RyaW5nc1xuICAgIGZ1bmN0aW9uIGNvbmZpZ0Zyb21TdHJpbmdBbmRBcnJheShjb25maWcpIHtcbiAgICAgICAgdmFyIHRlbXBDb25maWcsXG4gICAgICAgICAgICBiZXN0TW9tZW50LFxuICAgICAgICAgICAgc2NvcmVUb0JlYXQsXG4gICAgICAgICAgICBpLFxuICAgICAgICAgICAgY3VycmVudFNjb3JlLFxuICAgICAgICAgICAgdmFsaWRGb3JtYXRGb3VuZCxcbiAgICAgICAgICAgIGJlc3RGb3JtYXRJc1ZhbGlkID0gZmFsc2U7XG5cbiAgICAgICAgaWYgKGNvbmZpZy5fZi5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgIGdldFBhcnNpbmdGbGFncyhjb25maWcpLmludmFsaWRGb3JtYXQgPSB0cnVlO1xuICAgICAgICAgICAgY29uZmlnLl9kID0gbmV3IERhdGUoTmFOKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCBjb25maWcuX2YubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGN1cnJlbnRTY29yZSA9IDA7XG4gICAgICAgICAgICB2YWxpZEZvcm1hdEZvdW5kID0gZmFsc2U7XG4gICAgICAgICAgICB0ZW1wQ29uZmlnID0gY29weUNvbmZpZyh7fSwgY29uZmlnKTtcbiAgICAgICAgICAgIGlmIChjb25maWcuX3VzZVVUQyAhPSBudWxsKSB7XG4gICAgICAgICAgICAgICAgdGVtcENvbmZpZy5fdXNlVVRDID0gY29uZmlnLl91c2VVVEM7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0ZW1wQ29uZmlnLl9mID0gY29uZmlnLl9mW2ldO1xuICAgICAgICAgICAgY29uZmlnRnJvbVN0cmluZ0FuZEZvcm1hdCh0ZW1wQ29uZmlnKTtcblxuICAgICAgICAgICAgaWYgKGlzVmFsaWQodGVtcENvbmZpZykpIHtcbiAgICAgICAgICAgICAgICB2YWxpZEZvcm1hdEZvdW5kID0gdHJ1ZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gaWYgdGhlcmUgaXMgYW55IGlucHV0IHRoYXQgd2FzIG5vdCBwYXJzZWQgYWRkIGEgcGVuYWx0eSBmb3IgdGhhdCBmb3JtYXRcbiAgICAgICAgICAgIGN1cnJlbnRTY29yZSArPSBnZXRQYXJzaW5nRmxhZ3ModGVtcENvbmZpZykuY2hhcnNMZWZ0T3ZlcjtcblxuICAgICAgICAgICAgLy9vciB0b2tlbnNcbiAgICAgICAgICAgIGN1cnJlbnRTY29yZSArPSBnZXRQYXJzaW5nRmxhZ3ModGVtcENvbmZpZykudW51c2VkVG9rZW5zLmxlbmd0aCAqIDEwO1xuXG4gICAgICAgICAgICBnZXRQYXJzaW5nRmxhZ3ModGVtcENvbmZpZykuc2NvcmUgPSBjdXJyZW50U2NvcmU7XG5cbiAgICAgICAgICAgIGlmICghYmVzdEZvcm1hdElzVmFsaWQpIHtcbiAgICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgICAgIHNjb3JlVG9CZWF0ID09IG51bGwgfHxcbiAgICAgICAgICAgICAgICAgICAgY3VycmVudFNjb3JlIDwgc2NvcmVUb0JlYXQgfHxcbiAgICAgICAgICAgICAgICAgICAgdmFsaWRGb3JtYXRGb3VuZFxuICAgICAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgICAgICBzY29yZVRvQmVhdCA9IGN1cnJlbnRTY29yZTtcbiAgICAgICAgICAgICAgICAgICAgYmVzdE1vbWVudCA9IHRlbXBDb25maWc7XG4gICAgICAgICAgICAgICAgICAgIGlmICh2YWxpZEZvcm1hdEZvdW5kKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBiZXN0Rm9ybWF0SXNWYWxpZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGlmIChjdXJyZW50U2NvcmUgPCBzY29yZVRvQmVhdCkge1xuICAgICAgICAgICAgICAgICAgICBzY29yZVRvQmVhdCA9IGN1cnJlbnRTY29yZTtcbiAgICAgICAgICAgICAgICAgICAgYmVzdE1vbWVudCA9IHRlbXBDb25maWc7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgZXh0ZW5kKGNvbmZpZywgYmVzdE1vbWVudCB8fCB0ZW1wQ29uZmlnKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBjb25maWdGcm9tT2JqZWN0KGNvbmZpZykge1xuICAgICAgICBpZiAoY29uZmlnLl9kKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgaSA9IG5vcm1hbGl6ZU9iamVjdFVuaXRzKGNvbmZpZy5faSksXG4gICAgICAgICAgICBkYXlPckRhdGUgPSBpLmRheSA9PT0gdW5kZWZpbmVkID8gaS5kYXRlIDogaS5kYXk7XG4gICAgICAgIGNvbmZpZy5fYSA9IG1hcChcbiAgICAgICAgICAgIFtpLnllYXIsIGkubW9udGgsIGRheU9yRGF0ZSwgaS5ob3VyLCBpLm1pbnV0ZSwgaS5zZWNvbmQsIGkubWlsbGlzZWNvbmRdLFxuICAgICAgICAgICAgZnVuY3Rpb24gKG9iaikge1xuICAgICAgICAgICAgICAgIHJldHVybiBvYmogJiYgcGFyc2VJbnQob2JqLCAxMCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG5cbiAgICAgICAgY29uZmlnRnJvbUFycmF5KGNvbmZpZyk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gY3JlYXRlRnJvbUNvbmZpZyhjb25maWcpIHtcbiAgICAgICAgdmFyIHJlcyA9IG5ldyBNb21lbnQoY2hlY2tPdmVyZmxvdyhwcmVwYXJlQ29uZmlnKGNvbmZpZykpKTtcbiAgICAgICAgaWYgKHJlcy5fbmV4dERheSkge1xuICAgICAgICAgICAgLy8gQWRkaW5nIGlzIHNtYXJ0IGVub3VnaCBhcm91bmQgRFNUXG4gICAgICAgICAgICByZXMuYWRkKDEsICdkJyk7XG4gICAgICAgICAgICByZXMuX25leHREYXkgPSB1bmRlZmluZWQ7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gcmVzO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHByZXBhcmVDb25maWcoY29uZmlnKSB7XG4gICAgICAgIHZhciBpbnB1dCA9IGNvbmZpZy5faSxcbiAgICAgICAgICAgIGZvcm1hdCA9IGNvbmZpZy5fZjtcblxuICAgICAgICBjb25maWcuX2xvY2FsZSA9IGNvbmZpZy5fbG9jYWxlIHx8IGdldExvY2FsZShjb25maWcuX2wpO1xuXG4gICAgICAgIGlmIChpbnB1dCA9PT0gbnVsbCB8fCAoZm9ybWF0ID09PSB1bmRlZmluZWQgJiYgaW5wdXQgPT09ICcnKSkge1xuICAgICAgICAgICAgcmV0dXJuIGNyZWF0ZUludmFsaWQoeyBudWxsSW5wdXQ6IHRydWUgfSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHlwZW9mIGlucHV0ID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgY29uZmlnLl9pID0gaW5wdXQgPSBjb25maWcuX2xvY2FsZS5wcmVwYXJzZShpbnB1dCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoaXNNb21lbnQoaW5wdXQpKSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3IE1vbWVudChjaGVja092ZXJmbG93KGlucHV0KSk7XG4gICAgICAgIH0gZWxzZSBpZiAoaXNEYXRlKGlucHV0KSkge1xuICAgICAgICAgICAgY29uZmlnLl9kID0gaW5wdXQ7XG4gICAgICAgIH0gZWxzZSBpZiAoaXNBcnJheShmb3JtYXQpKSB7XG4gICAgICAgICAgICBjb25maWdGcm9tU3RyaW5nQW5kQXJyYXkoY29uZmlnKTtcbiAgICAgICAgfSBlbHNlIGlmIChmb3JtYXQpIHtcbiAgICAgICAgICAgIGNvbmZpZ0Zyb21TdHJpbmdBbmRGb3JtYXQoY29uZmlnKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvbmZpZ0Zyb21JbnB1dChjb25maWcpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFpc1ZhbGlkKGNvbmZpZykpIHtcbiAgICAgICAgICAgIGNvbmZpZy5fZCA9IG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gY29uZmlnO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGNvbmZpZ0Zyb21JbnB1dChjb25maWcpIHtcbiAgICAgICAgdmFyIGlucHV0ID0gY29uZmlnLl9pO1xuICAgICAgICBpZiAoaXNVbmRlZmluZWQoaW5wdXQpKSB7XG4gICAgICAgICAgICBjb25maWcuX2QgPSBuZXcgRGF0ZShob29rcy5ub3coKSk7XG4gICAgICAgIH0gZWxzZSBpZiAoaXNEYXRlKGlucHV0KSkge1xuICAgICAgICAgICAgY29uZmlnLl9kID0gbmV3IERhdGUoaW5wdXQudmFsdWVPZigpKTtcbiAgICAgICAgfSBlbHNlIGlmICh0eXBlb2YgaW5wdXQgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICBjb25maWdGcm9tU3RyaW5nKGNvbmZpZyk7XG4gICAgICAgIH0gZWxzZSBpZiAoaXNBcnJheShpbnB1dCkpIHtcbiAgICAgICAgICAgIGNvbmZpZy5fYSA9IG1hcChpbnB1dC5zbGljZSgwKSwgZnVuY3Rpb24gKG9iaikge1xuICAgICAgICAgICAgICAgIHJldHVybiBwYXJzZUludChvYmosIDEwKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgY29uZmlnRnJvbUFycmF5KGNvbmZpZyk7XG4gICAgICAgIH0gZWxzZSBpZiAoaXNPYmplY3QoaW5wdXQpKSB7XG4gICAgICAgICAgICBjb25maWdGcm9tT2JqZWN0KGNvbmZpZyk7XG4gICAgICAgIH0gZWxzZSBpZiAoaXNOdW1iZXIoaW5wdXQpKSB7XG4gICAgICAgICAgICAvLyBmcm9tIG1pbGxpc2Vjb25kc1xuICAgICAgICAgICAgY29uZmlnLl9kID0gbmV3IERhdGUoaW5wdXQpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaG9va3MuY3JlYXRlRnJvbUlucHV0RmFsbGJhY2soY29uZmlnKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIGNyZWF0ZUxvY2FsT3JVVEMoaW5wdXQsIGZvcm1hdCwgbG9jYWxlLCBzdHJpY3QsIGlzVVRDKSB7XG4gICAgICAgIHZhciBjID0ge307XG5cbiAgICAgICAgaWYgKGZvcm1hdCA9PT0gdHJ1ZSB8fCBmb3JtYXQgPT09IGZhbHNlKSB7XG4gICAgICAgICAgICBzdHJpY3QgPSBmb3JtYXQ7XG4gICAgICAgICAgICBmb3JtYXQgPSB1bmRlZmluZWQ7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAobG9jYWxlID09PSB0cnVlIHx8IGxvY2FsZSA9PT0gZmFsc2UpIHtcbiAgICAgICAgICAgIHN0cmljdCA9IGxvY2FsZTtcbiAgICAgICAgICAgIGxvY2FsZSA9IHVuZGVmaW5lZDtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChcbiAgICAgICAgICAgIChpc09iamVjdChpbnB1dCkgJiYgaXNPYmplY3RFbXB0eShpbnB1dCkpIHx8XG4gICAgICAgICAgICAoaXNBcnJheShpbnB1dCkgJiYgaW5wdXQubGVuZ3RoID09PSAwKVxuICAgICAgICApIHtcbiAgICAgICAgICAgIGlucHV0ID0gdW5kZWZpbmVkO1xuICAgICAgICB9XG4gICAgICAgIC8vIG9iamVjdCBjb25zdHJ1Y3Rpb24gbXVzdCBiZSBkb25lIHRoaXMgd2F5LlxuICAgICAgICAvLyBodHRwczovL2dpdGh1Yi5jb20vbW9tZW50L21vbWVudC9pc3N1ZXMvMTQyM1xuICAgICAgICBjLl9pc0FNb21lbnRPYmplY3QgPSB0cnVlO1xuICAgICAgICBjLl91c2VVVEMgPSBjLl9pc1VUQyA9IGlzVVRDO1xuICAgICAgICBjLl9sID0gbG9jYWxlO1xuICAgICAgICBjLl9pID0gaW5wdXQ7XG4gICAgICAgIGMuX2YgPSBmb3JtYXQ7XG4gICAgICAgIGMuX3N0cmljdCA9IHN0cmljdDtcblxuICAgICAgICByZXR1cm4gY3JlYXRlRnJvbUNvbmZpZyhjKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBjcmVhdGVMb2NhbChpbnB1dCwgZm9ybWF0LCBsb2NhbGUsIHN0cmljdCkge1xuICAgICAgICByZXR1cm4gY3JlYXRlTG9jYWxPclVUQyhpbnB1dCwgZm9ybWF0LCBsb2NhbGUsIHN0cmljdCwgZmFsc2UpO1xuICAgIH1cblxuICAgIHZhciBwcm90b3R5cGVNaW4gPSBkZXByZWNhdGUoXG4gICAgICAgICAgICAnbW9tZW50KCkubWluIGlzIGRlcHJlY2F0ZWQsIHVzZSBtb21lbnQubWF4IGluc3RlYWQuIGh0dHA6Ly9tb21lbnRqcy5jb20vZ3VpZGVzLyMvd2FybmluZ3MvbWluLW1heC8nLFxuICAgICAgICAgICAgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHZhciBvdGhlciA9IGNyZWF0ZUxvY2FsLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuaXNWYWxpZCgpICYmIG90aGVyLmlzVmFsaWQoKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gb3RoZXIgPCB0aGlzID8gdGhpcyA6IG90aGVyO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBjcmVhdGVJbnZhbGlkKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICApLFxuICAgICAgICBwcm90b3R5cGVNYXggPSBkZXByZWNhdGUoXG4gICAgICAgICAgICAnbW9tZW50KCkubWF4IGlzIGRlcHJlY2F0ZWQsIHVzZSBtb21lbnQubWluIGluc3RlYWQuIGh0dHA6Ly9tb21lbnRqcy5jb20vZ3VpZGVzLyMvd2FybmluZ3MvbWluLW1heC8nLFxuICAgICAgICAgICAgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHZhciBvdGhlciA9IGNyZWF0ZUxvY2FsLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuaXNWYWxpZCgpICYmIG90aGVyLmlzVmFsaWQoKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gb3RoZXIgPiB0aGlzID8gdGhpcyA6IG90aGVyO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBjcmVhdGVJbnZhbGlkKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICApO1xuXG4gICAgLy8gUGljayBhIG1vbWVudCBtIGZyb20gbW9tZW50cyBzbyB0aGF0IG1bZm5dKG90aGVyKSBpcyB0cnVlIGZvciBhbGxcbiAgICAvLyBvdGhlci4gVGhpcyByZWxpZXMgb24gdGhlIGZ1bmN0aW9uIGZuIHRvIGJlIHRyYW5zaXRpdmUuXG4gICAgLy9cbiAgICAvLyBtb21lbnRzIHNob3VsZCBlaXRoZXIgYmUgYW4gYXJyYXkgb2YgbW9tZW50IG9iamVjdHMgb3IgYW4gYXJyYXksIHdob3NlXG4gICAgLy8gZmlyc3QgZWxlbWVudCBpcyBhbiBhcnJheSBvZiBtb21lbnQgb2JqZWN0cy5cbiAgICBmdW5jdGlvbiBwaWNrQnkoZm4sIG1vbWVudHMpIHtcbiAgICAgICAgdmFyIHJlcywgaTtcbiAgICAgICAgaWYgKG1vbWVudHMubGVuZ3RoID09PSAxICYmIGlzQXJyYXkobW9tZW50c1swXSkpIHtcbiAgICAgICAgICAgIG1vbWVudHMgPSBtb21lbnRzWzBdO1xuICAgICAgICB9XG4gICAgICAgIGlmICghbW9tZW50cy5sZW5ndGgpIHtcbiAgICAgICAgICAgIHJldHVybiBjcmVhdGVMb2NhbCgpO1xuICAgICAgICB9XG4gICAgICAgIHJlcyA9IG1vbWVudHNbMF07XG4gICAgICAgIGZvciAoaSA9IDE7IGkgPCBtb21lbnRzLmxlbmd0aDsgKytpKSB7XG4gICAgICAgICAgICBpZiAoIW1vbWVudHNbaV0uaXNWYWxpZCgpIHx8IG1vbWVudHNbaV1bZm5dKHJlcykpIHtcbiAgICAgICAgICAgICAgICByZXMgPSBtb21lbnRzW2ldO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfVxuXG4gICAgLy8gVE9ETzogVXNlIFtdLnNvcnQgaW5zdGVhZD9cbiAgICBmdW5jdGlvbiBtaW4oKSB7XG4gICAgICAgIHZhciBhcmdzID0gW10uc2xpY2UuY2FsbChhcmd1bWVudHMsIDApO1xuXG4gICAgICAgIHJldHVybiBwaWNrQnkoJ2lzQmVmb3JlJywgYXJncyk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gbWF4KCkge1xuICAgICAgICB2YXIgYXJncyA9IFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAwKTtcblxuICAgICAgICByZXR1cm4gcGlja0J5KCdpc0FmdGVyJywgYXJncyk7XG4gICAgfVxuXG4gICAgdmFyIG5vdyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIERhdGUubm93ID8gRGF0ZS5ub3coKSA6ICtuZXcgRGF0ZSgpO1xuICAgIH07XG5cbiAgICB2YXIgb3JkZXJpbmcgPSBbXG4gICAgICAgICd5ZWFyJyxcbiAgICAgICAgJ3F1YXJ0ZXInLFxuICAgICAgICAnbW9udGgnLFxuICAgICAgICAnd2VlaycsXG4gICAgICAgICdkYXknLFxuICAgICAgICAnaG91cicsXG4gICAgICAgICdtaW51dGUnLFxuICAgICAgICAnc2Vjb25kJyxcbiAgICAgICAgJ21pbGxpc2Vjb25kJyxcbiAgICBdO1xuXG4gICAgZnVuY3Rpb24gaXNEdXJhdGlvblZhbGlkKG0pIHtcbiAgICAgICAgdmFyIGtleSxcbiAgICAgICAgICAgIHVuaXRIYXNEZWNpbWFsID0gZmFsc2UsXG4gICAgICAgICAgICBpO1xuICAgICAgICBmb3IgKGtleSBpbiBtKSB7XG4gICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgaGFzT3duUHJvcChtLCBrZXkpICYmXG4gICAgICAgICAgICAgICAgIShcbiAgICAgICAgICAgICAgICAgICAgaW5kZXhPZi5jYWxsKG9yZGVyaW5nLCBrZXkpICE9PSAtMSAmJlxuICAgICAgICAgICAgICAgICAgICAobVtrZXldID09IG51bGwgfHwgIWlzTmFOKG1ba2V5XSkpXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgZm9yIChpID0gMDsgaSA8IG9yZGVyaW5nLmxlbmd0aDsgKytpKSB7XG4gICAgICAgICAgICBpZiAobVtvcmRlcmluZ1tpXV0pIHtcbiAgICAgICAgICAgICAgICBpZiAodW5pdEhhc0RlY2ltYWwpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOyAvLyBvbmx5IGFsbG93IG5vbi1pbnRlZ2VycyBmb3Igc21hbGxlc3QgdW5pdFxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAocGFyc2VGbG9hdChtW29yZGVyaW5nW2ldXSkgIT09IHRvSW50KG1bb3JkZXJpbmdbaV1dKSkge1xuICAgICAgICAgICAgICAgICAgICB1bml0SGFzRGVjaW1hbCA9IHRydWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gaXNWYWxpZCQxKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5faXNWYWxpZDtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBjcmVhdGVJbnZhbGlkJDEoKSB7XG4gICAgICAgIHJldHVybiBjcmVhdGVEdXJhdGlvbihOYU4pO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIER1cmF0aW9uKGR1cmF0aW9uKSB7XG4gICAgICAgIHZhciBub3JtYWxpemVkSW5wdXQgPSBub3JtYWxpemVPYmplY3RVbml0cyhkdXJhdGlvbiksXG4gICAgICAgICAgICB5ZWFycyA9IG5vcm1hbGl6ZWRJbnB1dC55ZWFyIHx8IDAsXG4gICAgICAgICAgICBxdWFydGVycyA9IG5vcm1hbGl6ZWRJbnB1dC5xdWFydGVyIHx8IDAsXG4gICAgICAgICAgICBtb250aHMgPSBub3JtYWxpemVkSW5wdXQubW9udGggfHwgMCxcbiAgICAgICAgICAgIHdlZWtzID0gbm9ybWFsaXplZElucHV0LndlZWsgfHwgbm9ybWFsaXplZElucHV0Lmlzb1dlZWsgfHwgMCxcbiAgICAgICAgICAgIGRheXMgPSBub3JtYWxpemVkSW5wdXQuZGF5IHx8IDAsXG4gICAgICAgICAgICBob3VycyA9IG5vcm1hbGl6ZWRJbnB1dC5ob3VyIHx8IDAsXG4gICAgICAgICAgICBtaW51dGVzID0gbm9ybWFsaXplZElucHV0Lm1pbnV0ZSB8fCAwLFxuICAgICAgICAgICAgc2Vjb25kcyA9IG5vcm1hbGl6ZWRJbnB1dC5zZWNvbmQgfHwgMCxcbiAgICAgICAgICAgIG1pbGxpc2Vjb25kcyA9IG5vcm1hbGl6ZWRJbnB1dC5taWxsaXNlY29uZCB8fCAwO1xuXG4gICAgICAgIHRoaXMuX2lzVmFsaWQgPSBpc0R1cmF0aW9uVmFsaWQobm9ybWFsaXplZElucHV0KTtcblxuICAgICAgICAvLyByZXByZXNlbnRhdGlvbiBmb3IgZGF0ZUFkZFJlbW92ZVxuICAgICAgICB0aGlzLl9taWxsaXNlY29uZHMgPVxuICAgICAgICAgICAgK21pbGxpc2Vjb25kcyArXG4gICAgICAgICAgICBzZWNvbmRzICogMWUzICsgLy8gMTAwMFxuICAgICAgICAgICAgbWludXRlcyAqIDZlNCArIC8vIDEwMDAgKiA2MFxuICAgICAgICAgICAgaG91cnMgKiAxMDAwICogNjAgKiA2MDsgLy91c2luZyAxMDAwICogNjAgKiA2MCBpbnN0ZWFkIG9mIDM2ZTUgdG8gYXZvaWQgZmxvYXRpbmcgcG9pbnQgcm91bmRpbmcgZXJyb3JzIGh0dHBzOi8vZ2l0aHViLmNvbS9tb21lbnQvbW9tZW50L2lzc3Vlcy8yOTc4XG4gICAgICAgIC8vIEJlY2F1c2Ugb2YgZGF0ZUFkZFJlbW92ZSB0cmVhdHMgMjQgaG91cnMgYXMgZGlmZmVyZW50IGZyb20gYVxuICAgICAgICAvLyBkYXkgd2hlbiB3b3JraW5nIGFyb3VuZCBEU1QsIHdlIG5lZWQgdG8gc3RvcmUgdGhlbSBzZXBhcmF0ZWx5XG4gICAgICAgIHRoaXMuX2RheXMgPSArZGF5cyArIHdlZWtzICogNztcbiAgICAgICAgLy8gSXQgaXMgaW1wb3NzaWJsZSB0byB0cmFuc2xhdGUgbW9udGhzIGludG8gZGF5cyB3aXRob3V0IGtub3dpbmdcbiAgICAgICAgLy8gd2hpY2ggbW9udGhzIHlvdSBhcmUgYXJlIHRhbGtpbmcgYWJvdXQsIHNvIHdlIGhhdmUgdG8gc3RvcmVcbiAgICAgICAgLy8gaXQgc2VwYXJhdGVseS5cbiAgICAgICAgdGhpcy5fbW9udGhzID0gK21vbnRocyArIHF1YXJ0ZXJzICogMyArIHllYXJzICogMTI7XG5cbiAgICAgICAgdGhpcy5fZGF0YSA9IHt9O1xuXG4gICAgICAgIHRoaXMuX2xvY2FsZSA9IGdldExvY2FsZSgpO1xuXG4gICAgICAgIHRoaXMuX2J1YmJsZSgpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGlzRHVyYXRpb24ob2JqKSB7XG4gICAgICAgIHJldHVybiBvYmogaW5zdGFuY2VvZiBEdXJhdGlvbjtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBhYnNSb3VuZChudW1iZXIpIHtcbiAgICAgICAgaWYgKG51bWJlciA8IDApIHtcbiAgICAgICAgICAgIHJldHVybiBNYXRoLnJvdW5kKC0xICogbnVtYmVyKSAqIC0xO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIE1hdGgucm91bmQobnVtYmVyKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vIGNvbXBhcmUgdHdvIGFycmF5cywgcmV0dXJuIHRoZSBudW1iZXIgb2YgZGlmZmVyZW5jZXNcbiAgICBmdW5jdGlvbiBjb21wYXJlQXJyYXlzKGFycmF5MSwgYXJyYXkyLCBkb250Q29udmVydCkge1xuICAgICAgICB2YXIgbGVuID0gTWF0aC5taW4oYXJyYXkxLmxlbmd0aCwgYXJyYXkyLmxlbmd0aCksXG4gICAgICAgICAgICBsZW5ndGhEaWZmID0gTWF0aC5hYnMoYXJyYXkxLmxlbmd0aCAtIGFycmF5Mi5sZW5ndGgpLFxuICAgICAgICAgICAgZGlmZnMgPSAwLFxuICAgICAgICAgICAgaTtcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IGxlbjsgaSsrKSB7XG4gICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgKGRvbnRDb252ZXJ0ICYmIGFycmF5MVtpXSAhPT0gYXJyYXkyW2ldKSB8fFxuICAgICAgICAgICAgICAgICghZG9udENvbnZlcnQgJiYgdG9JbnQoYXJyYXkxW2ldKSAhPT0gdG9JbnQoYXJyYXkyW2ldKSlcbiAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgIGRpZmZzKys7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGRpZmZzICsgbGVuZ3RoRGlmZjtcbiAgICB9XG5cbiAgICAvLyBGT1JNQVRUSU5HXG5cbiAgICBmdW5jdGlvbiBvZmZzZXQodG9rZW4sIHNlcGFyYXRvcikge1xuICAgICAgICBhZGRGb3JtYXRUb2tlbih0b2tlbiwgMCwgMCwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIG9mZnNldCA9IHRoaXMudXRjT2Zmc2V0KCksXG4gICAgICAgICAgICAgICAgc2lnbiA9ICcrJztcbiAgICAgICAgICAgIGlmIChvZmZzZXQgPCAwKSB7XG4gICAgICAgICAgICAgICAgb2Zmc2V0ID0gLW9mZnNldDtcbiAgICAgICAgICAgICAgICBzaWduID0gJy0nO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgICAgICBzaWduICtcbiAgICAgICAgICAgICAgICB6ZXJvRmlsbCh+fihvZmZzZXQgLyA2MCksIDIpICtcbiAgICAgICAgICAgICAgICBzZXBhcmF0b3IgK1xuICAgICAgICAgICAgICAgIHplcm9GaWxsKH5+b2Zmc2V0ICUgNjAsIDIpXG4gICAgICAgICAgICApO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBvZmZzZXQoJ1onLCAnOicpO1xuICAgIG9mZnNldCgnWlonLCAnJyk7XG5cbiAgICAvLyBQQVJTSU5HXG5cbiAgICBhZGRSZWdleFRva2VuKCdaJywgbWF0Y2hTaG9ydE9mZnNldCk7XG4gICAgYWRkUmVnZXhUb2tlbignWlonLCBtYXRjaFNob3J0T2Zmc2V0KTtcbiAgICBhZGRQYXJzZVRva2VuKFsnWicsICdaWiddLCBmdW5jdGlvbiAoaW5wdXQsIGFycmF5LCBjb25maWcpIHtcbiAgICAgICAgY29uZmlnLl91c2VVVEMgPSB0cnVlO1xuICAgICAgICBjb25maWcuX3R6bSA9IG9mZnNldEZyb21TdHJpbmcobWF0Y2hTaG9ydE9mZnNldCwgaW5wdXQpO1xuICAgIH0pO1xuXG4gICAgLy8gSEVMUEVSU1xuXG4gICAgLy8gdGltZXpvbmUgY2h1bmtlclxuICAgIC8vICcrMTA6MDAnID4gWycxMCcsICAnMDAnXVxuICAgIC8vICctMTUzMCcgID4gWyctMTUnLCAnMzAnXVxuICAgIHZhciBjaHVua09mZnNldCA9IC8oW1xcK1xcLV18XFxkXFxkKS9naTtcblxuICAgIGZ1bmN0aW9uIG9mZnNldEZyb21TdHJpbmcobWF0Y2hlciwgc3RyaW5nKSB7XG4gICAgICAgIHZhciBtYXRjaGVzID0gKHN0cmluZyB8fCAnJykubWF0Y2gobWF0Y2hlciksXG4gICAgICAgICAgICBjaHVuayxcbiAgICAgICAgICAgIHBhcnRzLFxuICAgICAgICAgICAgbWludXRlcztcblxuICAgICAgICBpZiAobWF0Y2hlcyA9PT0gbnVsbCkge1xuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICBjaHVuayA9IG1hdGNoZXNbbWF0Y2hlcy5sZW5ndGggLSAxXSB8fCBbXTtcbiAgICAgICAgcGFydHMgPSAoY2h1bmsgKyAnJykubWF0Y2goY2h1bmtPZmZzZXQpIHx8IFsnLScsIDAsIDBdO1xuICAgICAgICBtaW51dGVzID0gKyhwYXJ0c1sxXSAqIDYwKSArIHRvSW50KHBhcnRzWzJdKTtcblxuICAgICAgICByZXR1cm4gbWludXRlcyA9PT0gMCA/IDAgOiBwYXJ0c1swXSA9PT0gJysnID8gbWludXRlcyA6IC1taW51dGVzO1xuICAgIH1cblxuICAgIC8vIFJldHVybiBhIG1vbWVudCBmcm9tIGlucHV0LCB0aGF0IGlzIGxvY2FsL3V0Yy96b25lIGVxdWl2YWxlbnQgdG8gbW9kZWwuXG4gICAgZnVuY3Rpb24gY2xvbmVXaXRoT2Zmc2V0KGlucHV0LCBtb2RlbCkge1xuICAgICAgICB2YXIgcmVzLCBkaWZmO1xuICAgICAgICBpZiAobW9kZWwuX2lzVVRDKSB7XG4gICAgICAgICAgICByZXMgPSBtb2RlbC5jbG9uZSgpO1xuICAgICAgICAgICAgZGlmZiA9XG4gICAgICAgICAgICAgICAgKGlzTW9tZW50KGlucHV0KSB8fCBpc0RhdGUoaW5wdXQpXG4gICAgICAgICAgICAgICAgICAgID8gaW5wdXQudmFsdWVPZigpXG4gICAgICAgICAgICAgICAgICAgIDogY3JlYXRlTG9jYWwoaW5wdXQpLnZhbHVlT2YoKSkgLSByZXMudmFsdWVPZigpO1xuICAgICAgICAgICAgLy8gVXNlIGxvdy1sZXZlbCBhcGksIGJlY2F1c2UgdGhpcyBmbiBpcyBsb3ctbGV2ZWwgYXBpLlxuICAgICAgICAgICAgcmVzLl9kLnNldFRpbWUocmVzLl9kLnZhbHVlT2YoKSArIGRpZmYpO1xuICAgICAgICAgICAgaG9va3MudXBkYXRlT2Zmc2V0KHJlcywgZmFsc2UpO1xuICAgICAgICAgICAgcmV0dXJuIHJlcztcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBjcmVhdGVMb2NhbChpbnB1dCkubG9jYWwoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIGdldERhdGVPZmZzZXQobSkge1xuICAgICAgICAvLyBPbiBGaXJlZm94LjI0IERhdGUjZ2V0VGltZXpvbmVPZmZzZXQgcmV0dXJucyBhIGZsb2F0aW5nIHBvaW50LlxuICAgICAgICAvLyBodHRwczovL2dpdGh1Yi5jb20vbW9tZW50L21vbWVudC9wdWxsLzE4NzFcbiAgICAgICAgcmV0dXJuIC1NYXRoLnJvdW5kKG0uX2QuZ2V0VGltZXpvbmVPZmZzZXQoKSk7XG4gICAgfVxuXG4gICAgLy8gSE9PS1NcblxuICAgIC8vIFRoaXMgZnVuY3Rpb24gd2lsbCBiZSBjYWxsZWQgd2hlbmV2ZXIgYSBtb21lbnQgaXMgbXV0YXRlZC5cbiAgICAvLyBJdCBpcyBpbnRlbmRlZCB0byBrZWVwIHRoZSBvZmZzZXQgaW4gc3luYyB3aXRoIHRoZSB0aW1lem9uZS5cbiAgICBob29rcy51cGRhdGVPZmZzZXQgPSBmdW5jdGlvbiAoKSB7fTtcblxuICAgIC8vIE1PTUVOVFNcblxuICAgIC8vIGtlZXBMb2NhbFRpbWUgPSB0cnVlIG1lYW5zIG9ubHkgY2hhbmdlIHRoZSB0aW1lem9uZSwgd2l0aG91dFxuICAgIC8vIGFmZmVjdGluZyB0aGUgbG9jYWwgaG91ci4gU28gNTozMToyNiArMDMwMCAtLVt1dGNPZmZzZXQoMiwgdHJ1ZSldLS0+XG4gICAgLy8gNTozMToyNiArMDIwMCBJdCBpcyBwb3NzaWJsZSB0aGF0IDU6MzE6MjYgZG9lc24ndCBleGlzdCB3aXRoIG9mZnNldFxuICAgIC8vICswMjAwLCBzbyB3ZSBhZGp1c3QgdGhlIHRpbWUgYXMgbmVlZGVkLCB0byBiZSB2YWxpZC5cbiAgICAvL1xuICAgIC8vIEtlZXBpbmcgdGhlIHRpbWUgYWN0dWFsbHkgYWRkcy9zdWJ0cmFjdHMgKG9uZSBob3VyKVxuICAgIC8vIGZyb20gdGhlIGFjdHVhbCByZXByZXNlbnRlZCB0aW1lLiBUaGF0IGlzIHdoeSB3ZSBjYWxsIHVwZGF0ZU9mZnNldFxuICAgIC8vIGEgc2Vjb25kIHRpbWUuIEluIGNhc2UgaXQgd2FudHMgdXMgdG8gY2hhbmdlIHRoZSBvZmZzZXQgYWdhaW5cbiAgICAvLyBfY2hhbmdlSW5Qcm9ncmVzcyA9PSB0cnVlIGNhc2UsIHRoZW4gd2UgaGF2ZSB0byBhZGp1c3QsIGJlY2F1c2VcbiAgICAvLyB0aGVyZSBpcyBubyBzdWNoIHRpbWUgaW4gdGhlIGdpdmVuIHRpbWV6b25lLlxuICAgIGZ1bmN0aW9uIGdldFNldE9mZnNldChpbnB1dCwga2VlcExvY2FsVGltZSwga2VlcE1pbnV0ZXMpIHtcbiAgICAgICAgdmFyIG9mZnNldCA9IHRoaXMuX29mZnNldCB8fCAwLFxuICAgICAgICAgICAgbG9jYWxBZGp1c3Q7XG4gICAgICAgIGlmICghdGhpcy5pc1ZhbGlkKCkpIHtcbiAgICAgICAgICAgIHJldHVybiBpbnB1dCAhPSBudWxsID8gdGhpcyA6IE5hTjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoaW5wdXQgIT0gbnVsbCkge1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBpbnB1dCA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICBpbnB1dCA9IG9mZnNldEZyb21TdHJpbmcobWF0Y2hTaG9ydE9mZnNldCwgaW5wdXQpO1xuICAgICAgICAgICAgICAgIGlmIChpbnB1dCA9PT0gbnVsbCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2UgaWYgKE1hdGguYWJzKGlucHV0KSA8IDE2ICYmICFrZWVwTWludXRlcykge1xuICAgICAgICAgICAgICAgIGlucHV0ID0gaW5wdXQgKiA2MDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICghdGhpcy5faXNVVEMgJiYga2VlcExvY2FsVGltZSkge1xuICAgICAgICAgICAgICAgIGxvY2FsQWRqdXN0ID0gZ2V0RGF0ZU9mZnNldCh0aGlzKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMuX29mZnNldCA9IGlucHV0O1xuICAgICAgICAgICAgdGhpcy5faXNVVEMgPSB0cnVlO1xuICAgICAgICAgICAgaWYgKGxvY2FsQWRqdXN0ICE9IG51bGwpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmFkZChsb2NhbEFkanVzdCwgJ20nKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChvZmZzZXQgIT09IGlucHV0KSB7XG4gICAgICAgICAgICAgICAgaWYgKCFrZWVwTG9jYWxUaW1lIHx8IHRoaXMuX2NoYW5nZUluUHJvZ3Jlc3MpIHtcbiAgICAgICAgICAgICAgICAgICAgYWRkU3VidHJhY3QoXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLFxuICAgICAgICAgICAgICAgICAgICAgICAgY3JlYXRlRHVyYXRpb24oaW5wdXQgLSBvZmZzZXQsICdtJyksXG4gICAgICAgICAgICAgICAgICAgICAgICAxLFxuICAgICAgICAgICAgICAgICAgICAgICAgZmFsc2VcbiAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKCF0aGlzLl9jaGFuZ2VJblByb2dyZXNzKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX2NoYW5nZUluUHJvZ3Jlc3MgPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICBob29rcy51cGRhdGVPZmZzZXQodGhpcywgdHJ1ZSk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX2NoYW5nZUluUHJvZ3Jlc3MgPSBudWxsO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2lzVVRDID8gb2Zmc2V0IDogZ2V0RGF0ZU9mZnNldCh0aGlzKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIGdldFNldFpvbmUoaW5wdXQsIGtlZXBMb2NhbFRpbWUpIHtcbiAgICAgICAgaWYgKGlucHV0ICE9IG51bGwpIHtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgaW5wdXQgIT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAgICAgaW5wdXQgPSAtaW5wdXQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRoaXMudXRjT2Zmc2V0KGlucHV0LCBrZWVwTG9jYWxUaW1lKTtcblxuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gLXRoaXMudXRjT2Zmc2V0KCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiBzZXRPZmZzZXRUb1VUQyhrZWVwTG9jYWxUaW1lKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnV0Y09mZnNldCgwLCBrZWVwTG9jYWxUaW1lKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBzZXRPZmZzZXRUb0xvY2FsKGtlZXBMb2NhbFRpbWUpIHtcbiAgICAgICAgaWYgKHRoaXMuX2lzVVRDKSB7XG4gICAgICAgICAgICB0aGlzLnV0Y09mZnNldCgwLCBrZWVwTG9jYWxUaW1lKTtcbiAgICAgICAgICAgIHRoaXMuX2lzVVRDID0gZmFsc2U7XG5cbiAgICAgICAgICAgIGlmIChrZWVwTG9jYWxUaW1lKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zdWJ0cmFjdChnZXREYXRlT2Zmc2V0KHRoaXMpLCAnbScpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHNldE9mZnNldFRvUGFyc2VkT2Zmc2V0KCkge1xuICAgICAgICBpZiAodGhpcy5fdHptICE9IG51bGwpIHtcbiAgICAgICAgICAgIHRoaXMudXRjT2Zmc2V0KHRoaXMuX3R6bSwgZmFsc2UsIHRydWUpO1xuICAgICAgICB9IGVsc2UgaWYgKHR5cGVvZiB0aGlzLl9pID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgdmFyIHRab25lID0gb2Zmc2V0RnJvbVN0cmluZyhtYXRjaE9mZnNldCwgdGhpcy5faSk7XG4gICAgICAgICAgICBpZiAodFpvbmUgIT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIHRoaXMudXRjT2Zmc2V0KHRab25lKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy51dGNPZmZzZXQoMCwgdHJ1ZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gaGFzQWxpZ25lZEhvdXJPZmZzZXQoaW5wdXQpIHtcbiAgICAgICAgaWYgKCF0aGlzLmlzVmFsaWQoKSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIGlucHV0ID0gaW5wdXQgPyBjcmVhdGVMb2NhbChpbnB1dCkudXRjT2Zmc2V0KCkgOiAwO1xuXG4gICAgICAgIHJldHVybiAodGhpcy51dGNPZmZzZXQoKSAtIGlucHV0KSAlIDYwID09PSAwO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGlzRGF5bGlnaHRTYXZpbmdUaW1lKCkge1xuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgdGhpcy51dGNPZmZzZXQoKSA+IHRoaXMuY2xvbmUoKS5tb250aCgwKS51dGNPZmZzZXQoKSB8fFxuICAgICAgICAgICAgdGhpcy51dGNPZmZzZXQoKSA+IHRoaXMuY2xvbmUoKS5tb250aCg1KS51dGNPZmZzZXQoKVxuICAgICAgICApO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGlzRGF5bGlnaHRTYXZpbmdUaW1lU2hpZnRlZCgpIHtcbiAgICAgICAgaWYgKCFpc1VuZGVmaW5lZCh0aGlzLl9pc0RTVFNoaWZ0ZWQpKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5faXNEU1RTaGlmdGVkO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGMgPSB7fSxcbiAgICAgICAgICAgIG90aGVyO1xuXG4gICAgICAgIGNvcHlDb25maWcoYywgdGhpcyk7XG4gICAgICAgIGMgPSBwcmVwYXJlQ29uZmlnKGMpO1xuXG4gICAgICAgIGlmIChjLl9hKSB7XG4gICAgICAgICAgICBvdGhlciA9IGMuX2lzVVRDID8gY3JlYXRlVVRDKGMuX2EpIDogY3JlYXRlTG9jYWwoYy5fYSk7XG4gICAgICAgICAgICB0aGlzLl9pc0RTVFNoaWZ0ZWQgPVxuICAgICAgICAgICAgICAgIHRoaXMuaXNWYWxpZCgpICYmIGNvbXBhcmVBcnJheXMoYy5fYSwgb3RoZXIudG9BcnJheSgpKSA+IDA7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLl9pc0RTVFNoaWZ0ZWQgPSBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzLl9pc0RTVFNoaWZ0ZWQ7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gaXNMb2NhbCgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuaXNWYWxpZCgpID8gIXRoaXMuX2lzVVRDIDogZmFsc2U7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gaXNVdGNPZmZzZXQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmlzVmFsaWQoKSA/IHRoaXMuX2lzVVRDIDogZmFsc2U7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gaXNVdGMoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmlzVmFsaWQoKSA/IHRoaXMuX2lzVVRDICYmIHRoaXMuX29mZnNldCA9PT0gMCA6IGZhbHNlO1xuICAgIH1cblxuICAgIC8vIEFTUC5ORVQganNvbiBkYXRlIGZvcm1hdCByZWdleFxuICAgIHZhciBhc3BOZXRSZWdleCA9IC9eKC18XFwrKT8oPzooXFxkKilbLiBdKT8oXFxkKyk6KFxcZCspKD86OihcXGQrKShcXC5cXGQqKT8pPyQvLFxuICAgICAgICAvLyBmcm9tIGh0dHA6Ly9kb2NzLmNsb3N1cmUtbGlicmFyeS5nb29nbGVjb2RlLmNvbS9naXQvY2xvc3VyZV9nb29nX2RhdGVfZGF0ZS5qcy5zb3VyY2UuaHRtbFxuICAgICAgICAvLyBzb21ld2hhdCBtb3JlIGluIGxpbmUgd2l0aCA0LjQuMy4yIDIwMDQgc3BlYywgYnV0IGFsbG93cyBkZWNpbWFsIGFueXdoZXJlXG4gICAgICAgIC8vIGFuZCBmdXJ0aGVyIG1vZGlmaWVkIHRvIGFsbG93IGZvciBzdHJpbmdzIGNvbnRhaW5pbmcgYm90aCB3ZWVrIGFuZCBkYXlcbiAgICAgICAgaXNvUmVnZXggPSAvXigtfFxcKyk/UCg/OihbLStdP1swLTksLl0qKVkpPyg/OihbLStdP1swLTksLl0qKU0pPyg/OihbLStdP1swLTksLl0qKVcpPyg/OihbLStdP1swLTksLl0qKUQpPyg/OlQoPzooWy0rXT9bMC05LC5dKilIKT8oPzooWy0rXT9bMC05LC5dKilNKT8oPzooWy0rXT9bMC05LC5dKilTKT8pPyQvO1xuXG4gICAgZnVuY3Rpb24gY3JlYXRlRHVyYXRpb24oaW5wdXQsIGtleSkge1xuICAgICAgICB2YXIgZHVyYXRpb24gPSBpbnB1dCxcbiAgICAgICAgICAgIC8vIG1hdGNoaW5nIGFnYWluc3QgcmVnZXhwIGlzIGV4cGVuc2l2ZSwgZG8gaXQgb24gZGVtYW5kXG4gICAgICAgICAgICBtYXRjaCA9IG51bGwsXG4gICAgICAgICAgICBzaWduLFxuICAgICAgICAgICAgcmV0LFxuICAgICAgICAgICAgZGlmZlJlcztcblxuICAgICAgICBpZiAoaXNEdXJhdGlvbihpbnB1dCkpIHtcbiAgICAgICAgICAgIGR1cmF0aW9uID0ge1xuICAgICAgICAgICAgICAgIG1zOiBpbnB1dC5fbWlsbGlzZWNvbmRzLFxuICAgICAgICAgICAgICAgIGQ6IGlucHV0Ll9kYXlzLFxuICAgICAgICAgICAgICAgIE06IGlucHV0Ll9tb250aHMsXG4gICAgICAgICAgICB9O1xuICAgICAgICB9IGVsc2UgaWYgKGlzTnVtYmVyKGlucHV0KSB8fCAhaXNOYU4oK2lucHV0KSkge1xuICAgICAgICAgICAgZHVyYXRpb24gPSB7fTtcbiAgICAgICAgICAgIGlmIChrZXkpIHtcbiAgICAgICAgICAgICAgICBkdXJhdGlvbltrZXldID0gK2lucHV0O1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBkdXJhdGlvbi5taWxsaXNlY29uZHMgPSAraW5wdXQ7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAoKG1hdGNoID0gYXNwTmV0UmVnZXguZXhlYyhpbnB1dCkpKSB7XG4gICAgICAgICAgICBzaWduID0gbWF0Y2hbMV0gPT09ICctJyA/IC0xIDogMTtcbiAgICAgICAgICAgIGR1cmF0aW9uID0ge1xuICAgICAgICAgICAgICAgIHk6IDAsXG4gICAgICAgICAgICAgICAgZDogdG9JbnQobWF0Y2hbREFURV0pICogc2lnbixcbiAgICAgICAgICAgICAgICBoOiB0b0ludChtYXRjaFtIT1VSXSkgKiBzaWduLFxuICAgICAgICAgICAgICAgIG06IHRvSW50KG1hdGNoW01JTlVURV0pICogc2lnbixcbiAgICAgICAgICAgICAgICBzOiB0b0ludChtYXRjaFtTRUNPTkRdKSAqIHNpZ24sXG4gICAgICAgICAgICAgICAgbXM6IHRvSW50KGFic1JvdW5kKG1hdGNoW01JTExJU0VDT05EXSAqIDEwMDApKSAqIHNpZ24sIC8vIHRoZSBtaWxsaXNlY29uZCBkZWNpbWFsIHBvaW50IGlzIGluY2x1ZGVkIGluIHRoZSBtYXRjaFxuICAgICAgICAgICAgfTtcbiAgICAgICAgfSBlbHNlIGlmICgobWF0Y2ggPSBpc29SZWdleC5leGVjKGlucHV0KSkpIHtcbiAgICAgICAgICAgIHNpZ24gPSBtYXRjaFsxXSA9PT0gJy0nID8gLTEgOiAxO1xuICAgICAgICAgICAgZHVyYXRpb24gPSB7XG4gICAgICAgICAgICAgICAgeTogcGFyc2VJc28obWF0Y2hbMl0sIHNpZ24pLFxuICAgICAgICAgICAgICAgIE06IHBhcnNlSXNvKG1hdGNoWzNdLCBzaWduKSxcbiAgICAgICAgICAgICAgICB3OiBwYXJzZUlzbyhtYXRjaFs0XSwgc2lnbiksXG4gICAgICAgICAgICAgICAgZDogcGFyc2VJc28obWF0Y2hbNV0sIHNpZ24pLFxuICAgICAgICAgICAgICAgIGg6IHBhcnNlSXNvKG1hdGNoWzZdLCBzaWduKSxcbiAgICAgICAgICAgICAgICBtOiBwYXJzZUlzbyhtYXRjaFs3XSwgc2lnbiksXG4gICAgICAgICAgICAgICAgczogcGFyc2VJc28obWF0Y2hbOF0sIHNpZ24pLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgfSBlbHNlIGlmIChkdXJhdGlvbiA9PSBudWxsKSB7XG4gICAgICAgICAgICAvLyBjaGVja3MgZm9yIG51bGwgb3IgdW5kZWZpbmVkXG4gICAgICAgICAgICBkdXJhdGlvbiA9IHt9O1xuICAgICAgICB9IGVsc2UgaWYgKFxuICAgICAgICAgICAgdHlwZW9mIGR1cmF0aW9uID09PSAnb2JqZWN0JyAmJlxuICAgICAgICAgICAgKCdmcm9tJyBpbiBkdXJhdGlvbiB8fCAndG8nIGluIGR1cmF0aW9uKVxuICAgICAgICApIHtcbiAgICAgICAgICAgIGRpZmZSZXMgPSBtb21lbnRzRGlmZmVyZW5jZShcbiAgICAgICAgICAgICAgICBjcmVhdGVMb2NhbChkdXJhdGlvbi5mcm9tKSxcbiAgICAgICAgICAgICAgICBjcmVhdGVMb2NhbChkdXJhdGlvbi50bylcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIGR1cmF0aW9uID0ge307XG4gICAgICAgICAgICBkdXJhdGlvbi5tcyA9IGRpZmZSZXMubWlsbGlzZWNvbmRzO1xuICAgICAgICAgICAgZHVyYXRpb24uTSA9IGRpZmZSZXMubW9udGhzO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0ID0gbmV3IER1cmF0aW9uKGR1cmF0aW9uKTtcblxuICAgICAgICBpZiAoaXNEdXJhdGlvbihpbnB1dCkgJiYgaGFzT3duUHJvcChpbnB1dCwgJ19sb2NhbGUnKSkge1xuICAgICAgICAgICAgcmV0Ll9sb2NhbGUgPSBpbnB1dC5fbG9jYWxlO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGlzRHVyYXRpb24oaW5wdXQpICYmIGhhc093blByb3AoaW5wdXQsICdfaXNWYWxpZCcpKSB7XG4gICAgICAgICAgICByZXQuX2lzVmFsaWQgPSBpbnB1dC5faXNWYWxpZDtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiByZXQ7XG4gICAgfVxuXG4gICAgY3JlYXRlRHVyYXRpb24uZm4gPSBEdXJhdGlvbi5wcm90b3R5cGU7XG4gICAgY3JlYXRlRHVyYXRpb24uaW52YWxpZCA9IGNyZWF0ZUludmFsaWQkMTtcblxuICAgIGZ1bmN0aW9uIHBhcnNlSXNvKGlucCwgc2lnbikge1xuICAgICAgICAvLyBXZSdkIG5vcm1hbGx5IHVzZSB+fmlucCBmb3IgdGhpcywgYnV0IHVuZm9ydHVuYXRlbHkgaXQgYWxzb1xuICAgICAgICAvLyBjb252ZXJ0cyBmbG9hdHMgdG8gaW50cy5cbiAgICAgICAgLy8gaW5wIG1heSBiZSB1bmRlZmluZWQsIHNvIGNhcmVmdWwgY2FsbGluZyByZXBsYWNlIG9uIGl0LlxuICAgICAgICB2YXIgcmVzID0gaW5wICYmIHBhcnNlRmxvYXQoaW5wLnJlcGxhY2UoJywnLCAnLicpKTtcbiAgICAgICAgLy8gYXBwbHkgc2lnbiB3aGlsZSB3ZSdyZSBhdCBpdFxuICAgICAgICByZXR1cm4gKGlzTmFOKHJlcykgPyAwIDogcmVzKSAqIHNpZ247XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gcG9zaXRpdmVNb21lbnRzRGlmZmVyZW5jZShiYXNlLCBvdGhlcikge1xuICAgICAgICB2YXIgcmVzID0ge307XG5cbiAgICAgICAgcmVzLm1vbnRocyA9XG4gICAgICAgICAgICBvdGhlci5tb250aCgpIC0gYmFzZS5tb250aCgpICsgKG90aGVyLnllYXIoKSAtIGJhc2UueWVhcigpKSAqIDEyO1xuICAgICAgICBpZiAoYmFzZS5jbG9uZSgpLmFkZChyZXMubW9udGhzLCAnTScpLmlzQWZ0ZXIob3RoZXIpKSB7XG4gICAgICAgICAgICAtLXJlcy5tb250aHM7XG4gICAgICAgIH1cblxuICAgICAgICByZXMubWlsbGlzZWNvbmRzID0gK290aGVyIC0gK2Jhc2UuY2xvbmUoKS5hZGQocmVzLm1vbnRocywgJ00nKTtcblxuICAgICAgICByZXR1cm4gcmVzO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIG1vbWVudHNEaWZmZXJlbmNlKGJhc2UsIG90aGVyKSB7XG4gICAgICAgIHZhciByZXM7XG4gICAgICAgIGlmICghKGJhc2UuaXNWYWxpZCgpICYmIG90aGVyLmlzVmFsaWQoKSkpIHtcbiAgICAgICAgICAgIHJldHVybiB7IG1pbGxpc2Vjb25kczogMCwgbW9udGhzOiAwIH07XG4gICAgICAgIH1cblxuICAgICAgICBvdGhlciA9IGNsb25lV2l0aE9mZnNldChvdGhlciwgYmFzZSk7XG4gICAgICAgIGlmIChiYXNlLmlzQmVmb3JlKG90aGVyKSkge1xuICAgICAgICAgICAgcmVzID0gcG9zaXRpdmVNb21lbnRzRGlmZmVyZW5jZShiYXNlLCBvdGhlcik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXMgPSBwb3NpdGl2ZU1vbWVudHNEaWZmZXJlbmNlKG90aGVyLCBiYXNlKTtcbiAgICAgICAgICAgIHJlcy5taWxsaXNlY29uZHMgPSAtcmVzLm1pbGxpc2Vjb25kcztcbiAgICAgICAgICAgIHJlcy5tb250aHMgPSAtcmVzLm1vbnRocztcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfVxuXG4gICAgLy8gVE9ETzogcmVtb3ZlICduYW1lJyBhcmcgYWZ0ZXIgZGVwcmVjYXRpb24gaXMgcmVtb3ZlZFxuICAgIGZ1bmN0aW9uIGNyZWF0ZUFkZGVyKGRpcmVjdGlvbiwgbmFtZSkge1xuICAgICAgICByZXR1cm4gZnVuY3Rpb24gKHZhbCwgcGVyaW9kKSB7XG4gICAgICAgICAgICB2YXIgZHVyLCB0bXA7XG4gICAgICAgICAgICAvL2ludmVydCB0aGUgYXJndW1lbnRzLCBidXQgY29tcGxhaW4gYWJvdXQgaXRcbiAgICAgICAgICAgIGlmIChwZXJpb2QgIT09IG51bGwgJiYgIWlzTmFOKCtwZXJpb2QpKSB7XG4gICAgICAgICAgICAgICAgZGVwcmVjYXRlU2ltcGxlKFxuICAgICAgICAgICAgICAgICAgICBuYW1lLFxuICAgICAgICAgICAgICAgICAgICAnbW9tZW50KCkuJyArXG4gICAgICAgICAgICAgICAgICAgICAgICBuYW1lICtcbiAgICAgICAgICAgICAgICAgICAgICAgICcocGVyaW9kLCBudW1iZXIpIGlzIGRlcHJlY2F0ZWQuIFBsZWFzZSB1c2UgbW9tZW50KCkuJyArXG4gICAgICAgICAgICAgICAgICAgICAgICBuYW1lICtcbiAgICAgICAgICAgICAgICAgICAgICAgICcobnVtYmVyLCBwZXJpb2QpLiAnICtcbiAgICAgICAgICAgICAgICAgICAgICAgICdTZWUgaHR0cDovL21vbWVudGpzLmNvbS9ndWlkZXMvIy93YXJuaW5ncy9hZGQtaW52ZXJ0ZWQtcGFyYW0vIGZvciBtb3JlIGluZm8uJ1xuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgdG1wID0gdmFsO1xuICAgICAgICAgICAgICAgIHZhbCA9IHBlcmlvZDtcbiAgICAgICAgICAgICAgICBwZXJpb2QgPSB0bXA7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGR1ciA9IGNyZWF0ZUR1cmF0aW9uKHZhbCwgcGVyaW9kKTtcbiAgICAgICAgICAgIGFkZFN1YnRyYWN0KHRoaXMsIGR1ciwgZGlyZWN0aW9uKTtcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9O1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGFkZFN1YnRyYWN0KG1vbSwgZHVyYXRpb24sIGlzQWRkaW5nLCB1cGRhdGVPZmZzZXQpIHtcbiAgICAgICAgdmFyIG1pbGxpc2Vjb25kcyA9IGR1cmF0aW9uLl9taWxsaXNlY29uZHMsXG4gICAgICAgICAgICBkYXlzID0gYWJzUm91bmQoZHVyYXRpb24uX2RheXMpLFxuICAgICAgICAgICAgbW9udGhzID0gYWJzUm91bmQoZHVyYXRpb24uX21vbnRocyk7XG5cbiAgICAgICAgaWYgKCFtb20uaXNWYWxpZCgpKSB7XG4gICAgICAgICAgICAvLyBObyBvcFxuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdXBkYXRlT2Zmc2V0ID0gdXBkYXRlT2Zmc2V0ID09IG51bGwgPyB0cnVlIDogdXBkYXRlT2Zmc2V0O1xuXG4gICAgICAgIGlmIChtb250aHMpIHtcbiAgICAgICAgICAgIHNldE1vbnRoKG1vbSwgZ2V0KG1vbSwgJ01vbnRoJykgKyBtb250aHMgKiBpc0FkZGluZyk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGRheXMpIHtcbiAgICAgICAgICAgIHNldCQxKG1vbSwgJ0RhdGUnLCBnZXQobW9tLCAnRGF0ZScpICsgZGF5cyAqIGlzQWRkaW5nKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAobWlsbGlzZWNvbmRzKSB7XG4gICAgICAgICAgICBtb20uX2Quc2V0VGltZShtb20uX2QudmFsdWVPZigpICsgbWlsbGlzZWNvbmRzICogaXNBZGRpbmcpO1xuICAgICAgICB9XG4gICAgICAgIGlmICh1cGRhdGVPZmZzZXQpIHtcbiAgICAgICAgICAgIGhvb2tzLnVwZGF0ZU9mZnNldChtb20sIGRheXMgfHwgbW9udGhzKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHZhciBhZGQgPSBjcmVhdGVBZGRlcigxLCAnYWRkJyksXG4gICAgICAgIHN1YnRyYWN0ID0gY3JlYXRlQWRkZXIoLTEsICdzdWJ0cmFjdCcpO1xuXG4gICAgZnVuY3Rpb24gaXNTdHJpbmcoaW5wdXQpIHtcbiAgICAgICAgcmV0dXJuIHR5cGVvZiBpbnB1dCA9PT0gJ3N0cmluZycgfHwgaW5wdXQgaW5zdGFuY2VvZiBTdHJpbmc7XG4gICAgfVxuXG4gICAgLy8gdHlwZSBNb21lbnRJbnB1dCA9IE1vbWVudCB8IERhdGUgfCBzdHJpbmcgfCBudW1iZXIgfCAobnVtYmVyIHwgc3RyaW5nKVtdIHwgTW9tZW50SW5wdXRPYmplY3QgfCB2b2lkOyAvLyBudWxsIHwgdW5kZWZpbmVkXG4gICAgZnVuY3Rpb24gaXNNb21lbnRJbnB1dChpbnB1dCkge1xuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgaXNNb21lbnQoaW5wdXQpIHx8XG4gICAgICAgICAgICBpc0RhdGUoaW5wdXQpIHx8XG4gICAgICAgICAgICBpc1N0cmluZyhpbnB1dCkgfHxcbiAgICAgICAgICAgIGlzTnVtYmVyKGlucHV0KSB8fFxuICAgICAgICAgICAgaXNOdW1iZXJPclN0cmluZ0FycmF5KGlucHV0KSB8fFxuICAgICAgICAgICAgaXNNb21lbnRJbnB1dE9iamVjdChpbnB1dCkgfHxcbiAgICAgICAgICAgIGlucHV0ID09PSBudWxsIHx8XG4gICAgICAgICAgICBpbnB1dCA9PT0gdW5kZWZpbmVkXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gaXNNb21lbnRJbnB1dE9iamVjdChpbnB1dCkge1xuICAgICAgICB2YXIgb2JqZWN0VGVzdCA9IGlzT2JqZWN0KGlucHV0KSAmJiAhaXNPYmplY3RFbXB0eShpbnB1dCksXG4gICAgICAgICAgICBwcm9wZXJ0eVRlc3QgPSBmYWxzZSxcbiAgICAgICAgICAgIHByb3BlcnRpZXMgPSBbXG4gICAgICAgICAgICAgICAgJ3llYXJzJyxcbiAgICAgICAgICAgICAgICAneWVhcicsXG4gICAgICAgICAgICAgICAgJ3knLFxuICAgICAgICAgICAgICAgICdtb250aHMnLFxuICAgICAgICAgICAgICAgICdtb250aCcsXG4gICAgICAgICAgICAgICAgJ00nLFxuICAgICAgICAgICAgICAgICdkYXlzJyxcbiAgICAgICAgICAgICAgICAnZGF5JyxcbiAgICAgICAgICAgICAgICAnZCcsXG4gICAgICAgICAgICAgICAgJ2RhdGVzJyxcbiAgICAgICAgICAgICAgICAnZGF0ZScsXG4gICAgICAgICAgICAgICAgJ0QnLFxuICAgICAgICAgICAgICAgICdob3VycycsXG4gICAgICAgICAgICAgICAgJ2hvdXInLFxuICAgICAgICAgICAgICAgICdoJyxcbiAgICAgICAgICAgICAgICAnbWludXRlcycsXG4gICAgICAgICAgICAgICAgJ21pbnV0ZScsXG4gICAgICAgICAgICAgICAgJ20nLFxuICAgICAgICAgICAgICAgICdzZWNvbmRzJyxcbiAgICAgICAgICAgICAgICAnc2Vjb25kJyxcbiAgICAgICAgICAgICAgICAncycsXG4gICAgICAgICAgICAgICAgJ21pbGxpc2Vjb25kcycsXG4gICAgICAgICAgICAgICAgJ21pbGxpc2Vjb25kJyxcbiAgICAgICAgICAgICAgICAnbXMnLFxuICAgICAgICAgICAgXSxcbiAgICAgICAgICAgIGksXG4gICAgICAgICAgICBwcm9wZXJ0eTtcblxuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgcHJvcGVydGllcy5sZW5ndGg7IGkgKz0gMSkge1xuICAgICAgICAgICAgcHJvcGVydHkgPSBwcm9wZXJ0aWVzW2ldO1xuICAgICAgICAgICAgcHJvcGVydHlUZXN0ID0gcHJvcGVydHlUZXN0IHx8IGhhc093blByb3AoaW5wdXQsIHByb3BlcnR5KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBvYmplY3RUZXN0ICYmIHByb3BlcnR5VGVzdDtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBpc051bWJlck9yU3RyaW5nQXJyYXkoaW5wdXQpIHtcbiAgICAgICAgdmFyIGFycmF5VGVzdCA9IGlzQXJyYXkoaW5wdXQpLFxuICAgICAgICAgICAgZGF0YVR5cGVUZXN0ID0gZmFsc2U7XG4gICAgICAgIGlmIChhcnJheVRlc3QpIHtcbiAgICAgICAgICAgIGRhdGFUeXBlVGVzdCA9XG4gICAgICAgICAgICAgICAgaW5wdXQuZmlsdGVyKGZ1bmN0aW9uIChpdGVtKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiAhaXNOdW1iZXIoaXRlbSkgJiYgaXNTdHJpbmcoaW5wdXQpO1xuICAgICAgICAgICAgICAgIH0pLmxlbmd0aCA9PT0gMDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gYXJyYXlUZXN0ICYmIGRhdGFUeXBlVGVzdDtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBpc0NhbGVuZGFyU3BlYyhpbnB1dCkge1xuICAgICAgICB2YXIgb2JqZWN0VGVzdCA9IGlzT2JqZWN0KGlucHV0KSAmJiAhaXNPYmplY3RFbXB0eShpbnB1dCksXG4gICAgICAgICAgICBwcm9wZXJ0eVRlc3QgPSBmYWxzZSxcbiAgICAgICAgICAgIHByb3BlcnRpZXMgPSBbXG4gICAgICAgICAgICAgICAgJ3NhbWVEYXknLFxuICAgICAgICAgICAgICAgICduZXh0RGF5JyxcbiAgICAgICAgICAgICAgICAnbGFzdERheScsXG4gICAgICAgICAgICAgICAgJ25leHRXZWVrJyxcbiAgICAgICAgICAgICAgICAnbGFzdFdlZWsnLFxuICAgICAgICAgICAgICAgICdzYW1lRWxzZScsXG4gICAgICAgICAgICBdLFxuICAgICAgICAgICAgaSxcbiAgICAgICAgICAgIHByb3BlcnR5O1xuXG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCBwcm9wZXJ0aWVzLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgICAgICAgICBwcm9wZXJ0eSA9IHByb3BlcnRpZXNbaV07XG4gICAgICAgICAgICBwcm9wZXJ0eVRlc3QgPSBwcm9wZXJ0eVRlc3QgfHwgaGFzT3duUHJvcChpbnB1dCwgcHJvcGVydHkpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG9iamVjdFRlc3QgJiYgcHJvcGVydHlUZXN0O1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGdldENhbGVuZGFyRm9ybWF0KG15TW9tZW50LCBub3cpIHtcbiAgICAgICAgdmFyIGRpZmYgPSBteU1vbWVudC5kaWZmKG5vdywgJ2RheXMnLCB0cnVlKTtcbiAgICAgICAgcmV0dXJuIGRpZmYgPCAtNlxuICAgICAgICAgICAgPyAnc2FtZUVsc2UnXG4gICAgICAgICAgICA6IGRpZmYgPCAtMVxuICAgICAgICAgICAgPyAnbGFzdFdlZWsnXG4gICAgICAgICAgICA6IGRpZmYgPCAwXG4gICAgICAgICAgICA/ICdsYXN0RGF5J1xuICAgICAgICAgICAgOiBkaWZmIDwgMVxuICAgICAgICAgICAgPyAnc2FtZURheSdcbiAgICAgICAgICAgIDogZGlmZiA8IDJcbiAgICAgICAgICAgID8gJ25leHREYXknXG4gICAgICAgICAgICA6IGRpZmYgPCA3XG4gICAgICAgICAgICA/ICduZXh0V2VlaydcbiAgICAgICAgICAgIDogJ3NhbWVFbHNlJztcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBjYWxlbmRhciQxKHRpbWUsIGZvcm1hdHMpIHtcbiAgICAgICAgLy8gU3VwcG9ydCBmb3Igc2luZ2xlIHBhcmFtZXRlciwgZm9ybWF0cyBvbmx5IG92ZXJsb2FkIHRvIHRoZSBjYWxlbmRhciBmdW5jdGlvblxuICAgICAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICAgICAgaWYgKGlzTW9tZW50SW5wdXQoYXJndW1lbnRzWzBdKSkge1xuICAgICAgICAgICAgICAgIHRpbWUgPSBhcmd1bWVudHNbMF07XG4gICAgICAgICAgICAgICAgZm9ybWF0cyA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoaXNDYWxlbmRhclNwZWMoYXJndW1lbnRzWzBdKSkge1xuICAgICAgICAgICAgICAgIGZvcm1hdHMgPSBhcmd1bWVudHNbMF07XG4gICAgICAgICAgICAgICAgdGltZSA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICAvLyBXZSB3YW50IHRvIGNvbXBhcmUgdGhlIHN0YXJ0IG9mIHRvZGF5LCB2cyB0aGlzLlxuICAgICAgICAvLyBHZXR0aW5nIHN0YXJ0LW9mLXRvZGF5IGRlcGVuZHMgb24gd2hldGhlciB3ZSdyZSBsb2NhbC91dGMvb2Zmc2V0IG9yIG5vdC5cbiAgICAgICAgdmFyIG5vdyA9IHRpbWUgfHwgY3JlYXRlTG9jYWwoKSxcbiAgICAgICAgICAgIHNvZCA9IGNsb25lV2l0aE9mZnNldChub3csIHRoaXMpLnN0YXJ0T2YoJ2RheScpLFxuICAgICAgICAgICAgZm9ybWF0ID0gaG9va3MuY2FsZW5kYXJGb3JtYXQodGhpcywgc29kKSB8fCAnc2FtZUVsc2UnLFxuICAgICAgICAgICAgb3V0cHV0ID1cbiAgICAgICAgICAgICAgICBmb3JtYXRzICYmXG4gICAgICAgICAgICAgICAgKGlzRnVuY3Rpb24oZm9ybWF0c1tmb3JtYXRdKVxuICAgICAgICAgICAgICAgICAgICA/IGZvcm1hdHNbZm9ybWF0XS5jYWxsKHRoaXMsIG5vdylcbiAgICAgICAgICAgICAgICAgICAgOiBmb3JtYXRzW2Zvcm1hdF0pO1xuXG4gICAgICAgIHJldHVybiB0aGlzLmZvcm1hdChcbiAgICAgICAgICAgIG91dHB1dCB8fCB0aGlzLmxvY2FsZURhdGEoKS5jYWxlbmRhcihmb3JtYXQsIHRoaXMsIGNyZWF0ZUxvY2FsKG5vdykpXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gY2xvbmUoKSB7XG4gICAgICAgIHJldHVybiBuZXcgTW9tZW50KHRoaXMpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGlzQWZ0ZXIoaW5wdXQsIHVuaXRzKSB7XG4gICAgICAgIHZhciBsb2NhbElucHV0ID0gaXNNb21lbnQoaW5wdXQpID8gaW5wdXQgOiBjcmVhdGVMb2NhbChpbnB1dCk7XG4gICAgICAgIGlmICghKHRoaXMuaXNWYWxpZCgpICYmIGxvY2FsSW5wdXQuaXNWYWxpZCgpKSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIHVuaXRzID0gbm9ybWFsaXplVW5pdHModW5pdHMpIHx8ICdtaWxsaXNlY29uZCc7XG4gICAgICAgIGlmICh1bml0cyA9PT0gJ21pbGxpc2Vjb25kJykge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMudmFsdWVPZigpID4gbG9jYWxJbnB1dC52YWx1ZU9mKCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gbG9jYWxJbnB1dC52YWx1ZU9mKCkgPCB0aGlzLmNsb25lKCkuc3RhcnRPZih1bml0cykudmFsdWVPZigpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gaXNCZWZvcmUoaW5wdXQsIHVuaXRzKSB7XG4gICAgICAgIHZhciBsb2NhbElucHV0ID0gaXNNb21lbnQoaW5wdXQpID8gaW5wdXQgOiBjcmVhdGVMb2NhbChpbnB1dCk7XG4gICAgICAgIGlmICghKHRoaXMuaXNWYWxpZCgpICYmIGxvY2FsSW5wdXQuaXNWYWxpZCgpKSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIHVuaXRzID0gbm9ybWFsaXplVW5pdHModW5pdHMpIHx8ICdtaWxsaXNlY29uZCc7XG4gICAgICAgIGlmICh1bml0cyA9PT0gJ21pbGxpc2Vjb25kJykge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMudmFsdWVPZigpIDwgbG9jYWxJbnB1dC52YWx1ZU9mKCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5jbG9uZSgpLmVuZE9mKHVuaXRzKS52YWx1ZU9mKCkgPCBsb2NhbElucHV0LnZhbHVlT2YoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIGlzQmV0d2Vlbihmcm9tLCB0bywgdW5pdHMsIGluY2x1c2l2aXR5KSB7XG4gICAgICAgIHZhciBsb2NhbEZyb20gPSBpc01vbWVudChmcm9tKSA/IGZyb20gOiBjcmVhdGVMb2NhbChmcm9tKSxcbiAgICAgICAgICAgIGxvY2FsVG8gPSBpc01vbWVudCh0bykgPyB0byA6IGNyZWF0ZUxvY2FsKHRvKTtcbiAgICAgICAgaWYgKCEodGhpcy5pc1ZhbGlkKCkgJiYgbG9jYWxGcm9tLmlzVmFsaWQoKSAmJiBsb2NhbFRvLmlzVmFsaWQoKSkpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICBpbmNsdXNpdml0eSA9IGluY2x1c2l2aXR5IHx8ICcoKSc7XG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICAoaW5jbHVzaXZpdHlbMF0gPT09ICcoJ1xuICAgICAgICAgICAgICAgID8gdGhpcy5pc0FmdGVyKGxvY2FsRnJvbSwgdW5pdHMpXG4gICAgICAgICAgICAgICAgOiAhdGhpcy5pc0JlZm9yZShsb2NhbEZyb20sIHVuaXRzKSkgJiZcbiAgICAgICAgICAgIChpbmNsdXNpdml0eVsxXSA9PT0gJyknXG4gICAgICAgICAgICAgICAgPyB0aGlzLmlzQmVmb3JlKGxvY2FsVG8sIHVuaXRzKVxuICAgICAgICAgICAgICAgIDogIXRoaXMuaXNBZnRlcihsb2NhbFRvLCB1bml0cykpXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gaXNTYW1lKGlucHV0LCB1bml0cykge1xuICAgICAgICB2YXIgbG9jYWxJbnB1dCA9IGlzTW9tZW50KGlucHV0KSA/IGlucHV0IDogY3JlYXRlTG9jYWwoaW5wdXQpLFxuICAgICAgICAgICAgaW5wdXRNcztcbiAgICAgICAgaWYgKCEodGhpcy5pc1ZhbGlkKCkgJiYgbG9jYWxJbnB1dC5pc1ZhbGlkKCkpKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgdW5pdHMgPSBub3JtYWxpemVVbml0cyh1bml0cykgfHwgJ21pbGxpc2Vjb25kJztcbiAgICAgICAgaWYgKHVuaXRzID09PSAnbWlsbGlzZWNvbmQnKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy52YWx1ZU9mKCkgPT09IGxvY2FsSW5wdXQudmFsdWVPZigpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaW5wdXRNcyA9IGxvY2FsSW5wdXQudmFsdWVPZigpO1xuICAgICAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgICAgICB0aGlzLmNsb25lKCkuc3RhcnRPZih1bml0cykudmFsdWVPZigpIDw9IGlucHV0TXMgJiZcbiAgICAgICAgICAgICAgICBpbnB1dE1zIDw9IHRoaXMuY2xvbmUoKS5lbmRPZih1bml0cykudmFsdWVPZigpXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gaXNTYW1lT3JBZnRlcihpbnB1dCwgdW5pdHMpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuaXNTYW1lKGlucHV0LCB1bml0cykgfHwgdGhpcy5pc0FmdGVyKGlucHV0LCB1bml0cyk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gaXNTYW1lT3JCZWZvcmUoaW5wdXQsIHVuaXRzKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmlzU2FtZShpbnB1dCwgdW5pdHMpIHx8IHRoaXMuaXNCZWZvcmUoaW5wdXQsIHVuaXRzKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBkaWZmKGlucHV0LCB1bml0cywgYXNGbG9hdCkge1xuICAgICAgICB2YXIgdGhhdCwgem9uZURlbHRhLCBvdXRwdXQ7XG5cbiAgICAgICAgaWYgKCF0aGlzLmlzVmFsaWQoKSkge1xuICAgICAgICAgICAgcmV0dXJuIE5hTjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoYXQgPSBjbG9uZVdpdGhPZmZzZXQoaW5wdXQsIHRoaXMpO1xuXG4gICAgICAgIGlmICghdGhhdC5pc1ZhbGlkKCkpIHtcbiAgICAgICAgICAgIHJldHVybiBOYU47XG4gICAgICAgIH1cblxuICAgICAgICB6b25lRGVsdGEgPSAodGhhdC51dGNPZmZzZXQoKSAtIHRoaXMudXRjT2Zmc2V0KCkpICogNmU0O1xuXG4gICAgICAgIHVuaXRzID0gbm9ybWFsaXplVW5pdHModW5pdHMpO1xuXG4gICAgICAgIHN3aXRjaCAodW5pdHMpIHtcbiAgICAgICAgICAgIGNhc2UgJ3llYXInOlxuICAgICAgICAgICAgICAgIG91dHB1dCA9IG1vbnRoRGlmZih0aGlzLCB0aGF0KSAvIDEyO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSAnbW9udGgnOlxuICAgICAgICAgICAgICAgIG91dHB1dCA9IG1vbnRoRGlmZih0aGlzLCB0aGF0KTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgJ3F1YXJ0ZXInOlxuICAgICAgICAgICAgICAgIG91dHB1dCA9IG1vbnRoRGlmZih0aGlzLCB0aGF0KSAvIDM7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlICdzZWNvbmQnOlxuICAgICAgICAgICAgICAgIG91dHB1dCA9ICh0aGlzIC0gdGhhdCkgLyAxZTM7XG4gICAgICAgICAgICAgICAgYnJlYWs7IC8vIDEwMDBcbiAgICAgICAgICAgIGNhc2UgJ21pbnV0ZSc6XG4gICAgICAgICAgICAgICAgb3V0cHV0ID0gKHRoaXMgLSB0aGF0KSAvIDZlNDtcbiAgICAgICAgICAgICAgICBicmVhazsgLy8gMTAwMCAqIDYwXG4gICAgICAgICAgICBjYXNlICdob3VyJzpcbiAgICAgICAgICAgICAgICBvdXRwdXQgPSAodGhpcyAtIHRoYXQpIC8gMzZlNTtcbiAgICAgICAgICAgICAgICBicmVhazsgLy8gMTAwMCAqIDYwICogNjBcbiAgICAgICAgICAgIGNhc2UgJ2RheSc6XG4gICAgICAgICAgICAgICAgb3V0cHV0ID0gKHRoaXMgLSB0aGF0IC0gem9uZURlbHRhKSAvIDg2NGU1O1xuICAgICAgICAgICAgICAgIGJyZWFrOyAvLyAxMDAwICogNjAgKiA2MCAqIDI0LCBuZWdhdGUgZHN0XG4gICAgICAgICAgICBjYXNlICd3ZWVrJzpcbiAgICAgICAgICAgICAgICBvdXRwdXQgPSAodGhpcyAtIHRoYXQgLSB6b25lRGVsdGEpIC8gNjA0OGU1O1xuICAgICAgICAgICAgICAgIGJyZWFrOyAvLyAxMDAwICogNjAgKiA2MCAqIDI0ICogNywgbmVnYXRlIGRzdFxuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICBvdXRwdXQgPSB0aGlzIC0gdGhhdDtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBhc0Zsb2F0ID8gb3V0cHV0IDogYWJzRmxvb3Iob3V0cHV0KTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBtb250aERpZmYoYSwgYikge1xuICAgICAgICBpZiAoYS5kYXRlKCkgPCBiLmRhdGUoKSkge1xuICAgICAgICAgICAgLy8gZW5kLW9mLW1vbnRoIGNhbGN1bGF0aW9ucyB3b3JrIGNvcnJlY3Qgd2hlbiB0aGUgc3RhcnQgbW9udGggaGFzIG1vcmVcbiAgICAgICAgICAgIC8vIGRheXMgdGhhbiB0aGUgZW5kIG1vbnRoLlxuICAgICAgICAgICAgcmV0dXJuIC1tb250aERpZmYoYiwgYSk7XG4gICAgICAgIH1cbiAgICAgICAgLy8gZGlmZmVyZW5jZSBpbiBtb250aHNcbiAgICAgICAgdmFyIHdob2xlTW9udGhEaWZmID0gKGIueWVhcigpIC0gYS55ZWFyKCkpICogMTIgKyAoYi5tb250aCgpIC0gYS5tb250aCgpKSxcbiAgICAgICAgICAgIC8vIGIgaXMgaW4gKGFuY2hvciAtIDEgbW9udGgsIGFuY2hvciArIDEgbW9udGgpXG4gICAgICAgICAgICBhbmNob3IgPSBhLmNsb25lKCkuYWRkKHdob2xlTW9udGhEaWZmLCAnbW9udGhzJyksXG4gICAgICAgICAgICBhbmNob3IyLFxuICAgICAgICAgICAgYWRqdXN0O1xuXG4gICAgICAgIGlmIChiIC0gYW5jaG9yIDwgMCkge1xuICAgICAgICAgICAgYW5jaG9yMiA9IGEuY2xvbmUoKS5hZGQod2hvbGVNb250aERpZmYgLSAxLCAnbW9udGhzJyk7XG4gICAgICAgICAgICAvLyBsaW5lYXIgYWNyb3NzIHRoZSBtb250aFxuICAgICAgICAgICAgYWRqdXN0ID0gKGIgLSBhbmNob3IpIC8gKGFuY2hvciAtIGFuY2hvcjIpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgYW5jaG9yMiA9IGEuY2xvbmUoKS5hZGQod2hvbGVNb250aERpZmYgKyAxLCAnbW9udGhzJyk7XG4gICAgICAgICAgICAvLyBsaW5lYXIgYWNyb3NzIHRoZSBtb250aFxuICAgICAgICAgICAgYWRqdXN0ID0gKGIgLSBhbmNob3IpIC8gKGFuY2hvcjIgLSBhbmNob3IpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy9jaGVjayBmb3IgbmVnYXRpdmUgemVybywgcmV0dXJuIHplcm8gaWYgbmVnYXRpdmUgemVyb1xuICAgICAgICByZXR1cm4gLSh3aG9sZU1vbnRoRGlmZiArIGFkanVzdCkgfHwgMDtcbiAgICB9XG5cbiAgICBob29rcy5kZWZhdWx0Rm9ybWF0ID0gJ1lZWVktTU0tRERUSEg6bW06c3NaJztcbiAgICBob29rcy5kZWZhdWx0Rm9ybWF0VXRjID0gJ1lZWVktTU0tRERUSEg6bW06c3NbWl0nO1xuXG4gICAgZnVuY3Rpb24gdG9TdHJpbmcoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmNsb25lKCkubG9jYWxlKCdlbicpLmZvcm1hdCgnZGRkIE1NTSBERCBZWVlZIEhIOm1tOnNzIFtHTVRdWlonKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiB0b0lTT1N0cmluZyhrZWVwT2Zmc2V0KSB7XG4gICAgICAgIGlmICghdGhpcy5pc1ZhbGlkKCkpIHtcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG4gICAgICAgIHZhciB1dGMgPSBrZWVwT2Zmc2V0ICE9PSB0cnVlLFxuICAgICAgICAgICAgbSA9IHV0YyA/IHRoaXMuY2xvbmUoKS51dGMoKSA6IHRoaXM7XG4gICAgICAgIGlmIChtLnllYXIoKSA8IDAgfHwgbS55ZWFyKCkgPiA5OTk5KSB7XG4gICAgICAgICAgICByZXR1cm4gZm9ybWF0TW9tZW50KFxuICAgICAgICAgICAgICAgIG0sXG4gICAgICAgICAgICAgICAgdXRjXG4gICAgICAgICAgICAgICAgICAgID8gJ1lZWVlZWS1NTS1ERFtUXUhIOm1tOnNzLlNTU1taXSdcbiAgICAgICAgICAgICAgICAgICAgOiAnWVlZWVlZLU1NLUREW1RdSEg6bW06c3MuU1NTWidcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGlzRnVuY3Rpb24oRGF0ZS5wcm90b3R5cGUudG9JU09TdHJpbmcpKSB7XG4gICAgICAgICAgICAvLyBuYXRpdmUgaW1wbGVtZW50YXRpb24gaXMgfjUweCBmYXN0ZXIsIHVzZSBpdCB3aGVuIHdlIGNhblxuICAgICAgICAgICAgaWYgKHV0Yykge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLnRvRGF0ZSgpLnRvSVNPU3RyaW5nKCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJldHVybiBuZXcgRGF0ZSh0aGlzLnZhbHVlT2YoKSArIHRoaXMudXRjT2Zmc2V0KCkgKiA2MCAqIDEwMDApXG4gICAgICAgICAgICAgICAgICAgIC50b0lTT1N0cmluZygpXG4gICAgICAgICAgICAgICAgICAgIC5yZXBsYWNlKCdaJywgZm9ybWF0TW9tZW50KG0sICdaJykpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmb3JtYXRNb21lbnQoXG4gICAgICAgICAgICBtLFxuICAgICAgICAgICAgdXRjID8gJ1lZWVktTU0tRERbVF1ISDptbTpzcy5TU1NbWl0nIDogJ1lZWVktTU0tRERbVF1ISDptbTpzcy5TU1NaJ1xuICAgICAgICApO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJldHVybiBhIGh1bWFuIHJlYWRhYmxlIHJlcHJlc2VudGF0aW9uIG9mIGEgbW9tZW50IHRoYXQgY2FuXG4gICAgICogYWxzbyBiZSBldmFsdWF0ZWQgdG8gZ2V0IGEgbmV3IG1vbWVudCB3aGljaCBpcyB0aGUgc2FtZVxuICAgICAqXG4gICAgICogQGxpbmsgaHR0cHM6Ly9ub2RlanMub3JnL2Rpc3QvbGF0ZXN0L2RvY3MvYXBpL3V0aWwuaHRtbCN1dGlsX2N1c3RvbV9pbnNwZWN0X2Z1bmN0aW9uX29uX29iamVjdHNcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBpbnNwZWN0KCkge1xuICAgICAgICBpZiAoIXRoaXMuaXNWYWxpZCgpKSB7XG4gICAgICAgICAgICByZXR1cm4gJ21vbWVudC5pbnZhbGlkKC8qICcgKyB0aGlzLl9pICsgJyAqLyknO1xuICAgICAgICB9XG4gICAgICAgIHZhciBmdW5jID0gJ21vbWVudCcsXG4gICAgICAgICAgICB6b25lID0gJycsXG4gICAgICAgICAgICBwcmVmaXgsXG4gICAgICAgICAgICB5ZWFyLFxuICAgICAgICAgICAgZGF0ZXRpbWUsXG4gICAgICAgICAgICBzdWZmaXg7XG4gICAgICAgIGlmICghdGhpcy5pc0xvY2FsKCkpIHtcbiAgICAgICAgICAgIGZ1bmMgPSB0aGlzLnV0Y09mZnNldCgpID09PSAwID8gJ21vbWVudC51dGMnIDogJ21vbWVudC5wYXJzZVpvbmUnO1xuICAgICAgICAgICAgem9uZSA9ICdaJztcbiAgICAgICAgfVxuICAgICAgICBwcmVmaXggPSAnWycgKyBmdW5jICsgJyhcIl0nO1xuICAgICAgICB5ZWFyID0gMCA8PSB0aGlzLnllYXIoKSAmJiB0aGlzLnllYXIoKSA8PSA5OTk5ID8gJ1lZWVknIDogJ1lZWVlZWSc7XG4gICAgICAgIGRhdGV0aW1lID0gJy1NTS1ERFtUXUhIOm1tOnNzLlNTUyc7XG4gICAgICAgIHN1ZmZpeCA9IHpvbmUgKyAnW1wiKV0nO1xuXG4gICAgICAgIHJldHVybiB0aGlzLmZvcm1hdChwcmVmaXggKyB5ZWFyICsgZGF0ZXRpbWUgKyBzdWZmaXgpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGZvcm1hdChpbnB1dFN0cmluZykge1xuICAgICAgICBpZiAoIWlucHV0U3RyaW5nKSB7XG4gICAgICAgICAgICBpbnB1dFN0cmluZyA9IHRoaXMuaXNVdGMoKVxuICAgICAgICAgICAgICAgID8gaG9va3MuZGVmYXVsdEZvcm1hdFV0Y1xuICAgICAgICAgICAgICAgIDogaG9va3MuZGVmYXVsdEZvcm1hdDtcbiAgICAgICAgfVxuICAgICAgICB2YXIgb3V0cHV0ID0gZm9ybWF0TW9tZW50KHRoaXMsIGlucHV0U3RyaW5nKTtcbiAgICAgICAgcmV0dXJuIHRoaXMubG9jYWxlRGF0YSgpLnBvc3Rmb3JtYXQob3V0cHV0KTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBmcm9tKHRpbWUsIHdpdGhvdXRTdWZmaXgpIHtcbiAgICAgICAgaWYgKFxuICAgICAgICAgICAgdGhpcy5pc1ZhbGlkKCkgJiZcbiAgICAgICAgICAgICgoaXNNb21lbnQodGltZSkgJiYgdGltZS5pc1ZhbGlkKCkpIHx8IGNyZWF0ZUxvY2FsKHRpbWUpLmlzVmFsaWQoKSlcbiAgICAgICAgKSB7XG4gICAgICAgICAgICByZXR1cm4gY3JlYXRlRHVyYXRpb24oeyB0bzogdGhpcywgZnJvbTogdGltZSB9KVxuICAgICAgICAgICAgICAgIC5sb2NhbGUodGhpcy5sb2NhbGUoKSlcbiAgICAgICAgICAgICAgICAuaHVtYW5pemUoIXdpdGhvdXRTdWZmaXgpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMubG9jYWxlRGF0YSgpLmludmFsaWREYXRlKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiBmcm9tTm93KHdpdGhvdXRTdWZmaXgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZnJvbShjcmVhdGVMb2NhbCgpLCB3aXRob3V0U3VmZml4KTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiB0byh0aW1lLCB3aXRob3V0U3VmZml4KSB7XG4gICAgICAgIGlmIChcbiAgICAgICAgICAgIHRoaXMuaXNWYWxpZCgpICYmXG4gICAgICAgICAgICAoKGlzTW9tZW50KHRpbWUpICYmIHRpbWUuaXNWYWxpZCgpKSB8fCBjcmVhdGVMb2NhbCh0aW1lKS5pc1ZhbGlkKCkpXG4gICAgICAgICkge1xuICAgICAgICAgICAgcmV0dXJuIGNyZWF0ZUR1cmF0aW9uKHsgZnJvbTogdGhpcywgdG86IHRpbWUgfSlcbiAgICAgICAgICAgICAgICAubG9jYWxlKHRoaXMubG9jYWxlKCkpXG4gICAgICAgICAgICAgICAgLmh1bWFuaXplKCF3aXRob3V0U3VmZml4KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmxvY2FsZURhdGEoKS5pbnZhbGlkRGF0ZSgpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gdG9Ob3cod2l0aG91dFN1ZmZpeCkge1xuICAgICAgICByZXR1cm4gdGhpcy50byhjcmVhdGVMb2NhbCgpLCB3aXRob3V0U3VmZml4KTtcbiAgICB9XG5cbiAgICAvLyBJZiBwYXNzZWQgYSBsb2NhbGUga2V5LCBpdCB3aWxsIHNldCB0aGUgbG9jYWxlIGZvciB0aGlzXG4gICAgLy8gaW5zdGFuY2UuICBPdGhlcndpc2UsIGl0IHdpbGwgcmV0dXJuIHRoZSBsb2NhbGUgY29uZmlndXJhdGlvblxuICAgIC8vIHZhcmlhYmxlcyBmb3IgdGhpcyBpbnN0YW5jZS5cbiAgICBmdW5jdGlvbiBsb2NhbGUoa2V5KSB7XG4gICAgICAgIHZhciBuZXdMb2NhbGVEYXRhO1xuXG4gICAgICAgIGlmIChrZXkgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2xvY2FsZS5fYWJicjtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIG5ld0xvY2FsZURhdGEgPSBnZXRMb2NhbGUoa2V5KTtcbiAgICAgICAgICAgIGlmIChuZXdMb2NhbGVEYXRhICE9IG51bGwpIHtcbiAgICAgICAgICAgICAgICB0aGlzLl9sb2NhbGUgPSBuZXdMb2NhbGVEYXRhO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICB2YXIgbGFuZyA9IGRlcHJlY2F0ZShcbiAgICAgICAgJ21vbWVudCgpLmxhbmcoKSBpcyBkZXByZWNhdGVkLiBJbnN0ZWFkLCB1c2UgbW9tZW50KCkubG9jYWxlRGF0YSgpIHRvIGdldCB0aGUgbGFuZ3VhZ2UgY29uZmlndXJhdGlvbi4gVXNlIG1vbWVudCgpLmxvY2FsZSgpIHRvIGNoYW5nZSBsYW5ndWFnZXMuJyxcbiAgICAgICAgZnVuY3Rpb24gKGtleSkge1xuICAgICAgICAgICAgaWYgKGtleSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMubG9jYWxlRGF0YSgpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5sb2NhbGUoa2V5KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICk7XG5cbiAgICBmdW5jdGlvbiBsb2NhbGVEYXRhKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fbG9jYWxlO1xuICAgIH1cblxuICAgIHZhciBNU19QRVJfU0VDT05EID0gMTAwMCxcbiAgICAgICAgTVNfUEVSX01JTlVURSA9IDYwICogTVNfUEVSX1NFQ09ORCxcbiAgICAgICAgTVNfUEVSX0hPVVIgPSA2MCAqIE1TX1BFUl9NSU5VVEUsXG4gICAgICAgIE1TX1BFUl80MDBfWUVBUlMgPSAoMzY1ICogNDAwICsgOTcpICogMjQgKiBNU19QRVJfSE9VUjtcblxuICAgIC8vIGFjdHVhbCBtb2R1bG8gLSBoYW5kbGVzIG5lZ2F0aXZlIG51bWJlcnMgKGZvciBkYXRlcyBiZWZvcmUgMTk3MCk6XG4gICAgZnVuY3Rpb24gbW9kJDEoZGl2aWRlbmQsIGRpdmlzb3IpIHtcbiAgICAgICAgcmV0dXJuICgoZGl2aWRlbmQgJSBkaXZpc29yKSArIGRpdmlzb3IpICUgZGl2aXNvcjtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBsb2NhbFN0YXJ0T2ZEYXRlKHksIG0sIGQpIHtcbiAgICAgICAgLy8gdGhlIGRhdGUgY29uc3RydWN0b3IgcmVtYXBzIHllYXJzIDAtOTkgdG8gMTkwMC0xOTk5XG4gICAgICAgIGlmICh5IDwgMTAwICYmIHkgPj0gMCkge1xuICAgICAgICAgICAgLy8gcHJlc2VydmUgbGVhcCB5ZWFycyB1c2luZyBhIGZ1bGwgNDAwIHllYXIgY3ljbGUsIHRoZW4gcmVzZXRcbiAgICAgICAgICAgIHJldHVybiBuZXcgRGF0ZSh5ICsgNDAwLCBtLCBkKSAtIE1TX1BFUl80MDBfWUVBUlM7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3IERhdGUoeSwgbSwgZCkudmFsdWVPZigpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gdXRjU3RhcnRPZkRhdGUoeSwgbSwgZCkge1xuICAgICAgICAvLyBEYXRlLlVUQyByZW1hcHMgeWVhcnMgMC05OSB0byAxOTAwLTE5OTlcbiAgICAgICAgaWYgKHkgPCAxMDAgJiYgeSA+PSAwKSB7XG4gICAgICAgICAgICAvLyBwcmVzZXJ2ZSBsZWFwIHllYXJzIHVzaW5nIGEgZnVsbCA0MDAgeWVhciBjeWNsZSwgdGhlbiByZXNldFxuICAgICAgICAgICAgcmV0dXJuIERhdGUuVVRDKHkgKyA0MDAsIG0sIGQpIC0gTVNfUEVSXzQwMF9ZRUFSUztcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBEYXRlLlVUQyh5LCBtLCBkKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIHN0YXJ0T2YodW5pdHMpIHtcbiAgICAgICAgdmFyIHRpbWUsIHN0YXJ0T2ZEYXRlO1xuICAgICAgICB1bml0cyA9IG5vcm1hbGl6ZVVuaXRzKHVuaXRzKTtcbiAgICAgICAgaWYgKHVuaXRzID09PSB1bmRlZmluZWQgfHwgdW5pdHMgPT09ICdtaWxsaXNlY29uZCcgfHwgIXRoaXMuaXNWYWxpZCgpKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfVxuXG4gICAgICAgIHN0YXJ0T2ZEYXRlID0gdGhpcy5faXNVVEMgPyB1dGNTdGFydE9mRGF0ZSA6IGxvY2FsU3RhcnRPZkRhdGU7XG5cbiAgICAgICAgc3dpdGNoICh1bml0cykge1xuICAgICAgICAgICAgY2FzZSAneWVhcic6XG4gICAgICAgICAgICAgICAgdGltZSA9IHN0YXJ0T2ZEYXRlKHRoaXMueWVhcigpLCAwLCAxKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgJ3F1YXJ0ZXInOlxuICAgICAgICAgICAgICAgIHRpbWUgPSBzdGFydE9mRGF0ZShcbiAgICAgICAgICAgICAgICAgICAgdGhpcy55ZWFyKCksXG4gICAgICAgICAgICAgICAgICAgIHRoaXMubW9udGgoKSAtICh0aGlzLm1vbnRoKCkgJSAzKSxcbiAgICAgICAgICAgICAgICAgICAgMVxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlICdtb250aCc6XG4gICAgICAgICAgICAgICAgdGltZSA9IHN0YXJ0T2ZEYXRlKHRoaXMueWVhcigpLCB0aGlzLm1vbnRoKCksIDEpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSAnd2Vlayc6XG4gICAgICAgICAgICAgICAgdGltZSA9IHN0YXJ0T2ZEYXRlKFxuICAgICAgICAgICAgICAgICAgICB0aGlzLnllYXIoKSxcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5tb250aCgpLFxuICAgICAgICAgICAgICAgICAgICB0aGlzLmRhdGUoKSAtIHRoaXMud2Vla2RheSgpXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgJ2lzb1dlZWsnOlxuICAgICAgICAgICAgICAgIHRpbWUgPSBzdGFydE9mRGF0ZShcbiAgICAgICAgICAgICAgICAgICAgdGhpcy55ZWFyKCksXG4gICAgICAgICAgICAgICAgICAgIHRoaXMubW9udGgoKSxcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5kYXRlKCkgLSAodGhpcy5pc29XZWVrZGF5KCkgLSAxKVxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlICdkYXknOlxuICAgICAgICAgICAgY2FzZSAnZGF0ZSc6XG4gICAgICAgICAgICAgICAgdGltZSA9IHN0YXJ0T2ZEYXRlKHRoaXMueWVhcigpLCB0aGlzLm1vbnRoKCksIHRoaXMuZGF0ZSgpKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgJ2hvdXInOlxuICAgICAgICAgICAgICAgIHRpbWUgPSB0aGlzLl9kLnZhbHVlT2YoKTtcbiAgICAgICAgICAgICAgICB0aW1lIC09IG1vZCQxKFxuICAgICAgICAgICAgICAgICAgICB0aW1lICsgKHRoaXMuX2lzVVRDID8gMCA6IHRoaXMudXRjT2Zmc2V0KCkgKiBNU19QRVJfTUlOVVRFKSxcbiAgICAgICAgICAgICAgICAgICAgTVNfUEVSX0hPVVJcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSAnbWludXRlJzpcbiAgICAgICAgICAgICAgICB0aW1lID0gdGhpcy5fZC52YWx1ZU9mKCk7XG4gICAgICAgICAgICAgICAgdGltZSAtPSBtb2QkMSh0aW1lLCBNU19QRVJfTUlOVVRFKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgJ3NlY29uZCc6XG4gICAgICAgICAgICAgICAgdGltZSA9IHRoaXMuX2QudmFsdWVPZigpO1xuICAgICAgICAgICAgICAgIHRpbWUgLT0gbW9kJDEodGltZSwgTVNfUEVSX1NFQ09ORCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLl9kLnNldFRpbWUodGltZSk7XG4gICAgICAgIGhvb2tzLnVwZGF0ZU9mZnNldCh0aGlzLCB0cnVlKTtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gZW5kT2YodW5pdHMpIHtcbiAgICAgICAgdmFyIHRpbWUsIHN0YXJ0T2ZEYXRlO1xuICAgICAgICB1bml0cyA9IG5vcm1hbGl6ZVVuaXRzKHVuaXRzKTtcbiAgICAgICAgaWYgKHVuaXRzID09PSB1bmRlZmluZWQgfHwgdW5pdHMgPT09ICdtaWxsaXNlY29uZCcgfHwgIXRoaXMuaXNWYWxpZCgpKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfVxuXG4gICAgICAgIHN0YXJ0T2ZEYXRlID0gdGhpcy5faXNVVEMgPyB1dGNTdGFydE9mRGF0ZSA6IGxvY2FsU3RhcnRPZkRhdGU7XG5cbiAgICAgICAgc3dpdGNoICh1bml0cykge1xuICAgICAgICAgICAgY2FzZSAneWVhcic6XG4gICAgICAgICAgICAgICAgdGltZSA9IHN0YXJ0T2ZEYXRlKHRoaXMueWVhcigpICsgMSwgMCwgMSkgLSAxO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSAncXVhcnRlcic6XG4gICAgICAgICAgICAgICAgdGltZSA9XG4gICAgICAgICAgICAgICAgICAgIHN0YXJ0T2ZEYXRlKFxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy55ZWFyKCksXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLm1vbnRoKCkgLSAodGhpcy5tb250aCgpICUgMykgKyAzLFxuICAgICAgICAgICAgICAgICAgICAgICAgMVxuICAgICAgICAgICAgICAgICAgICApIC0gMTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgJ21vbnRoJzpcbiAgICAgICAgICAgICAgICB0aW1lID0gc3RhcnRPZkRhdGUodGhpcy55ZWFyKCksIHRoaXMubW9udGgoKSArIDEsIDEpIC0gMTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgJ3dlZWsnOlxuICAgICAgICAgICAgICAgIHRpbWUgPVxuICAgICAgICAgICAgICAgICAgICBzdGFydE9mRGF0ZShcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMueWVhcigpLFxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5tb250aCgpLFxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5kYXRlKCkgLSB0aGlzLndlZWtkYXkoKSArIDdcbiAgICAgICAgICAgICAgICAgICAgKSAtIDE7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlICdpc29XZWVrJzpcbiAgICAgICAgICAgICAgICB0aW1lID1cbiAgICAgICAgICAgICAgICAgICAgc3RhcnRPZkRhdGUoXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnllYXIoKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMubW9udGgoKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZGF0ZSgpIC0gKHRoaXMuaXNvV2Vla2RheSgpIC0gMSkgKyA3XG4gICAgICAgICAgICAgICAgICAgICkgLSAxO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSAnZGF5JzpcbiAgICAgICAgICAgIGNhc2UgJ2RhdGUnOlxuICAgICAgICAgICAgICAgIHRpbWUgPSBzdGFydE9mRGF0ZSh0aGlzLnllYXIoKSwgdGhpcy5tb250aCgpLCB0aGlzLmRhdGUoKSArIDEpIC0gMTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgJ2hvdXInOlxuICAgICAgICAgICAgICAgIHRpbWUgPSB0aGlzLl9kLnZhbHVlT2YoKTtcbiAgICAgICAgICAgICAgICB0aW1lICs9XG4gICAgICAgICAgICAgICAgICAgIE1TX1BFUl9IT1VSIC1cbiAgICAgICAgICAgICAgICAgICAgbW9kJDEoXG4gICAgICAgICAgICAgICAgICAgICAgICB0aW1lICsgKHRoaXMuX2lzVVRDID8gMCA6IHRoaXMudXRjT2Zmc2V0KCkgKiBNU19QRVJfTUlOVVRFKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIE1TX1BFUl9IT1VSXG4gICAgICAgICAgICAgICAgICAgICkgLVxuICAgICAgICAgICAgICAgICAgICAxO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSAnbWludXRlJzpcbiAgICAgICAgICAgICAgICB0aW1lID0gdGhpcy5fZC52YWx1ZU9mKCk7XG4gICAgICAgICAgICAgICAgdGltZSArPSBNU19QRVJfTUlOVVRFIC0gbW9kJDEodGltZSwgTVNfUEVSX01JTlVURSkgLSAxO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSAnc2Vjb25kJzpcbiAgICAgICAgICAgICAgICB0aW1lID0gdGhpcy5fZC52YWx1ZU9mKCk7XG4gICAgICAgICAgICAgICAgdGltZSArPSBNU19QRVJfU0VDT05EIC0gbW9kJDEodGltZSwgTVNfUEVSX1NFQ09ORCkgLSAxO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5fZC5zZXRUaW1lKHRpbWUpO1xuICAgICAgICBob29rcy51cGRhdGVPZmZzZXQodGhpcywgdHJ1ZSk7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHZhbHVlT2YoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9kLnZhbHVlT2YoKSAtICh0aGlzLl9vZmZzZXQgfHwgMCkgKiA2MDAwMDtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiB1bml4KCkge1xuICAgICAgICByZXR1cm4gTWF0aC5mbG9vcih0aGlzLnZhbHVlT2YoKSAvIDEwMDApO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHRvRGF0ZSgpIHtcbiAgICAgICAgcmV0dXJuIG5ldyBEYXRlKHRoaXMudmFsdWVPZigpKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiB0b0FycmF5KCkge1xuICAgICAgICB2YXIgbSA9IHRoaXM7XG4gICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICBtLnllYXIoKSxcbiAgICAgICAgICAgIG0ubW9udGgoKSxcbiAgICAgICAgICAgIG0uZGF0ZSgpLFxuICAgICAgICAgICAgbS5ob3VyKCksXG4gICAgICAgICAgICBtLm1pbnV0ZSgpLFxuICAgICAgICAgICAgbS5zZWNvbmQoKSxcbiAgICAgICAgICAgIG0ubWlsbGlzZWNvbmQoKSxcbiAgICAgICAgXTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiB0b09iamVjdCgpIHtcbiAgICAgICAgdmFyIG0gPSB0aGlzO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgeWVhcnM6IG0ueWVhcigpLFxuICAgICAgICAgICAgbW9udGhzOiBtLm1vbnRoKCksXG4gICAgICAgICAgICBkYXRlOiBtLmRhdGUoKSxcbiAgICAgICAgICAgIGhvdXJzOiBtLmhvdXJzKCksXG4gICAgICAgICAgICBtaW51dGVzOiBtLm1pbnV0ZXMoKSxcbiAgICAgICAgICAgIHNlY29uZHM6IG0uc2Vjb25kcygpLFxuICAgICAgICAgICAgbWlsbGlzZWNvbmRzOiBtLm1pbGxpc2Vjb25kcygpLFxuICAgICAgICB9O1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHRvSlNPTigpIHtcbiAgICAgICAgLy8gbmV3IERhdGUoTmFOKS50b0pTT04oKSA9PT0gbnVsbFxuICAgICAgICByZXR1cm4gdGhpcy5pc1ZhbGlkKCkgPyB0aGlzLnRvSVNPU3RyaW5nKCkgOiBudWxsO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGlzVmFsaWQkMigpIHtcbiAgICAgICAgcmV0dXJuIGlzVmFsaWQodGhpcyk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gcGFyc2luZ0ZsYWdzKCkge1xuICAgICAgICByZXR1cm4gZXh0ZW5kKHt9LCBnZXRQYXJzaW5nRmxhZ3ModGhpcykpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGludmFsaWRBdCgpIHtcbiAgICAgICAgcmV0dXJuIGdldFBhcnNpbmdGbGFncyh0aGlzKS5vdmVyZmxvdztcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBjcmVhdGlvbkRhdGEoKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBpbnB1dDogdGhpcy5faSxcbiAgICAgICAgICAgIGZvcm1hdDogdGhpcy5fZixcbiAgICAgICAgICAgIGxvY2FsZTogdGhpcy5fbG9jYWxlLFxuICAgICAgICAgICAgaXNVVEM6IHRoaXMuX2lzVVRDLFxuICAgICAgICAgICAgc3RyaWN0OiB0aGlzLl9zdHJpY3QsXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgYWRkRm9ybWF0VG9rZW4oJ04nLCAwLCAwLCAnZXJhQWJicicpO1xuICAgIGFkZEZvcm1hdFRva2VuKCdOTicsIDAsIDAsICdlcmFBYmJyJyk7XG4gICAgYWRkRm9ybWF0VG9rZW4oJ05OTicsIDAsIDAsICdlcmFBYmJyJyk7XG4gICAgYWRkRm9ybWF0VG9rZW4oJ05OTk4nLCAwLCAwLCAnZXJhTmFtZScpO1xuICAgIGFkZEZvcm1hdFRva2VuKCdOTk5OTicsIDAsIDAsICdlcmFOYXJyb3cnKTtcblxuICAgIGFkZEZvcm1hdFRva2VuKCd5JywgWyd5JywgMV0sICd5bycsICdlcmFZZWFyJyk7XG4gICAgYWRkRm9ybWF0VG9rZW4oJ3knLCBbJ3l5JywgMl0sIDAsICdlcmFZZWFyJyk7XG4gICAgYWRkRm9ybWF0VG9rZW4oJ3knLCBbJ3l5eScsIDNdLCAwLCAnZXJhWWVhcicpO1xuICAgIGFkZEZvcm1hdFRva2VuKCd5JywgWyd5eXl5JywgNF0sIDAsICdlcmFZZWFyJyk7XG5cbiAgICBhZGRSZWdleFRva2VuKCdOJywgbWF0Y2hFcmFBYmJyKTtcbiAgICBhZGRSZWdleFRva2VuKCdOTicsIG1hdGNoRXJhQWJicik7XG4gICAgYWRkUmVnZXhUb2tlbignTk5OJywgbWF0Y2hFcmFBYmJyKTtcbiAgICBhZGRSZWdleFRva2VuKCdOTk5OJywgbWF0Y2hFcmFOYW1lKTtcbiAgICBhZGRSZWdleFRva2VuKCdOTk5OTicsIG1hdGNoRXJhTmFycm93KTtcblxuICAgIGFkZFBhcnNlVG9rZW4oWydOJywgJ05OJywgJ05OTicsICdOTk5OJywgJ05OTk5OJ10sIGZ1bmN0aW9uIChcbiAgICAgICAgaW5wdXQsXG4gICAgICAgIGFycmF5LFxuICAgICAgICBjb25maWcsXG4gICAgICAgIHRva2VuXG4gICAgKSB7XG4gICAgICAgIHZhciBlcmEgPSBjb25maWcuX2xvY2FsZS5lcmFzUGFyc2UoaW5wdXQsIHRva2VuLCBjb25maWcuX3N0cmljdCk7XG4gICAgICAgIGlmIChlcmEpIHtcbiAgICAgICAgICAgIGdldFBhcnNpbmdGbGFncyhjb25maWcpLmVyYSA9IGVyYTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGdldFBhcnNpbmdGbGFncyhjb25maWcpLmludmFsaWRFcmEgPSBpbnB1dDtcbiAgICAgICAgfVxuICAgIH0pO1xuXG4gICAgYWRkUmVnZXhUb2tlbigneScsIG1hdGNoVW5zaWduZWQpO1xuICAgIGFkZFJlZ2V4VG9rZW4oJ3l5JywgbWF0Y2hVbnNpZ25lZCk7XG4gICAgYWRkUmVnZXhUb2tlbigneXl5JywgbWF0Y2hVbnNpZ25lZCk7XG4gICAgYWRkUmVnZXhUb2tlbigneXl5eScsIG1hdGNoVW5zaWduZWQpO1xuICAgIGFkZFJlZ2V4VG9rZW4oJ3lvJywgbWF0Y2hFcmFZZWFyT3JkaW5hbCk7XG5cbiAgICBhZGRQYXJzZVRva2VuKFsneScsICd5eScsICd5eXknLCAneXl5eSddLCBZRUFSKTtcbiAgICBhZGRQYXJzZVRva2VuKFsneW8nXSwgZnVuY3Rpb24gKGlucHV0LCBhcnJheSwgY29uZmlnLCB0b2tlbikge1xuICAgICAgICB2YXIgbWF0Y2g7XG4gICAgICAgIGlmIChjb25maWcuX2xvY2FsZS5fZXJhWWVhck9yZGluYWxSZWdleCkge1xuICAgICAgICAgICAgbWF0Y2ggPSBpbnB1dC5tYXRjaChjb25maWcuX2xvY2FsZS5fZXJhWWVhck9yZGluYWxSZWdleCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoY29uZmlnLl9sb2NhbGUuZXJhWWVhck9yZGluYWxQYXJzZSkge1xuICAgICAgICAgICAgYXJyYXlbWUVBUl0gPSBjb25maWcuX2xvY2FsZS5lcmFZZWFyT3JkaW5hbFBhcnNlKGlucHV0LCBtYXRjaCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBhcnJheVtZRUFSXSA9IHBhcnNlSW50KGlucHV0LCAxMCk7XG4gICAgICAgIH1cbiAgICB9KTtcblxuICAgIGZ1bmN0aW9uIGxvY2FsZUVyYXMobSwgZm9ybWF0KSB7XG4gICAgICAgIHZhciBpLFxuICAgICAgICAgICAgbCxcbiAgICAgICAgICAgIGRhdGUsXG4gICAgICAgICAgICBlcmFzID0gdGhpcy5fZXJhcyB8fCBnZXRMb2NhbGUoJ2VuJykuX2VyYXM7XG4gICAgICAgIGZvciAoaSA9IDAsIGwgPSBlcmFzLmxlbmd0aDsgaSA8IGw7ICsraSkge1xuICAgICAgICAgICAgc3dpdGNoICh0eXBlb2YgZXJhc1tpXS5zaW5jZSkge1xuICAgICAgICAgICAgICAgIGNhc2UgJ3N0cmluZyc6XG4gICAgICAgICAgICAgICAgICAgIC8vIHRydW5jYXRlIHRpbWVcbiAgICAgICAgICAgICAgICAgICAgZGF0ZSA9IGhvb2tzKGVyYXNbaV0uc2luY2UpLnN0YXJ0T2YoJ2RheScpO1xuICAgICAgICAgICAgICAgICAgICBlcmFzW2ldLnNpbmNlID0gZGF0ZS52YWx1ZU9mKCk7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBzd2l0Y2ggKHR5cGVvZiBlcmFzW2ldLnVudGlsKSB7XG4gICAgICAgICAgICAgICAgY2FzZSAndW5kZWZpbmVkJzpcbiAgICAgICAgICAgICAgICAgICAgZXJhc1tpXS51bnRpbCA9ICtJbmZpbml0eTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgY2FzZSAnc3RyaW5nJzpcbiAgICAgICAgICAgICAgICAgICAgLy8gdHJ1bmNhdGUgdGltZVxuICAgICAgICAgICAgICAgICAgICBkYXRlID0gaG9va3MoZXJhc1tpXS51bnRpbCkuc3RhcnRPZignZGF5JykudmFsdWVPZigpO1xuICAgICAgICAgICAgICAgICAgICBlcmFzW2ldLnVudGlsID0gZGF0ZS52YWx1ZU9mKCk7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBlcmFzO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGxvY2FsZUVyYXNQYXJzZShlcmFOYW1lLCBmb3JtYXQsIHN0cmljdCkge1xuICAgICAgICB2YXIgaSxcbiAgICAgICAgICAgIGwsXG4gICAgICAgICAgICBlcmFzID0gdGhpcy5lcmFzKCksXG4gICAgICAgICAgICBuYW1lLFxuICAgICAgICAgICAgYWJicixcbiAgICAgICAgICAgIG5hcnJvdztcbiAgICAgICAgZXJhTmFtZSA9IGVyYU5hbWUudG9VcHBlckNhc2UoKTtcblxuICAgICAgICBmb3IgKGkgPSAwLCBsID0gZXJhcy5sZW5ndGg7IGkgPCBsOyArK2kpIHtcbiAgICAgICAgICAgIG5hbWUgPSBlcmFzW2ldLm5hbWUudG9VcHBlckNhc2UoKTtcbiAgICAgICAgICAgIGFiYnIgPSBlcmFzW2ldLmFiYnIudG9VcHBlckNhc2UoKTtcbiAgICAgICAgICAgIG5hcnJvdyA9IGVyYXNbaV0ubmFycm93LnRvVXBwZXJDYXNlKCk7XG5cbiAgICAgICAgICAgIGlmIChzdHJpY3QpIHtcbiAgICAgICAgICAgICAgICBzd2l0Y2ggKGZvcm1hdCkge1xuICAgICAgICAgICAgICAgICAgICBjYXNlICdOJzpcbiAgICAgICAgICAgICAgICAgICAgY2FzZSAnTk4nOlxuICAgICAgICAgICAgICAgICAgICBjYXNlICdOTk4nOlxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGFiYnIgPT09IGVyYU5hbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZXJhc1tpXTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICAgICAgICAgIGNhc2UgJ05OTk4nOlxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG5hbWUgPT09IGVyYU5hbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZXJhc1tpXTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICAgICAgICAgIGNhc2UgJ05OTk5OJzpcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChuYXJyb3cgPT09IGVyYU5hbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZXJhc1tpXTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSBpZiAoW25hbWUsIGFiYnIsIG5hcnJvd10uaW5kZXhPZihlcmFOYW1lKSA+PSAwKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGVyYXNbaV07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiBsb2NhbGVFcmFzQ29udmVydFllYXIoZXJhLCB5ZWFyKSB7XG4gICAgICAgIHZhciBkaXIgPSBlcmEuc2luY2UgPD0gZXJhLnVudGlsID8gKzEgOiAtMTtcbiAgICAgICAgaWYgKHllYXIgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgcmV0dXJuIGhvb2tzKGVyYS5zaW5jZSkueWVhcigpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIGhvb2tzKGVyYS5zaW5jZSkueWVhcigpICsgKHllYXIgLSBlcmEub2Zmc2V0KSAqIGRpcjtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIGdldEVyYU5hbWUoKSB7XG4gICAgICAgIHZhciBpLFxuICAgICAgICAgICAgbCxcbiAgICAgICAgICAgIHZhbCxcbiAgICAgICAgICAgIGVyYXMgPSB0aGlzLmxvY2FsZURhdGEoKS5lcmFzKCk7XG4gICAgICAgIGZvciAoaSA9IDAsIGwgPSBlcmFzLmxlbmd0aDsgaSA8IGw7ICsraSkge1xuICAgICAgICAgICAgLy8gdHJ1bmNhdGUgdGltZVxuICAgICAgICAgICAgdmFsID0gdGhpcy5zdGFydE9mKCdkYXknKS52YWx1ZU9mKCk7XG5cbiAgICAgICAgICAgIGlmIChlcmFzW2ldLnNpbmNlIDw9IHZhbCAmJiB2YWwgPD0gZXJhc1tpXS51bnRpbCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBlcmFzW2ldLm5hbWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoZXJhc1tpXS51bnRpbCA8PSB2YWwgJiYgdmFsIDw9IGVyYXNbaV0uc2luY2UpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZXJhc1tpXS5uYW1lO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuICcnO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGdldEVyYU5hcnJvdygpIHtcbiAgICAgICAgdmFyIGksXG4gICAgICAgICAgICBsLFxuICAgICAgICAgICAgdmFsLFxuICAgICAgICAgICAgZXJhcyA9IHRoaXMubG9jYWxlRGF0YSgpLmVyYXMoKTtcbiAgICAgICAgZm9yIChpID0gMCwgbCA9IGVyYXMubGVuZ3RoOyBpIDwgbDsgKytpKSB7XG4gICAgICAgICAgICAvLyB0cnVuY2F0ZSB0aW1lXG4gICAgICAgICAgICB2YWwgPSB0aGlzLnN0YXJ0T2YoJ2RheScpLnZhbHVlT2YoKTtcblxuICAgICAgICAgICAgaWYgKGVyYXNbaV0uc2luY2UgPD0gdmFsICYmIHZhbCA8PSBlcmFzW2ldLnVudGlsKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGVyYXNbaV0ubmFycm93O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGVyYXNbaV0udW50aWwgPD0gdmFsICYmIHZhbCA8PSBlcmFzW2ldLnNpbmNlKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGVyYXNbaV0ubmFycm93O1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuICcnO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGdldEVyYUFiYnIoKSB7XG4gICAgICAgIHZhciBpLFxuICAgICAgICAgICAgbCxcbiAgICAgICAgICAgIHZhbCxcbiAgICAgICAgICAgIGVyYXMgPSB0aGlzLmxvY2FsZURhdGEoKS5lcmFzKCk7XG4gICAgICAgIGZvciAoaSA9IDAsIGwgPSBlcmFzLmxlbmd0aDsgaSA8IGw7ICsraSkge1xuICAgICAgICAgICAgLy8gdHJ1bmNhdGUgdGltZVxuICAgICAgICAgICAgdmFsID0gdGhpcy5zdGFydE9mKCdkYXknKS52YWx1ZU9mKCk7XG5cbiAgICAgICAgICAgIGlmIChlcmFzW2ldLnNpbmNlIDw9IHZhbCAmJiB2YWwgPD0gZXJhc1tpXS51bnRpbCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBlcmFzW2ldLmFiYnI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoZXJhc1tpXS51bnRpbCA8PSB2YWwgJiYgdmFsIDw9IGVyYXNbaV0uc2luY2UpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZXJhc1tpXS5hYmJyO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuICcnO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGdldEVyYVllYXIoKSB7XG4gICAgICAgIHZhciBpLFxuICAgICAgICAgICAgbCxcbiAgICAgICAgICAgIGRpcixcbiAgICAgICAgICAgIHZhbCxcbiAgICAgICAgICAgIGVyYXMgPSB0aGlzLmxvY2FsZURhdGEoKS5lcmFzKCk7XG4gICAgICAgIGZvciAoaSA9IDAsIGwgPSBlcmFzLmxlbmd0aDsgaSA8IGw7ICsraSkge1xuICAgICAgICAgICAgZGlyID0gZXJhc1tpXS5zaW5jZSA8PSBlcmFzW2ldLnVudGlsID8gKzEgOiAtMTtcblxuICAgICAgICAgICAgLy8gdHJ1bmNhdGUgdGltZVxuICAgICAgICAgICAgdmFsID0gdGhpcy5zdGFydE9mKCdkYXknKS52YWx1ZU9mKCk7XG5cbiAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICAoZXJhc1tpXS5zaW5jZSA8PSB2YWwgJiYgdmFsIDw9IGVyYXNbaV0udW50aWwpIHx8XG4gICAgICAgICAgICAgICAgKGVyYXNbaV0udW50aWwgPD0gdmFsICYmIHZhbCA8PSBlcmFzW2ldLnNpbmNlKVxuICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgICAgICAgICAgKHRoaXMueWVhcigpIC0gaG9va3MoZXJhc1tpXS5zaW5jZSkueWVhcigpKSAqIGRpciArXG4gICAgICAgICAgICAgICAgICAgIGVyYXNbaV0ub2Zmc2V0XG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzLnllYXIoKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBlcmFzTmFtZVJlZ2V4KGlzU3RyaWN0KSB7XG4gICAgICAgIGlmICghaGFzT3duUHJvcCh0aGlzLCAnX2VyYXNOYW1lUmVnZXgnKSkge1xuICAgICAgICAgICAgY29tcHV0ZUVyYXNQYXJzZS5jYWxsKHRoaXMpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBpc1N0cmljdCA/IHRoaXMuX2VyYXNOYW1lUmVnZXggOiB0aGlzLl9lcmFzUmVnZXg7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gZXJhc0FiYnJSZWdleChpc1N0cmljdCkge1xuICAgICAgICBpZiAoIWhhc093blByb3AodGhpcywgJ19lcmFzQWJiclJlZ2V4JykpIHtcbiAgICAgICAgICAgIGNvbXB1dGVFcmFzUGFyc2UuY2FsbCh0aGlzKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gaXNTdHJpY3QgPyB0aGlzLl9lcmFzQWJiclJlZ2V4IDogdGhpcy5fZXJhc1JlZ2V4O1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGVyYXNOYXJyb3dSZWdleChpc1N0cmljdCkge1xuICAgICAgICBpZiAoIWhhc093blByb3AodGhpcywgJ19lcmFzTmFycm93UmVnZXgnKSkge1xuICAgICAgICAgICAgY29tcHV0ZUVyYXNQYXJzZS5jYWxsKHRoaXMpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBpc1N0cmljdCA/IHRoaXMuX2VyYXNOYXJyb3dSZWdleCA6IHRoaXMuX2VyYXNSZWdleDtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBtYXRjaEVyYUFiYnIoaXNTdHJpY3QsIGxvY2FsZSkge1xuICAgICAgICByZXR1cm4gbG9jYWxlLmVyYXNBYmJyUmVnZXgoaXNTdHJpY3QpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIG1hdGNoRXJhTmFtZShpc1N0cmljdCwgbG9jYWxlKSB7XG4gICAgICAgIHJldHVybiBsb2NhbGUuZXJhc05hbWVSZWdleChpc1N0cmljdCk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gbWF0Y2hFcmFOYXJyb3coaXNTdHJpY3QsIGxvY2FsZSkge1xuICAgICAgICByZXR1cm4gbG9jYWxlLmVyYXNOYXJyb3dSZWdleChpc1N0cmljdCk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gbWF0Y2hFcmFZZWFyT3JkaW5hbChpc1N0cmljdCwgbG9jYWxlKSB7XG4gICAgICAgIHJldHVybiBsb2NhbGUuX2VyYVllYXJPcmRpbmFsUmVnZXggfHwgbWF0Y2hVbnNpZ25lZDtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBjb21wdXRlRXJhc1BhcnNlKCkge1xuICAgICAgICB2YXIgYWJiclBpZWNlcyA9IFtdLFxuICAgICAgICAgICAgbmFtZVBpZWNlcyA9IFtdLFxuICAgICAgICAgICAgbmFycm93UGllY2VzID0gW10sXG4gICAgICAgICAgICBtaXhlZFBpZWNlcyA9IFtdLFxuICAgICAgICAgICAgaSxcbiAgICAgICAgICAgIGwsXG4gICAgICAgICAgICBlcmFzID0gdGhpcy5lcmFzKCk7XG5cbiAgICAgICAgZm9yIChpID0gMCwgbCA9IGVyYXMubGVuZ3RoOyBpIDwgbDsgKytpKSB7XG4gICAgICAgICAgICBuYW1lUGllY2VzLnB1c2gocmVnZXhFc2NhcGUoZXJhc1tpXS5uYW1lKSk7XG4gICAgICAgICAgICBhYmJyUGllY2VzLnB1c2gocmVnZXhFc2NhcGUoZXJhc1tpXS5hYmJyKSk7XG4gICAgICAgICAgICBuYXJyb3dQaWVjZXMucHVzaChyZWdleEVzY2FwZShlcmFzW2ldLm5hcnJvdykpO1xuXG4gICAgICAgICAgICBtaXhlZFBpZWNlcy5wdXNoKHJlZ2V4RXNjYXBlKGVyYXNbaV0ubmFtZSkpO1xuICAgICAgICAgICAgbWl4ZWRQaWVjZXMucHVzaChyZWdleEVzY2FwZShlcmFzW2ldLmFiYnIpKTtcbiAgICAgICAgICAgIG1peGVkUGllY2VzLnB1c2gocmVnZXhFc2NhcGUoZXJhc1tpXS5uYXJyb3cpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuX2VyYXNSZWdleCA9IG5ldyBSZWdFeHAoJ14oJyArIG1peGVkUGllY2VzLmpvaW4oJ3wnKSArICcpJywgJ2knKTtcbiAgICAgICAgdGhpcy5fZXJhc05hbWVSZWdleCA9IG5ldyBSZWdFeHAoJ14oJyArIG5hbWVQaWVjZXMuam9pbignfCcpICsgJyknLCAnaScpO1xuICAgICAgICB0aGlzLl9lcmFzQWJiclJlZ2V4ID0gbmV3IFJlZ0V4cCgnXignICsgYWJiclBpZWNlcy5qb2luKCd8JykgKyAnKScsICdpJyk7XG4gICAgICAgIHRoaXMuX2VyYXNOYXJyb3dSZWdleCA9IG5ldyBSZWdFeHAoXG4gICAgICAgICAgICAnXignICsgbmFycm93UGllY2VzLmpvaW4oJ3wnKSArICcpJyxcbiAgICAgICAgICAgICdpJ1xuICAgICAgICApO1xuICAgIH1cblxuICAgIC8vIEZPUk1BVFRJTkdcblxuICAgIGFkZEZvcm1hdFRva2VuKDAsIFsnZ2cnLCAyXSwgMCwgZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy53ZWVrWWVhcigpICUgMTAwO1xuICAgIH0pO1xuXG4gICAgYWRkRm9ybWF0VG9rZW4oMCwgWydHRycsIDJdLCAwLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmlzb1dlZWtZZWFyKCkgJSAxMDA7XG4gICAgfSk7XG5cbiAgICBmdW5jdGlvbiBhZGRXZWVrWWVhckZvcm1hdFRva2VuKHRva2VuLCBnZXR0ZXIpIHtcbiAgICAgICAgYWRkRm9ybWF0VG9rZW4oMCwgW3Rva2VuLCB0b2tlbi5sZW5ndGhdLCAwLCBnZXR0ZXIpO1xuICAgIH1cblxuICAgIGFkZFdlZWtZZWFyRm9ybWF0VG9rZW4oJ2dnZ2cnLCAnd2Vla1llYXInKTtcbiAgICBhZGRXZWVrWWVhckZvcm1hdFRva2VuKCdnZ2dnZycsICd3ZWVrWWVhcicpO1xuICAgIGFkZFdlZWtZZWFyRm9ybWF0VG9rZW4oJ0dHR0cnLCAnaXNvV2Vla1llYXInKTtcbiAgICBhZGRXZWVrWWVhckZvcm1hdFRva2VuKCdHR0dHRycsICdpc29XZWVrWWVhcicpO1xuXG4gICAgLy8gQUxJQVNFU1xuXG4gICAgYWRkVW5pdEFsaWFzKCd3ZWVrWWVhcicsICdnZycpO1xuICAgIGFkZFVuaXRBbGlhcygnaXNvV2Vla1llYXInLCAnR0cnKTtcblxuICAgIC8vIFBSSU9SSVRZXG5cbiAgICBhZGRVbml0UHJpb3JpdHkoJ3dlZWtZZWFyJywgMSk7XG4gICAgYWRkVW5pdFByaW9yaXR5KCdpc29XZWVrWWVhcicsIDEpO1xuXG4gICAgLy8gUEFSU0lOR1xuXG4gICAgYWRkUmVnZXhUb2tlbignRycsIG1hdGNoU2lnbmVkKTtcbiAgICBhZGRSZWdleFRva2VuKCdnJywgbWF0Y2hTaWduZWQpO1xuICAgIGFkZFJlZ2V4VG9rZW4oJ0dHJywgbWF0Y2gxdG8yLCBtYXRjaDIpO1xuICAgIGFkZFJlZ2V4VG9rZW4oJ2dnJywgbWF0Y2gxdG8yLCBtYXRjaDIpO1xuICAgIGFkZFJlZ2V4VG9rZW4oJ0dHR0cnLCBtYXRjaDF0bzQsIG1hdGNoNCk7XG4gICAgYWRkUmVnZXhUb2tlbignZ2dnZycsIG1hdGNoMXRvNCwgbWF0Y2g0KTtcbiAgICBhZGRSZWdleFRva2VuKCdHR0dHRycsIG1hdGNoMXRvNiwgbWF0Y2g2KTtcbiAgICBhZGRSZWdleFRva2VuKCdnZ2dnZycsIG1hdGNoMXRvNiwgbWF0Y2g2KTtcblxuICAgIGFkZFdlZWtQYXJzZVRva2VuKFsnZ2dnZycsICdnZ2dnZycsICdHR0dHJywgJ0dHR0dHJ10sIGZ1bmN0aW9uIChcbiAgICAgICAgaW5wdXQsXG4gICAgICAgIHdlZWssXG4gICAgICAgIGNvbmZpZyxcbiAgICAgICAgdG9rZW5cbiAgICApIHtcbiAgICAgICAgd2Vla1t0b2tlbi5zdWJzdHIoMCwgMildID0gdG9JbnQoaW5wdXQpO1xuICAgIH0pO1xuXG4gICAgYWRkV2Vla1BhcnNlVG9rZW4oWydnZycsICdHRyddLCBmdW5jdGlvbiAoaW5wdXQsIHdlZWssIGNvbmZpZywgdG9rZW4pIHtcbiAgICAgICAgd2Vla1t0b2tlbl0gPSBob29rcy5wYXJzZVR3b0RpZ2l0WWVhcihpbnB1dCk7XG4gICAgfSk7XG5cbiAgICAvLyBNT01FTlRTXG5cbiAgICBmdW5jdGlvbiBnZXRTZXRXZWVrWWVhcihpbnB1dCkge1xuICAgICAgICByZXR1cm4gZ2V0U2V0V2Vla1llYXJIZWxwZXIuY2FsbChcbiAgICAgICAgICAgIHRoaXMsXG4gICAgICAgICAgICBpbnB1dCxcbiAgICAgICAgICAgIHRoaXMud2VlaygpLFxuICAgICAgICAgICAgdGhpcy53ZWVrZGF5KCksXG4gICAgICAgICAgICB0aGlzLmxvY2FsZURhdGEoKS5fd2Vlay5kb3csXG4gICAgICAgICAgICB0aGlzLmxvY2FsZURhdGEoKS5fd2Vlay5kb3lcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBnZXRTZXRJU09XZWVrWWVhcihpbnB1dCkge1xuICAgICAgICByZXR1cm4gZ2V0U2V0V2Vla1llYXJIZWxwZXIuY2FsbChcbiAgICAgICAgICAgIHRoaXMsXG4gICAgICAgICAgICBpbnB1dCxcbiAgICAgICAgICAgIHRoaXMuaXNvV2VlaygpLFxuICAgICAgICAgICAgdGhpcy5pc29XZWVrZGF5KCksXG4gICAgICAgICAgICAxLFxuICAgICAgICAgICAgNFxuICAgICAgICApO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGdldElTT1dlZWtzSW5ZZWFyKCkge1xuICAgICAgICByZXR1cm4gd2Vla3NJblllYXIodGhpcy55ZWFyKCksIDEsIDQpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGdldElTT1dlZWtzSW5JU09XZWVrWWVhcigpIHtcbiAgICAgICAgcmV0dXJuIHdlZWtzSW5ZZWFyKHRoaXMuaXNvV2Vla1llYXIoKSwgMSwgNCk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gZ2V0V2Vla3NJblllYXIoKSB7XG4gICAgICAgIHZhciB3ZWVrSW5mbyA9IHRoaXMubG9jYWxlRGF0YSgpLl93ZWVrO1xuICAgICAgICByZXR1cm4gd2Vla3NJblllYXIodGhpcy55ZWFyKCksIHdlZWtJbmZvLmRvdywgd2Vla0luZm8uZG95KTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBnZXRXZWVrc0luV2Vla1llYXIoKSB7XG4gICAgICAgIHZhciB3ZWVrSW5mbyA9IHRoaXMubG9jYWxlRGF0YSgpLl93ZWVrO1xuICAgICAgICByZXR1cm4gd2Vla3NJblllYXIodGhpcy53ZWVrWWVhcigpLCB3ZWVrSW5mby5kb3csIHdlZWtJbmZvLmRveSk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gZ2V0U2V0V2Vla1llYXJIZWxwZXIoaW5wdXQsIHdlZWssIHdlZWtkYXksIGRvdywgZG95KSB7XG4gICAgICAgIHZhciB3ZWVrc1RhcmdldDtcbiAgICAgICAgaWYgKGlucHV0ID09IG51bGwpIHtcbiAgICAgICAgICAgIHJldHVybiB3ZWVrT2ZZZWFyKHRoaXMsIGRvdywgZG95KS55ZWFyO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgd2Vla3NUYXJnZXQgPSB3ZWVrc0luWWVhcihpbnB1dCwgZG93LCBkb3kpO1xuICAgICAgICAgICAgaWYgKHdlZWsgPiB3ZWVrc1RhcmdldCkge1xuICAgICAgICAgICAgICAgIHdlZWsgPSB3ZWVrc1RhcmdldDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBzZXRXZWVrQWxsLmNhbGwodGhpcywgaW5wdXQsIHdlZWssIHdlZWtkYXksIGRvdywgZG95KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIHNldFdlZWtBbGwod2Vla1llYXIsIHdlZWssIHdlZWtkYXksIGRvdywgZG95KSB7XG4gICAgICAgIHZhciBkYXlPZlllYXJEYXRhID0gZGF5T2ZZZWFyRnJvbVdlZWtzKHdlZWtZZWFyLCB3ZWVrLCB3ZWVrZGF5LCBkb3csIGRveSksXG4gICAgICAgICAgICBkYXRlID0gY3JlYXRlVVRDRGF0ZShkYXlPZlllYXJEYXRhLnllYXIsIDAsIGRheU9mWWVhckRhdGEuZGF5T2ZZZWFyKTtcblxuICAgICAgICB0aGlzLnllYXIoZGF0ZS5nZXRVVENGdWxsWWVhcigpKTtcbiAgICAgICAgdGhpcy5tb250aChkYXRlLmdldFVUQ01vbnRoKCkpO1xuICAgICAgICB0aGlzLmRhdGUoZGF0ZS5nZXRVVENEYXRlKCkpO1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICAvLyBGT1JNQVRUSU5HXG5cbiAgICBhZGRGb3JtYXRUb2tlbignUScsIDAsICdRbycsICdxdWFydGVyJyk7XG5cbiAgICAvLyBBTElBU0VTXG5cbiAgICBhZGRVbml0QWxpYXMoJ3F1YXJ0ZXInLCAnUScpO1xuXG4gICAgLy8gUFJJT1JJVFlcblxuICAgIGFkZFVuaXRQcmlvcml0eSgncXVhcnRlcicsIDcpO1xuXG4gICAgLy8gUEFSU0lOR1xuXG4gICAgYWRkUmVnZXhUb2tlbignUScsIG1hdGNoMSk7XG4gICAgYWRkUGFyc2VUb2tlbignUScsIGZ1bmN0aW9uIChpbnB1dCwgYXJyYXkpIHtcbiAgICAgICAgYXJyYXlbTU9OVEhdID0gKHRvSW50KGlucHV0KSAtIDEpICogMztcbiAgICB9KTtcblxuICAgIC8vIE1PTUVOVFNcblxuICAgIGZ1bmN0aW9uIGdldFNldFF1YXJ0ZXIoaW5wdXQpIHtcbiAgICAgICAgcmV0dXJuIGlucHV0ID09IG51bGxcbiAgICAgICAgICAgID8gTWF0aC5jZWlsKCh0aGlzLm1vbnRoKCkgKyAxKSAvIDMpXG4gICAgICAgICAgICA6IHRoaXMubW9udGgoKGlucHV0IC0gMSkgKiAzICsgKHRoaXMubW9udGgoKSAlIDMpKTtcbiAgICB9XG5cbiAgICAvLyBGT1JNQVRUSU5HXG5cbiAgICBhZGRGb3JtYXRUb2tlbignRCcsIFsnREQnLCAyXSwgJ0RvJywgJ2RhdGUnKTtcblxuICAgIC8vIEFMSUFTRVNcblxuICAgIGFkZFVuaXRBbGlhcygnZGF0ZScsICdEJyk7XG5cbiAgICAvLyBQUklPUklUWVxuICAgIGFkZFVuaXRQcmlvcml0eSgnZGF0ZScsIDkpO1xuXG4gICAgLy8gUEFSU0lOR1xuXG4gICAgYWRkUmVnZXhUb2tlbignRCcsIG1hdGNoMXRvMik7XG4gICAgYWRkUmVnZXhUb2tlbignREQnLCBtYXRjaDF0bzIsIG1hdGNoMik7XG4gICAgYWRkUmVnZXhUb2tlbignRG8nLCBmdW5jdGlvbiAoaXNTdHJpY3QsIGxvY2FsZSkge1xuICAgICAgICAvLyBUT0RPOiBSZW1vdmUgXCJvcmRpbmFsUGFyc2VcIiBmYWxsYmFjayBpbiBuZXh0IG1ham9yIHJlbGVhc2UuXG4gICAgICAgIHJldHVybiBpc1N0cmljdFxuICAgICAgICAgICAgPyBsb2NhbGUuX2RheU9mTW9udGhPcmRpbmFsUGFyc2UgfHwgbG9jYWxlLl9vcmRpbmFsUGFyc2VcbiAgICAgICAgICAgIDogbG9jYWxlLl9kYXlPZk1vbnRoT3JkaW5hbFBhcnNlTGVuaWVudDtcbiAgICB9KTtcblxuICAgIGFkZFBhcnNlVG9rZW4oWydEJywgJ0REJ10sIERBVEUpO1xuICAgIGFkZFBhcnNlVG9rZW4oJ0RvJywgZnVuY3Rpb24gKGlucHV0LCBhcnJheSkge1xuICAgICAgICBhcnJheVtEQVRFXSA9IHRvSW50KGlucHV0Lm1hdGNoKG1hdGNoMXRvMilbMF0pO1xuICAgIH0pO1xuXG4gICAgLy8gTU9NRU5UU1xuXG4gICAgdmFyIGdldFNldERheU9mTW9udGggPSBtYWtlR2V0U2V0KCdEYXRlJywgdHJ1ZSk7XG5cbiAgICAvLyBGT1JNQVRUSU5HXG5cbiAgICBhZGRGb3JtYXRUb2tlbignREREJywgWydEREREJywgM10sICdERERvJywgJ2RheU9mWWVhcicpO1xuXG4gICAgLy8gQUxJQVNFU1xuXG4gICAgYWRkVW5pdEFsaWFzKCdkYXlPZlllYXInLCAnREREJyk7XG5cbiAgICAvLyBQUklPUklUWVxuICAgIGFkZFVuaXRQcmlvcml0eSgnZGF5T2ZZZWFyJywgNCk7XG5cbiAgICAvLyBQQVJTSU5HXG5cbiAgICBhZGRSZWdleFRva2VuKCdEREQnLCBtYXRjaDF0bzMpO1xuICAgIGFkZFJlZ2V4VG9rZW4oJ0REREQnLCBtYXRjaDMpO1xuICAgIGFkZFBhcnNlVG9rZW4oWydEREQnLCAnRERERCddLCBmdW5jdGlvbiAoaW5wdXQsIGFycmF5LCBjb25maWcpIHtcbiAgICAgICAgY29uZmlnLl9kYXlPZlllYXIgPSB0b0ludChpbnB1dCk7XG4gICAgfSk7XG5cbiAgICAvLyBIRUxQRVJTXG5cbiAgICAvLyBNT01FTlRTXG5cbiAgICBmdW5jdGlvbiBnZXRTZXREYXlPZlllYXIoaW5wdXQpIHtcbiAgICAgICAgdmFyIGRheU9mWWVhciA9XG4gICAgICAgICAgICBNYXRoLnJvdW5kKFxuICAgICAgICAgICAgICAgICh0aGlzLmNsb25lKCkuc3RhcnRPZignZGF5JykgLSB0aGlzLmNsb25lKCkuc3RhcnRPZigneWVhcicpKSAvIDg2NGU1XG4gICAgICAgICAgICApICsgMTtcbiAgICAgICAgcmV0dXJuIGlucHV0ID09IG51bGwgPyBkYXlPZlllYXIgOiB0aGlzLmFkZChpbnB1dCAtIGRheU9mWWVhciwgJ2QnKTtcbiAgICB9XG5cbiAgICAvLyBGT1JNQVRUSU5HXG5cbiAgICBhZGRGb3JtYXRUb2tlbignbScsIFsnbW0nLCAyXSwgMCwgJ21pbnV0ZScpO1xuXG4gICAgLy8gQUxJQVNFU1xuXG4gICAgYWRkVW5pdEFsaWFzKCdtaW51dGUnLCAnbScpO1xuXG4gICAgLy8gUFJJT1JJVFlcblxuICAgIGFkZFVuaXRQcmlvcml0eSgnbWludXRlJywgMTQpO1xuXG4gICAgLy8gUEFSU0lOR1xuXG4gICAgYWRkUmVnZXhUb2tlbignbScsIG1hdGNoMXRvMik7XG4gICAgYWRkUmVnZXhUb2tlbignbW0nLCBtYXRjaDF0bzIsIG1hdGNoMik7XG4gICAgYWRkUGFyc2VUb2tlbihbJ20nLCAnbW0nXSwgTUlOVVRFKTtcblxuICAgIC8vIE1PTUVOVFNcblxuICAgIHZhciBnZXRTZXRNaW51dGUgPSBtYWtlR2V0U2V0KCdNaW51dGVzJywgZmFsc2UpO1xuXG4gICAgLy8gRk9STUFUVElOR1xuXG4gICAgYWRkRm9ybWF0VG9rZW4oJ3MnLCBbJ3NzJywgMl0sIDAsICdzZWNvbmQnKTtcblxuICAgIC8vIEFMSUFTRVNcblxuICAgIGFkZFVuaXRBbGlhcygnc2Vjb25kJywgJ3MnKTtcblxuICAgIC8vIFBSSU9SSVRZXG5cbiAgICBhZGRVbml0UHJpb3JpdHkoJ3NlY29uZCcsIDE1KTtcblxuICAgIC8vIFBBUlNJTkdcblxuICAgIGFkZFJlZ2V4VG9rZW4oJ3MnLCBtYXRjaDF0bzIpO1xuICAgIGFkZFJlZ2V4VG9rZW4oJ3NzJywgbWF0Y2gxdG8yLCBtYXRjaDIpO1xuICAgIGFkZFBhcnNlVG9rZW4oWydzJywgJ3NzJ10sIFNFQ09ORCk7XG5cbiAgICAvLyBNT01FTlRTXG5cbiAgICB2YXIgZ2V0U2V0U2Vjb25kID0gbWFrZUdldFNldCgnU2Vjb25kcycsIGZhbHNlKTtcblxuICAgIC8vIEZPUk1BVFRJTkdcblxuICAgIGFkZEZvcm1hdFRva2VuKCdTJywgMCwgMCwgZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gfn4odGhpcy5taWxsaXNlY29uZCgpIC8gMTAwKTtcbiAgICB9KTtcblxuICAgIGFkZEZvcm1hdFRva2VuKDAsIFsnU1MnLCAyXSwgMCwgZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gfn4odGhpcy5taWxsaXNlY29uZCgpIC8gMTApO1xuICAgIH0pO1xuXG4gICAgYWRkRm9ybWF0VG9rZW4oMCwgWydTU1MnLCAzXSwgMCwgJ21pbGxpc2Vjb25kJyk7XG4gICAgYWRkRm9ybWF0VG9rZW4oMCwgWydTU1NTJywgNF0sIDAsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubWlsbGlzZWNvbmQoKSAqIDEwO1xuICAgIH0pO1xuICAgIGFkZEZvcm1hdFRva2VuKDAsIFsnU1NTU1MnLCA1XSwgMCwgZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5taWxsaXNlY29uZCgpICogMTAwO1xuICAgIH0pO1xuICAgIGFkZEZvcm1hdFRva2VuKDAsIFsnU1NTU1NTJywgNl0sIDAsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubWlsbGlzZWNvbmQoKSAqIDEwMDA7XG4gICAgfSk7XG4gICAgYWRkRm9ybWF0VG9rZW4oMCwgWydTU1NTU1NTJywgN10sIDAsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubWlsbGlzZWNvbmQoKSAqIDEwMDAwO1xuICAgIH0pO1xuICAgIGFkZEZvcm1hdFRva2VuKDAsIFsnU1NTU1NTU1MnLCA4XSwgMCwgZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5taWxsaXNlY29uZCgpICogMTAwMDAwO1xuICAgIH0pO1xuICAgIGFkZEZvcm1hdFRva2VuKDAsIFsnU1NTU1NTU1NTJywgOV0sIDAsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubWlsbGlzZWNvbmQoKSAqIDEwMDAwMDA7XG4gICAgfSk7XG5cbiAgICAvLyBBTElBU0VTXG5cbiAgICBhZGRVbml0QWxpYXMoJ21pbGxpc2Vjb25kJywgJ21zJyk7XG5cbiAgICAvLyBQUklPUklUWVxuXG4gICAgYWRkVW5pdFByaW9yaXR5KCdtaWxsaXNlY29uZCcsIDE2KTtcblxuICAgIC8vIFBBUlNJTkdcblxuICAgIGFkZFJlZ2V4VG9rZW4oJ1MnLCBtYXRjaDF0bzMsIG1hdGNoMSk7XG4gICAgYWRkUmVnZXhUb2tlbignU1MnLCBtYXRjaDF0bzMsIG1hdGNoMik7XG4gICAgYWRkUmVnZXhUb2tlbignU1NTJywgbWF0Y2gxdG8zLCBtYXRjaDMpO1xuXG4gICAgdmFyIHRva2VuLCBnZXRTZXRNaWxsaXNlY29uZDtcbiAgICBmb3IgKHRva2VuID0gJ1NTU1MnOyB0b2tlbi5sZW5ndGggPD0gOTsgdG9rZW4gKz0gJ1MnKSB7XG4gICAgICAgIGFkZFJlZ2V4VG9rZW4odG9rZW4sIG1hdGNoVW5zaWduZWQpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHBhcnNlTXMoaW5wdXQsIGFycmF5KSB7XG4gICAgICAgIGFycmF5W01JTExJU0VDT05EXSA9IHRvSW50KCgnMC4nICsgaW5wdXQpICogMTAwMCk7XG4gICAgfVxuXG4gICAgZm9yICh0b2tlbiA9ICdTJzsgdG9rZW4ubGVuZ3RoIDw9IDk7IHRva2VuICs9ICdTJykge1xuICAgICAgICBhZGRQYXJzZVRva2VuKHRva2VuLCBwYXJzZU1zKTtcbiAgICB9XG5cbiAgICBnZXRTZXRNaWxsaXNlY29uZCA9IG1ha2VHZXRTZXQoJ01pbGxpc2Vjb25kcycsIGZhbHNlKTtcblxuICAgIC8vIEZPUk1BVFRJTkdcblxuICAgIGFkZEZvcm1hdFRva2VuKCd6JywgMCwgMCwgJ3pvbmVBYmJyJyk7XG4gICAgYWRkRm9ybWF0VG9rZW4oJ3p6JywgMCwgMCwgJ3pvbmVOYW1lJyk7XG5cbiAgICAvLyBNT01FTlRTXG5cbiAgICBmdW5jdGlvbiBnZXRab25lQWJicigpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2lzVVRDID8gJ1VUQycgOiAnJztcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBnZXRab25lTmFtZSgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2lzVVRDID8gJ0Nvb3JkaW5hdGVkIFVuaXZlcnNhbCBUaW1lJyA6ICcnO1xuICAgIH1cblxuICAgIHZhciBwcm90byA9IE1vbWVudC5wcm90b3R5cGU7XG5cbiAgICBwcm90by5hZGQgPSBhZGQ7XG4gICAgcHJvdG8uY2FsZW5kYXIgPSBjYWxlbmRhciQxO1xuICAgIHByb3RvLmNsb25lID0gY2xvbmU7XG4gICAgcHJvdG8uZGlmZiA9IGRpZmY7XG4gICAgcHJvdG8uZW5kT2YgPSBlbmRPZjtcbiAgICBwcm90by5mb3JtYXQgPSBmb3JtYXQ7XG4gICAgcHJvdG8uZnJvbSA9IGZyb207XG4gICAgcHJvdG8uZnJvbU5vdyA9IGZyb21Ob3c7XG4gICAgcHJvdG8udG8gPSB0bztcbiAgICBwcm90by50b05vdyA9IHRvTm93O1xuICAgIHByb3RvLmdldCA9IHN0cmluZ0dldDtcbiAgICBwcm90by5pbnZhbGlkQXQgPSBpbnZhbGlkQXQ7XG4gICAgcHJvdG8uaXNBZnRlciA9IGlzQWZ0ZXI7XG4gICAgcHJvdG8uaXNCZWZvcmUgPSBpc0JlZm9yZTtcbiAgICBwcm90by5pc0JldHdlZW4gPSBpc0JldHdlZW47XG4gICAgcHJvdG8uaXNTYW1lID0gaXNTYW1lO1xuICAgIHByb3RvLmlzU2FtZU9yQWZ0ZXIgPSBpc1NhbWVPckFmdGVyO1xuICAgIHByb3RvLmlzU2FtZU9yQmVmb3JlID0gaXNTYW1lT3JCZWZvcmU7XG4gICAgcHJvdG8uaXNWYWxpZCA9IGlzVmFsaWQkMjtcbiAgICBwcm90by5sYW5nID0gbGFuZztcbiAgICBwcm90by5sb2NhbGUgPSBsb2NhbGU7XG4gICAgcHJvdG8ubG9jYWxlRGF0YSA9IGxvY2FsZURhdGE7XG4gICAgcHJvdG8ubWF4ID0gcHJvdG90eXBlTWF4O1xuICAgIHByb3RvLm1pbiA9IHByb3RvdHlwZU1pbjtcbiAgICBwcm90by5wYXJzaW5nRmxhZ3MgPSBwYXJzaW5nRmxhZ3M7XG4gICAgcHJvdG8uc2V0ID0gc3RyaW5nU2V0O1xuICAgIHByb3RvLnN0YXJ0T2YgPSBzdGFydE9mO1xuICAgIHByb3RvLnN1YnRyYWN0ID0gc3VidHJhY3Q7XG4gICAgcHJvdG8udG9BcnJheSA9IHRvQXJyYXk7XG4gICAgcHJvdG8udG9PYmplY3QgPSB0b09iamVjdDtcbiAgICBwcm90by50b0RhdGUgPSB0b0RhdGU7XG4gICAgcHJvdG8udG9JU09TdHJpbmcgPSB0b0lTT1N0cmluZztcbiAgICBwcm90by5pbnNwZWN0ID0gaW5zcGVjdDtcbiAgICBpZiAodHlwZW9mIFN5bWJvbCAhPT0gJ3VuZGVmaW5lZCcgJiYgU3ltYm9sLmZvciAhPSBudWxsKSB7XG4gICAgICAgIHByb3RvW1N5bWJvbC5mb3IoJ25vZGVqcy51dGlsLmluc3BlY3QuY3VzdG9tJyldID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuICdNb21lbnQ8JyArIHRoaXMuZm9ybWF0KCkgKyAnPic7XG4gICAgICAgIH07XG4gICAgfVxuICAgIHByb3RvLnRvSlNPTiA9IHRvSlNPTjtcbiAgICBwcm90by50b1N0cmluZyA9IHRvU3RyaW5nO1xuICAgIHByb3RvLnVuaXggPSB1bml4O1xuICAgIHByb3RvLnZhbHVlT2YgPSB2YWx1ZU9mO1xuICAgIHByb3RvLmNyZWF0aW9uRGF0YSA9IGNyZWF0aW9uRGF0YTtcbiAgICBwcm90by5lcmFOYW1lID0gZ2V0RXJhTmFtZTtcbiAgICBwcm90by5lcmFOYXJyb3cgPSBnZXRFcmFOYXJyb3c7XG4gICAgcHJvdG8uZXJhQWJiciA9IGdldEVyYUFiYnI7XG4gICAgcHJvdG8uZXJhWWVhciA9IGdldEVyYVllYXI7XG4gICAgcHJvdG8ueWVhciA9IGdldFNldFllYXI7XG4gICAgcHJvdG8uaXNMZWFwWWVhciA9IGdldElzTGVhcFllYXI7XG4gICAgcHJvdG8ud2Vla1llYXIgPSBnZXRTZXRXZWVrWWVhcjtcbiAgICBwcm90by5pc29XZWVrWWVhciA9IGdldFNldElTT1dlZWtZZWFyO1xuICAgIHByb3RvLnF1YXJ0ZXIgPSBwcm90by5xdWFydGVycyA9IGdldFNldFF1YXJ0ZXI7XG4gICAgcHJvdG8ubW9udGggPSBnZXRTZXRNb250aDtcbiAgICBwcm90by5kYXlzSW5Nb250aCA9IGdldERheXNJbk1vbnRoO1xuICAgIHByb3RvLndlZWsgPSBwcm90by53ZWVrcyA9IGdldFNldFdlZWs7XG4gICAgcHJvdG8uaXNvV2VlayA9IHByb3RvLmlzb1dlZWtzID0gZ2V0U2V0SVNPV2VlaztcbiAgICBwcm90by53ZWVrc0luWWVhciA9IGdldFdlZWtzSW5ZZWFyO1xuICAgIHByb3RvLndlZWtzSW5XZWVrWWVhciA9IGdldFdlZWtzSW5XZWVrWWVhcjtcbiAgICBwcm90by5pc29XZWVrc0luWWVhciA9IGdldElTT1dlZWtzSW5ZZWFyO1xuICAgIHByb3RvLmlzb1dlZWtzSW5JU09XZWVrWWVhciA9IGdldElTT1dlZWtzSW5JU09XZWVrWWVhcjtcbiAgICBwcm90by5kYXRlID0gZ2V0U2V0RGF5T2ZNb250aDtcbiAgICBwcm90by5kYXkgPSBwcm90by5kYXlzID0gZ2V0U2V0RGF5T2ZXZWVrO1xuICAgIHByb3RvLndlZWtkYXkgPSBnZXRTZXRMb2NhbGVEYXlPZldlZWs7XG4gICAgcHJvdG8uaXNvV2Vla2RheSA9IGdldFNldElTT0RheU9mV2VlaztcbiAgICBwcm90by5kYXlPZlllYXIgPSBnZXRTZXREYXlPZlllYXI7XG4gICAgcHJvdG8uaG91ciA9IHByb3RvLmhvdXJzID0gZ2V0U2V0SG91cjtcbiAgICBwcm90by5taW51dGUgPSBwcm90by5taW51dGVzID0gZ2V0U2V0TWludXRlO1xuICAgIHByb3RvLnNlY29uZCA9IHByb3RvLnNlY29uZHMgPSBnZXRTZXRTZWNvbmQ7XG4gICAgcHJvdG8ubWlsbGlzZWNvbmQgPSBwcm90by5taWxsaXNlY29uZHMgPSBnZXRTZXRNaWxsaXNlY29uZDtcbiAgICBwcm90by51dGNPZmZzZXQgPSBnZXRTZXRPZmZzZXQ7XG4gICAgcHJvdG8udXRjID0gc2V0T2Zmc2V0VG9VVEM7XG4gICAgcHJvdG8ubG9jYWwgPSBzZXRPZmZzZXRUb0xvY2FsO1xuICAgIHByb3RvLnBhcnNlWm9uZSA9IHNldE9mZnNldFRvUGFyc2VkT2Zmc2V0O1xuICAgIHByb3RvLmhhc0FsaWduZWRIb3VyT2Zmc2V0ID0gaGFzQWxpZ25lZEhvdXJPZmZzZXQ7XG4gICAgcHJvdG8uaXNEU1QgPSBpc0RheWxpZ2h0U2F2aW5nVGltZTtcbiAgICBwcm90by5pc0xvY2FsID0gaXNMb2NhbDtcbiAgICBwcm90by5pc1V0Y09mZnNldCA9IGlzVXRjT2Zmc2V0O1xuICAgIHByb3RvLmlzVXRjID0gaXNVdGM7XG4gICAgcHJvdG8uaXNVVEMgPSBpc1V0YztcbiAgICBwcm90by56b25lQWJiciA9IGdldFpvbmVBYmJyO1xuICAgIHByb3RvLnpvbmVOYW1lID0gZ2V0Wm9uZU5hbWU7XG4gICAgcHJvdG8uZGF0ZXMgPSBkZXByZWNhdGUoXG4gICAgICAgICdkYXRlcyBhY2Nlc3NvciBpcyBkZXByZWNhdGVkLiBVc2UgZGF0ZSBpbnN0ZWFkLicsXG4gICAgICAgIGdldFNldERheU9mTW9udGhcbiAgICApO1xuICAgIHByb3RvLm1vbnRocyA9IGRlcHJlY2F0ZShcbiAgICAgICAgJ21vbnRocyBhY2Nlc3NvciBpcyBkZXByZWNhdGVkLiBVc2UgbW9udGggaW5zdGVhZCcsXG4gICAgICAgIGdldFNldE1vbnRoXG4gICAgKTtcbiAgICBwcm90by55ZWFycyA9IGRlcHJlY2F0ZShcbiAgICAgICAgJ3llYXJzIGFjY2Vzc29yIGlzIGRlcHJlY2F0ZWQuIFVzZSB5ZWFyIGluc3RlYWQnLFxuICAgICAgICBnZXRTZXRZZWFyXG4gICAgKTtcbiAgICBwcm90by56b25lID0gZGVwcmVjYXRlKFxuICAgICAgICAnbW9tZW50KCkuem9uZSBpcyBkZXByZWNhdGVkLCB1c2UgbW9tZW50KCkudXRjT2Zmc2V0IGluc3RlYWQuIGh0dHA6Ly9tb21lbnRqcy5jb20vZ3VpZGVzLyMvd2FybmluZ3Mvem9uZS8nLFxuICAgICAgICBnZXRTZXRab25lXG4gICAgKTtcbiAgICBwcm90by5pc0RTVFNoaWZ0ZWQgPSBkZXByZWNhdGUoXG4gICAgICAgICdpc0RTVFNoaWZ0ZWQgaXMgZGVwcmVjYXRlZC4gU2VlIGh0dHA6Ly9tb21lbnRqcy5jb20vZ3VpZGVzLyMvd2FybmluZ3MvZHN0LXNoaWZ0ZWQvIGZvciBtb3JlIGluZm9ybWF0aW9uJyxcbiAgICAgICAgaXNEYXlsaWdodFNhdmluZ1RpbWVTaGlmdGVkXG4gICAgKTtcblxuICAgIGZ1bmN0aW9uIGNyZWF0ZVVuaXgoaW5wdXQpIHtcbiAgICAgICAgcmV0dXJuIGNyZWF0ZUxvY2FsKGlucHV0ICogMTAwMCk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gY3JlYXRlSW5ab25lKCkge1xuICAgICAgICByZXR1cm4gY3JlYXRlTG9jYWwuYXBwbHkobnVsbCwgYXJndW1lbnRzKS5wYXJzZVpvbmUoKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBwcmVQYXJzZVBvc3RGb3JtYXQoc3RyaW5nKSB7XG4gICAgICAgIHJldHVybiBzdHJpbmc7XG4gICAgfVxuXG4gICAgdmFyIHByb3RvJDEgPSBMb2NhbGUucHJvdG90eXBlO1xuXG4gICAgcHJvdG8kMS5jYWxlbmRhciA9IGNhbGVuZGFyO1xuICAgIHByb3RvJDEubG9uZ0RhdGVGb3JtYXQgPSBsb25nRGF0ZUZvcm1hdDtcbiAgICBwcm90byQxLmludmFsaWREYXRlID0gaW52YWxpZERhdGU7XG4gICAgcHJvdG8kMS5vcmRpbmFsID0gb3JkaW5hbDtcbiAgICBwcm90byQxLnByZXBhcnNlID0gcHJlUGFyc2VQb3N0Rm9ybWF0O1xuICAgIHByb3RvJDEucG9zdGZvcm1hdCA9IHByZVBhcnNlUG9zdEZvcm1hdDtcbiAgICBwcm90byQxLnJlbGF0aXZlVGltZSA9IHJlbGF0aXZlVGltZTtcbiAgICBwcm90byQxLnBhc3RGdXR1cmUgPSBwYXN0RnV0dXJlO1xuICAgIHByb3RvJDEuc2V0ID0gc2V0O1xuICAgIHByb3RvJDEuZXJhcyA9IGxvY2FsZUVyYXM7XG4gICAgcHJvdG8kMS5lcmFzUGFyc2UgPSBsb2NhbGVFcmFzUGFyc2U7XG4gICAgcHJvdG8kMS5lcmFzQ29udmVydFllYXIgPSBsb2NhbGVFcmFzQ29udmVydFllYXI7XG4gICAgcHJvdG8kMS5lcmFzQWJiclJlZ2V4ID0gZXJhc0FiYnJSZWdleDtcbiAgICBwcm90byQxLmVyYXNOYW1lUmVnZXggPSBlcmFzTmFtZVJlZ2V4O1xuICAgIHByb3RvJDEuZXJhc05hcnJvd1JlZ2V4ID0gZXJhc05hcnJvd1JlZ2V4O1xuXG4gICAgcHJvdG8kMS5tb250aHMgPSBsb2NhbGVNb250aHM7XG4gICAgcHJvdG8kMS5tb250aHNTaG9ydCA9IGxvY2FsZU1vbnRoc1Nob3J0O1xuICAgIHByb3RvJDEubW9udGhzUGFyc2UgPSBsb2NhbGVNb250aHNQYXJzZTtcbiAgICBwcm90byQxLm1vbnRoc1JlZ2V4ID0gbW9udGhzUmVnZXg7XG4gICAgcHJvdG8kMS5tb250aHNTaG9ydFJlZ2V4ID0gbW9udGhzU2hvcnRSZWdleDtcbiAgICBwcm90byQxLndlZWsgPSBsb2NhbGVXZWVrO1xuICAgIHByb3RvJDEuZmlyc3REYXlPZlllYXIgPSBsb2NhbGVGaXJzdERheU9mWWVhcjtcbiAgICBwcm90byQxLmZpcnN0RGF5T2ZXZWVrID0gbG9jYWxlRmlyc3REYXlPZldlZWs7XG5cbiAgICBwcm90byQxLndlZWtkYXlzID0gbG9jYWxlV2Vla2RheXM7XG4gICAgcHJvdG8kMS53ZWVrZGF5c01pbiA9IGxvY2FsZVdlZWtkYXlzTWluO1xuICAgIHByb3RvJDEud2Vla2RheXNTaG9ydCA9IGxvY2FsZVdlZWtkYXlzU2hvcnQ7XG4gICAgcHJvdG8kMS53ZWVrZGF5c1BhcnNlID0gbG9jYWxlV2Vla2RheXNQYXJzZTtcblxuICAgIHByb3RvJDEud2Vla2RheXNSZWdleCA9IHdlZWtkYXlzUmVnZXg7XG4gICAgcHJvdG8kMS53ZWVrZGF5c1Nob3J0UmVnZXggPSB3ZWVrZGF5c1Nob3J0UmVnZXg7XG4gICAgcHJvdG8kMS53ZWVrZGF5c01pblJlZ2V4ID0gd2Vla2RheXNNaW5SZWdleDtcblxuICAgIHByb3RvJDEuaXNQTSA9IGxvY2FsZUlzUE07XG4gICAgcHJvdG8kMS5tZXJpZGllbSA9IGxvY2FsZU1lcmlkaWVtO1xuXG4gICAgZnVuY3Rpb24gZ2V0JDEoZm9ybWF0LCBpbmRleCwgZmllbGQsIHNldHRlcikge1xuICAgICAgICB2YXIgbG9jYWxlID0gZ2V0TG9jYWxlKCksXG4gICAgICAgICAgICB1dGMgPSBjcmVhdGVVVEMoKS5zZXQoc2V0dGVyLCBpbmRleCk7XG4gICAgICAgIHJldHVybiBsb2NhbGVbZmllbGRdKHV0YywgZm9ybWF0KTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBsaXN0TW9udGhzSW1wbChmb3JtYXQsIGluZGV4LCBmaWVsZCkge1xuICAgICAgICBpZiAoaXNOdW1iZXIoZm9ybWF0KSkge1xuICAgICAgICAgICAgaW5kZXggPSBmb3JtYXQ7XG4gICAgICAgICAgICBmb3JtYXQgPSB1bmRlZmluZWQ7XG4gICAgICAgIH1cblxuICAgICAgICBmb3JtYXQgPSBmb3JtYXQgfHwgJyc7XG5cbiAgICAgICAgaWYgKGluZGV4ICE9IG51bGwpIHtcbiAgICAgICAgICAgIHJldHVybiBnZXQkMShmb3JtYXQsIGluZGV4LCBmaWVsZCwgJ21vbnRoJyk7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgaSxcbiAgICAgICAgICAgIG91dCA9IFtdO1xuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgMTI7IGkrKykge1xuICAgICAgICAgICAgb3V0W2ldID0gZ2V0JDEoZm9ybWF0LCBpLCBmaWVsZCwgJ21vbnRoJyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG91dDtcbiAgICB9XG5cbiAgICAvLyAoKVxuICAgIC8vICg1KVxuICAgIC8vIChmbXQsIDUpXG4gICAgLy8gKGZtdClcbiAgICAvLyAodHJ1ZSlcbiAgICAvLyAodHJ1ZSwgNSlcbiAgICAvLyAodHJ1ZSwgZm10LCA1KVxuICAgIC8vICh0cnVlLCBmbXQpXG4gICAgZnVuY3Rpb24gbGlzdFdlZWtkYXlzSW1wbChsb2NhbGVTb3J0ZWQsIGZvcm1hdCwgaW5kZXgsIGZpZWxkKSB7XG4gICAgICAgIGlmICh0eXBlb2YgbG9jYWxlU29ydGVkID09PSAnYm9vbGVhbicpIHtcbiAgICAgICAgICAgIGlmIChpc051bWJlcihmb3JtYXQpKSB7XG4gICAgICAgICAgICAgICAgaW5kZXggPSBmb3JtYXQ7XG4gICAgICAgICAgICAgICAgZm9ybWF0ID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBmb3JtYXQgPSBmb3JtYXQgfHwgJyc7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBmb3JtYXQgPSBsb2NhbGVTb3J0ZWQ7XG4gICAgICAgICAgICBpbmRleCA9IGZvcm1hdDtcbiAgICAgICAgICAgIGxvY2FsZVNvcnRlZCA9IGZhbHNlO1xuXG4gICAgICAgICAgICBpZiAoaXNOdW1iZXIoZm9ybWF0KSkge1xuICAgICAgICAgICAgICAgIGluZGV4ID0gZm9ybWF0O1xuICAgICAgICAgICAgICAgIGZvcm1hdCA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgZm9ybWF0ID0gZm9ybWF0IHx8ICcnO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGxvY2FsZSA9IGdldExvY2FsZSgpLFxuICAgICAgICAgICAgc2hpZnQgPSBsb2NhbGVTb3J0ZWQgPyBsb2NhbGUuX3dlZWsuZG93IDogMCxcbiAgICAgICAgICAgIGksXG4gICAgICAgICAgICBvdXQgPSBbXTtcblxuICAgICAgICBpZiAoaW5kZXggIT0gbnVsbCkge1xuICAgICAgICAgICAgcmV0dXJuIGdldCQxKGZvcm1hdCwgKGluZGV4ICsgc2hpZnQpICUgNywgZmllbGQsICdkYXknKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCA3OyBpKyspIHtcbiAgICAgICAgICAgIG91dFtpXSA9IGdldCQxKGZvcm1hdCwgKGkgKyBzaGlmdCkgJSA3LCBmaWVsZCwgJ2RheScpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBvdXQ7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gbGlzdE1vbnRocyhmb3JtYXQsIGluZGV4KSB7XG4gICAgICAgIHJldHVybiBsaXN0TW9udGhzSW1wbChmb3JtYXQsIGluZGV4LCAnbW9udGhzJyk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gbGlzdE1vbnRoc1Nob3J0KGZvcm1hdCwgaW5kZXgpIHtcbiAgICAgICAgcmV0dXJuIGxpc3RNb250aHNJbXBsKGZvcm1hdCwgaW5kZXgsICdtb250aHNTaG9ydCcpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGxpc3RXZWVrZGF5cyhsb2NhbGVTb3J0ZWQsIGZvcm1hdCwgaW5kZXgpIHtcbiAgICAgICAgcmV0dXJuIGxpc3RXZWVrZGF5c0ltcGwobG9jYWxlU29ydGVkLCBmb3JtYXQsIGluZGV4LCAnd2Vla2RheXMnKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBsaXN0V2Vla2RheXNTaG9ydChsb2NhbGVTb3J0ZWQsIGZvcm1hdCwgaW5kZXgpIHtcbiAgICAgICAgcmV0dXJuIGxpc3RXZWVrZGF5c0ltcGwobG9jYWxlU29ydGVkLCBmb3JtYXQsIGluZGV4LCAnd2Vla2RheXNTaG9ydCcpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGxpc3RXZWVrZGF5c01pbihsb2NhbGVTb3J0ZWQsIGZvcm1hdCwgaW5kZXgpIHtcbiAgICAgICAgcmV0dXJuIGxpc3RXZWVrZGF5c0ltcGwobG9jYWxlU29ydGVkLCBmb3JtYXQsIGluZGV4LCAnd2Vla2RheXNNaW4nKTtcbiAgICB9XG5cbiAgICBnZXRTZXRHbG9iYWxMb2NhbGUoJ2VuJywge1xuICAgICAgICBlcmFzOiBbXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgc2luY2U6ICcwMDAxLTAxLTAxJyxcbiAgICAgICAgICAgICAgICB1bnRpbDogK0luZmluaXR5LFxuICAgICAgICAgICAgICAgIG9mZnNldDogMSxcbiAgICAgICAgICAgICAgICBuYW1lOiAnQW5ubyBEb21pbmknLFxuICAgICAgICAgICAgICAgIG5hcnJvdzogJ0FEJyxcbiAgICAgICAgICAgICAgICBhYmJyOiAnQUQnLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBzaW5jZTogJzAwMDAtMTItMzEnLFxuICAgICAgICAgICAgICAgIHVudGlsOiAtSW5maW5pdHksXG4gICAgICAgICAgICAgICAgb2Zmc2V0OiAxLFxuICAgICAgICAgICAgICAgIG5hbWU6ICdCZWZvcmUgQ2hyaXN0JyxcbiAgICAgICAgICAgICAgICBuYXJyb3c6ICdCQycsXG4gICAgICAgICAgICAgICAgYWJicjogJ0JDJyxcbiAgICAgICAgICAgIH0sXG4gICAgICAgIF0sXG4gICAgICAgIGRheU9mTW9udGhPcmRpbmFsUGFyc2U6IC9cXGR7MSwyfSh0aHxzdHxuZHxyZCkvLFxuICAgICAgICBvcmRpbmFsOiBmdW5jdGlvbiAobnVtYmVyKSB7XG4gICAgICAgICAgICB2YXIgYiA9IG51bWJlciAlIDEwLFxuICAgICAgICAgICAgICAgIG91dHB1dCA9XG4gICAgICAgICAgICAgICAgICAgIHRvSW50KChudW1iZXIgJSAxMDApIC8gMTApID09PSAxXG4gICAgICAgICAgICAgICAgICAgICAgICA/ICd0aCdcbiAgICAgICAgICAgICAgICAgICAgICAgIDogYiA9PT0gMVxuICAgICAgICAgICAgICAgICAgICAgICAgPyAnc3QnXG4gICAgICAgICAgICAgICAgICAgICAgICA6IGIgPT09IDJcbiAgICAgICAgICAgICAgICAgICAgICAgID8gJ25kJ1xuICAgICAgICAgICAgICAgICAgICAgICAgOiBiID09PSAzXG4gICAgICAgICAgICAgICAgICAgICAgICA/ICdyZCdcbiAgICAgICAgICAgICAgICAgICAgICAgIDogJ3RoJztcbiAgICAgICAgICAgIHJldHVybiBudW1iZXIgKyBvdXRwdXQ7XG4gICAgICAgIH0sXG4gICAgfSk7XG5cbiAgICAvLyBTaWRlIGVmZmVjdCBpbXBvcnRzXG5cbiAgICBob29rcy5sYW5nID0gZGVwcmVjYXRlKFxuICAgICAgICAnbW9tZW50LmxhbmcgaXMgZGVwcmVjYXRlZC4gVXNlIG1vbWVudC5sb2NhbGUgaW5zdGVhZC4nLFxuICAgICAgICBnZXRTZXRHbG9iYWxMb2NhbGVcbiAgICApO1xuICAgIGhvb2tzLmxhbmdEYXRhID0gZGVwcmVjYXRlKFxuICAgICAgICAnbW9tZW50LmxhbmdEYXRhIGlzIGRlcHJlY2F0ZWQuIFVzZSBtb21lbnQubG9jYWxlRGF0YSBpbnN0ZWFkLicsXG4gICAgICAgIGdldExvY2FsZVxuICAgICk7XG5cbiAgICB2YXIgbWF0aEFicyA9IE1hdGguYWJzO1xuXG4gICAgZnVuY3Rpb24gYWJzKCkge1xuICAgICAgICB2YXIgZGF0YSA9IHRoaXMuX2RhdGE7XG5cbiAgICAgICAgdGhpcy5fbWlsbGlzZWNvbmRzID0gbWF0aEFicyh0aGlzLl9taWxsaXNlY29uZHMpO1xuICAgICAgICB0aGlzLl9kYXlzID0gbWF0aEFicyh0aGlzLl9kYXlzKTtcbiAgICAgICAgdGhpcy5fbW9udGhzID0gbWF0aEFicyh0aGlzLl9tb250aHMpO1xuXG4gICAgICAgIGRhdGEubWlsbGlzZWNvbmRzID0gbWF0aEFicyhkYXRhLm1pbGxpc2Vjb25kcyk7XG4gICAgICAgIGRhdGEuc2Vjb25kcyA9IG1hdGhBYnMoZGF0YS5zZWNvbmRzKTtcbiAgICAgICAgZGF0YS5taW51dGVzID0gbWF0aEFicyhkYXRhLm1pbnV0ZXMpO1xuICAgICAgICBkYXRhLmhvdXJzID0gbWF0aEFicyhkYXRhLmhvdXJzKTtcbiAgICAgICAgZGF0YS5tb250aHMgPSBtYXRoQWJzKGRhdGEubW9udGhzKTtcbiAgICAgICAgZGF0YS55ZWFycyA9IG1hdGhBYnMoZGF0YS55ZWFycyk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gYWRkU3VidHJhY3QkMShkdXJhdGlvbiwgaW5wdXQsIHZhbHVlLCBkaXJlY3Rpb24pIHtcbiAgICAgICAgdmFyIG90aGVyID0gY3JlYXRlRHVyYXRpb24oaW5wdXQsIHZhbHVlKTtcblxuICAgICAgICBkdXJhdGlvbi5fbWlsbGlzZWNvbmRzICs9IGRpcmVjdGlvbiAqIG90aGVyLl9taWxsaXNlY29uZHM7XG4gICAgICAgIGR1cmF0aW9uLl9kYXlzICs9IGRpcmVjdGlvbiAqIG90aGVyLl9kYXlzO1xuICAgICAgICBkdXJhdGlvbi5fbW9udGhzICs9IGRpcmVjdGlvbiAqIG90aGVyLl9tb250aHM7XG5cbiAgICAgICAgcmV0dXJuIGR1cmF0aW9uLl9idWJibGUoKTtcbiAgICB9XG5cbiAgICAvLyBzdXBwb3J0cyBvbmx5IDIuMC1zdHlsZSBhZGQoMSwgJ3MnKSBvciBhZGQoZHVyYXRpb24pXG4gICAgZnVuY3Rpb24gYWRkJDEoaW5wdXQsIHZhbHVlKSB7XG4gICAgICAgIHJldHVybiBhZGRTdWJ0cmFjdCQxKHRoaXMsIGlucHV0LCB2YWx1ZSwgMSk7XG4gICAgfVxuXG4gICAgLy8gc3VwcG9ydHMgb25seSAyLjAtc3R5bGUgc3VidHJhY3QoMSwgJ3MnKSBvciBzdWJ0cmFjdChkdXJhdGlvbilcbiAgICBmdW5jdGlvbiBzdWJ0cmFjdCQxKGlucHV0LCB2YWx1ZSkge1xuICAgICAgICByZXR1cm4gYWRkU3VidHJhY3QkMSh0aGlzLCBpbnB1dCwgdmFsdWUsIC0xKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBhYnNDZWlsKG51bWJlcikge1xuICAgICAgICBpZiAobnVtYmVyIDwgMCkge1xuICAgICAgICAgICAgcmV0dXJuIE1hdGguZmxvb3IobnVtYmVyKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBNYXRoLmNlaWwobnVtYmVyKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIGJ1YmJsZSgpIHtcbiAgICAgICAgdmFyIG1pbGxpc2Vjb25kcyA9IHRoaXMuX21pbGxpc2Vjb25kcyxcbiAgICAgICAgICAgIGRheXMgPSB0aGlzLl9kYXlzLFxuICAgICAgICAgICAgbW9udGhzID0gdGhpcy5fbW9udGhzLFxuICAgICAgICAgICAgZGF0YSA9IHRoaXMuX2RhdGEsXG4gICAgICAgICAgICBzZWNvbmRzLFxuICAgICAgICAgICAgbWludXRlcyxcbiAgICAgICAgICAgIGhvdXJzLFxuICAgICAgICAgICAgeWVhcnMsXG4gICAgICAgICAgICBtb250aHNGcm9tRGF5cztcblxuICAgICAgICAvLyBpZiB3ZSBoYXZlIGEgbWl4IG9mIHBvc2l0aXZlIGFuZCBuZWdhdGl2ZSB2YWx1ZXMsIGJ1YmJsZSBkb3duIGZpcnN0XG4gICAgICAgIC8vIGNoZWNrOiBodHRwczovL2dpdGh1Yi5jb20vbW9tZW50L21vbWVudC9pc3N1ZXMvMjE2NlxuICAgICAgICBpZiAoXG4gICAgICAgICAgICAhKFxuICAgICAgICAgICAgICAgIChtaWxsaXNlY29uZHMgPj0gMCAmJiBkYXlzID49IDAgJiYgbW9udGhzID49IDApIHx8XG4gICAgICAgICAgICAgICAgKG1pbGxpc2Vjb25kcyA8PSAwICYmIGRheXMgPD0gMCAmJiBtb250aHMgPD0gMClcbiAgICAgICAgICAgIClcbiAgICAgICAgKSB7XG4gICAgICAgICAgICBtaWxsaXNlY29uZHMgKz0gYWJzQ2VpbChtb250aHNUb0RheXMobW9udGhzKSArIGRheXMpICogODY0ZTU7XG4gICAgICAgICAgICBkYXlzID0gMDtcbiAgICAgICAgICAgIG1vbnRocyA9IDA7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBUaGUgZm9sbG93aW5nIGNvZGUgYnViYmxlcyB1cCB2YWx1ZXMsIHNlZSB0aGUgdGVzdHMgZm9yXG4gICAgICAgIC8vIGV4YW1wbGVzIG9mIHdoYXQgdGhhdCBtZWFucy5cbiAgICAgICAgZGF0YS5taWxsaXNlY29uZHMgPSBtaWxsaXNlY29uZHMgJSAxMDAwO1xuXG4gICAgICAgIHNlY29uZHMgPSBhYnNGbG9vcihtaWxsaXNlY29uZHMgLyAxMDAwKTtcbiAgICAgICAgZGF0YS5zZWNvbmRzID0gc2Vjb25kcyAlIDYwO1xuXG4gICAgICAgIG1pbnV0ZXMgPSBhYnNGbG9vcihzZWNvbmRzIC8gNjApO1xuICAgICAgICBkYXRhLm1pbnV0ZXMgPSBtaW51dGVzICUgNjA7XG5cbiAgICAgICAgaG91cnMgPSBhYnNGbG9vcihtaW51dGVzIC8gNjApO1xuICAgICAgICBkYXRhLmhvdXJzID0gaG91cnMgJSAyNDtcblxuICAgICAgICBkYXlzICs9IGFic0Zsb29yKGhvdXJzIC8gMjQpO1xuXG4gICAgICAgIC8vIGNvbnZlcnQgZGF5cyB0byBtb250aHNcbiAgICAgICAgbW9udGhzRnJvbURheXMgPSBhYnNGbG9vcihkYXlzVG9Nb250aHMoZGF5cykpO1xuICAgICAgICBtb250aHMgKz0gbW9udGhzRnJvbURheXM7XG4gICAgICAgIGRheXMgLT0gYWJzQ2VpbChtb250aHNUb0RheXMobW9udGhzRnJvbURheXMpKTtcblxuICAgICAgICAvLyAxMiBtb250aHMgLT4gMSB5ZWFyXG4gICAgICAgIHllYXJzID0gYWJzRmxvb3IobW9udGhzIC8gMTIpO1xuICAgICAgICBtb250aHMgJT0gMTI7XG5cbiAgICAgICAgZGF0YS5kYXlzID0gZGF5cztcbiAgICAgICAgZGF0YS5tb250aHMgPSBtb250aHM7XG4gICAgICAgIGRhdGEueWVhcnMgPSB5ZWFycztcblxuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBkYXlzVG9Nb250aHMoZGF5cykge1xuICAgICAgICAvLyA0MDAgeWVhcnMgaGF2ZSAxNDYwOTcgZGF5cyAodGFraW5nIGludG8gYWNjb3VudCBsZWFwIHllYXIgcnVsZXMpXG4gICAgICAgIC8vIDQwMCB5ZWFycyBoYXZlIDEyIG1vbnRocyA9PT0gNDgwMFxuICAgICAgICByZXR1cm4gKGRheXMgKiA0ODAwKSAvIDE0NjA5NztcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBtb250aHNUb0RheXMobW9udGhzKSB7XG4gICAgICAgIC8vIHRoZSByZXZlcnNlIG9mIGRheXNUb01vbnRoc1xuICAgICAgICByZXR1cm4gKG1vbnRocyAqIDE0NjA5NykgLyA0ODAwO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGFzKHVuaXRzKSB7XG4gICAgICAgIGlmICghdGhpcy5pc1ZhbGlkKCkpIHtcbiAgICAgICAgICAgIHJldHVybiBOYU47XG4gICAgICAgIH1cbiAgICAgICAgdmFyIGRheXMsXG4gICAgICAgICAgICBtb250aHMsXG4gICAgICAgICAgICBtaWxsaXNlY29uZHMgPSB0aGlzLl9taWxsaXNlY29uZHM7XG5cbiAgICAgICAgdW5pdHMgPSBub3JtYWxpemVVbml0cyh1bml0cyk7XG5cbiAgICAgICAgaWYgKHVuaXRzID09PSAnbW9udGgnIHx8IHVuaXRzID09PSAncXVhcnRlcicgfHwgdW5pdHMgPT09ICd5ZWFyJykge1xuICAgICAgICAgICAgZGF5cyA9IHRoaXMuX2RheXMgKyBtaWxsaXNlY29uZHMgLyA4NjRlNTtcbiAgICAgICAgICAgIG1vbnRocyA9IHRoaXMuX21vbnRocyArIGRheXNUb01vbnRocyhkYXlzKTtcbiAgICAgICAgICAgIHN3aXRjaCAodW5pdHMpIHtcbiAgICAgICAgICAgICAgICBjYXNlICdtb250aCc6XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBtb250aHM7XG4gICAgICAgICAgICAgICAgY2FzZSAncXVhcnRlcic6XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBtb250aHMgLyAzO1xuICAgICAgICAgICAgICAgIGNhc2UgJ3llYXInOlxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gbW9udGhzIC8gMTI7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBoYW5kbGUgbWlsbGlzZWNvbmRzIHNlcGFyYXRlbHkgYmVjYXVzZSBvZiBmbG9hdGluZyBwb2ludCBtYXRoIGVycm9ycyAoaXNzdWUgIzE4NjcpXG4gICAgICAgICAgICBkYXlzID0gdGhpcy5fZGF5cyArIE1hdGgucm91bmQobW9udGhzVG9EYXlzKHRoaXMuX21vbnRocykpO1xuICAgICAgICAgICAgc3dpdGNoICh1bml0cykge1xuICAgICAgICAgICAgICAgIGNhc2UgJ3dlZWsnOlxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZGF5cyAvIDcgKyBtaWxsaXNlY29uZHMgLyA2MDQ4ZTU7XG4gICAgICAgICAgICAgICAgY2FzZSAnZGF5JzpcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGRheXMgKyBtaWxsaXNlY29uZHMgLyA4NjRlNTtcbiAgICAgICAgICAgICAgICBjYXNlICdob3VyJzpcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGRheXMgKiAyNCArIG1pbGxpc2Vjb25kcyAvIDM2ZTU7XG4gICAgICAgICAgICAgICAgY2FzZSAnbWludXRlJzpcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGRheXMgKiAxNDQwICsgbWlsbGlzZWNvbmRzIC8gNmU0O1xuICAgICAgICAgICAgICAgIGNhc2UgJ3NlY29uZCc6XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBkYXlzICogODY0MDAgKyBtaWxsaXNlY29uZHMgLyAxMDAwO1xuICAgICAgICAgICAgICAgIC8vIE1hdGguZmxvb3IgcHJldmVudHMgZmxvYXRpbmcgcG9pbnQgbWF0aCBlcnJvcnMgaGVyZVxuICAgICAgICAgICAgICAgIGNhc2UgJ21pbGxpc2Vjb25kJzpcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIE1hdGguZmxvb3IoZGF5cyAqIDg2NGU1KSArIG1pbGxpc2Vjb25kcztcbiAgICAgICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1Vua25vd24gdW5pdCAnICsgdW5pdHMpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gVE9ETzogVXNlIHRoaXMuYXMoJ21zJyk/XG4gICAgZnVuY3Rpb24gdmFsdWVPZiQxKCkge1xuICAgICAgICBpZiAoIXRoaXMuaXNWYWxpZCgpKSB7XG4gICAgICAgICAgICByZXR1cm4gTmFOO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICB0aGlzLl9taWxsaXNlY29uZHMgK1xuICAgICAgICAgICAgdGhpcy5fZGF5cyAqIDg2NGU1ICtcbiAgICAgICAgICAgICh0aGlzLl9tb250aHMgJSAxMikgKiAyNTkyZTYgK1xuICAgICAgICAgICAgdG9JbnQodGhpcy5fbW9udGhzIC8gMTIpICogMzE1MzZlNlxuICAgICAgICApO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIG1ha2VBcyhhbGlhcykge1xuICAgICAgICByZXR1cm4gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuYXMoYWxpYXMpO1xuICAgICAgICB9O1xuICAgIH1cblxuICAgIHZhciBhc01pbGxpc2Vjb25kcyA9IG1ha2VBcygnbXMnKSxcbiAgICAgICAgYXNTZWNvbmRzID0gbWFrZUFzKCdzJyksXG4gICAgICAgIGFzTWludXRlcyA9IG1ha2VBcygnbScpLFxuICAgICAgICBhc0hvdXJzID0gbWFrZUFzKCdoJyksXG4gICAgICAgIGFzRGF5cyA9IG1ha2VBcygnZCcpLFxuICAgICAgICBhc1dlZWtzID0gbWFrZUFzKCd3JyksXG4gICAgICAgIGFzTW9udGhzID0gbWFrZUFzKCdNJyksXG4gICAgICAgIGFzUXVhcnRlcnMgPSBtYWtlQXMoJ1EnKSxcbiAgICAgICAgYXNZZWFycyA9IG1ha2VBcygneScpO1xuXG4gICAgZnVuY3Rpb24gY2xvbmUkMSgpIHtcbiAgICAgICAgcmV0dXJuIGNyZWF0ZUR1cmF0aW9uKHRoaXMpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGdldCQyKHVuaXRzKSB7XG4gICAgICAgIHVuaXRzID0gbm9ybWFsaXplVW5pdHModW5pdHMpO1xuICAgICAgICByZXR1cm4gdGhpcy5pc1ZhbGlkKCkgPyB0aGlzW3VuaXRzICsgJ3MnXSgpIDogTmFOO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIG1ha2VHZXR0ZXIobmFtZSkge1xuICAgICAgICByZXR1cm4gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuaXNWYWxpZCgpID8gdGhpcy5fZGF0YVtuYW1lXSA6IE5hTjtcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICB2YXIgbWlsbGlzZWNvbmRzID0gbWFrZUdldHRlcignbWlsbGlzZWNvbmRzJyksXG4gICAgICAgIHNlY29uZHMgPSBtYWtlR2V0dGVyKCdzZWNvbmRzJyksXG4gICAgICAgIG1pbnV0ZXMgPSBtYWtlR2V0dGVyKCdtaW51dGVzJyksXG4gICAgICAgIGhvdXJzID0gbWFrZUdldHRlcignaG91cnMnKSxcbiAgICAgICAgZGF5cyA9IG1ha2VHZXR0ZXIoJ2RheXMnKSxcbiAgICAgICAgbW9udGhzID0gbWFrZUdldHRlcignbW9udGhzJyksXG4gICAgICAgIHllYXJzID0gbWFrZUdldHRlcigneWVhcnMnKTtcblxuICAgIGZ1bmN0aW9uIHdlZWtzKCkge1xuICAgICAgICByZXR1cm4gYWJzRmxvb3IodGhpcy5kYXlzKCkgLyA3KTtcbiAgICB9XG5cbiAgICB2YXIgcm91bmQgPSBNYXRoLnJvdW5kLFxuICAgICAgICB0aHJlc2hvbGRzID0ge1xuICAgICAgICAgICAgc3M6IDQ0LCAvLyBhIGZldyBzZWNvbmRzIHRvIHNlY29uZHNcbiAgICAgICAgICAgIHM6IDQ1LCAvLyBzZWNvbmRzIHRvIG1pbnV0ZVxuICAgICAgICAgICAgbTogNDUsIC8vIG1pbnV0ZXMgdG8gaG91clxuICAgICAgICAgICAgaDogMjIsIC8vIGhvdXJzIHRvIGRheVxuICAgICAgICAgICAgZDogMjYsIC8vIGRheXMgdG8gbW9udGgvd2Vla1xuICAgICAgICAgICAgdzogbnVsbCwgLy8gd2Vla3MgdG8gbW9udGhcbiAgICAgICAgICAgIE06IDExLCAvLyBtb250aHMgdG8geWVhclxuICAgICAgICB9O1xuXG4gICAgLy8gaGVscGVyIGZ1bmN0aW9uIGZvciBtb21lbnQuZm4uZnJvbSwgbW9tZW50LmZuLmZyb21Ob3csIGFuZCBtb21lbnQuZHVyYXRpb24uZm4uaHVtYW5pemVcbiAgICBmdW5jdGlvbiBzdWJzdGl0dXRlVGltZUFnbyhzdHJpbmcsIG51bWJlciwgd2l0aG91dFN1ZmZpeCwgaXNGdXR1cmUsIGxvY2FsZSkge1xuICAgICAgICByZXR1cm4gbG9jYWxlLnJlbGF0aXZlVGltZShudW1iZXIgfHwgMSwgISF3aXRob3V0U3VmZml4LCBzdHJpbmcsIGlzRnV0dXJlKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiByZWxhdGl2ZVRpbWUkMShwb3NOZWdEdXJhdGlvbiwgd2l0aG91dFN1ZmZpeCwgdGhyZXNob2xkcywgbG9jYWxlKSB7XG4gICAgICAgIHZhciBkdXJhdGlvbiA9IGNyZWF0ZUR1cmF0aW9uKHBvc05lZ0R1cmF0aW9uKS5hYnMoKSxcbiAgICAgICAgICAgIHNlY29uZHMgPSByb3VuZChkdXJhdGlvbi5hcygncycpKSxcbiAgICAgICAgICAgIG1pbnV0ZXMgPSByb3VuZChkdXJhdGlvbi5hcygnbScpKSxcbiAgICAgICAgICAgIGhvdXJzID0gcm91bmQoZHVyYXRpb24uYXMoJ2gnKSksXG4gICAgICAgICAgICBkYXlzID0gcm91bmQoZHVyYXRpb24uYXMoJ2QnKSksXG4gICAgICAgICAgICBtb250aHMgPSByb3VuZChkdXJhdGlvbi5hcygnTScpKSxcbiAgICAgICAgICAgIHdlZWtzID0gcm91bmQoZHVyYXRpb24uYXMoJ3cnKSksXG4gICAgICAgICAgICB5ZWFycyA9IHJvdW5kKGR1cmF0aW9uLmFzKCd5JykpLFxuICAgICAgICAgICAgYSA9XG4gICAgICAgICAgICAgICAgKHNlY29uZHMgPD0gdGhyZXNob2xkcy5zcyAmJiBbJ3MnLCBzZWNvbmRzXSkgfHxcbiAgICAgICAgICAgICAgICAoc2Vjb25kcyA8IHRocmVzaG9sZHMucyAmJiBbJ3NzJywgc2Vjb25kc10pIHx8XG4gICAgICAgICAgICAgICAgKG1pbnV0ZXMgPD0gMSAmJiBbJ20nXSkgfHxcbiAgICAgICAgICAgICAgICAobWludXRlcyA8IHRocmVzaG9sZHMubSAmJiBbJ21tJywgbWludXRlc10pIHx8XG4gICAgICAgICAgICAgICAgKGhvdXJzIDw9IDEgJiYgWydoJ10pIHx8XG4gICAgICAgICAgICAgICAgKGhvdXJzIDwgdGhyZXNob2xkcy5oICYmIFsnaGgnLCBob3Vyc10pIHx8XG4gICAgICAgICAgICAgICAgKGRheXMgPD0gMSAmJiBbJ2QnXSkgfHxcbiAgICAgICAgICAgICAgICAoZGF5cyA8IHRocmVzaG9sZHMuZCAmJiBbJ2RkJywgZGF5c10pO1xuXG4gICAgICAgIGlmICh0aHJlc2hvbGRzLncgIT0gbnVsbCkge1xuICAgICAgICAgICAgYSA9XG4gICAgICAgICAgICAgICAgYSB8fFxuICAgICAgICAgICAgICAgICh3ZWVrcyA8PSAxICYmIFsndyddKSB8fFxuICAgICAgICAgICAgICAgICh3ZWVrcyA8IHRocmVzaG9sZHMudyAmJiBbJ3d3Jywgd2Vla3NdKTtcbiAgICAgICAgfVxuICAgICAgICBhID0gYSB8fFxuICAgICAgICAgICAgKG1vbnRocyA8PSAxICYmIFsnTSddKSB8fFxuICAgICAgICAgICAgKG1vbnRocyA8IHRocmVzaG9sZHMuTSAmJiBbJ01NJywgbW9udGhzXSkgfHxcbiAgICAgICAgICAgICh5ZWFycyA8PSAxICYmIFsneSddKSB8fCBbJ3l5JywgeWVhcnNdO1xuXG4gICAgICAgIGFbMl0gPSB3aXRob3V0U3VmZml4O1xuICAgICAgICBhWzNdID0gK3Bvc05lZ0R1cmF0aW9uID4gMDtcbiAgICAgICAgYVs0XSA9IGxvY2FsZTtcbiAgICAgICAgcmV0dXJuIHN1YnN0aXR1dGVUaW1lQWdvLmFwcGx5KG51bGwsIGEpO1xuICAgIH1cblxuICAgIC8vIFRoaXMgZnVuY3Rpb24gYWxsb3dzIHlvdSB0byBzZXQgdGhlIHJvdW5kaW5nIGZ1bmN0aW9uIGZvciByZWxhdGl2ZSB0aW1lIHN0cmluZ3NcbiAgICBmdW5jdGlvbiBnZXRTZXRSZWxhdGl2ZVRpbWVSb3VuZGluZyhyb3VuZGluZ0Z1bmN0aW9uKSB7XG4gICAgICAgIGlmIChyb3VuZGluZ0Z1bmN0aW9uID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIHJldHVybiByb3VuZDtcbiAgICAgICAgfVxuICAgICAgICBpZiAodHlwZW9mIHJvdW5kaW5nRnVuY3Rpb24gPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgIHJvdW5kID0gcm91bmRpbmdGdW5jdGlvbjtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICAvLyBUaGlzIGZ1bmN0aW9uIGFsbG93cyB5b3UgdG8gc2V0IGEgdGhyZXNob2xkIGZvciByZWxhdGl2ZSB0aW1lIHN0cmluZ3NcbiAgICBmdW5jdGlvbiBnZXRTZXRSZWxhdGl2ZVRpbWVUaHJlc2hvbGQodGhyZXNob2xkLCBsaW1pdCkge1xuICAgICAgICBpZiAodGhyZXNob2xkc1t0aHJlc2hvbGRdID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICBpZiAobGltaXQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgcmV0dXJuIHRocmVzaG9sZHNbdGhyZXNob2xkXTtcbiAgICAgICAgfVxuICAgICAgICB0aHJlc2hvbGRzW3RocmVzaG9sZF0gPSBsaW1pdDtcbiAgICAgICAgaWYgKHRocmVzaG9sZCA9PT0gJ3MnKSB7XG4gICAgICAgICAgICB0aHJlc2hvbGRzLnNzID0gbGltaXQgLSAxO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGh1bWFuaXplKGFyZ1dpdGhTdWZmaXgsIGFyZ1RocmVzaG9sZHMpIHtcbiAgICAgICAgaWYgKCF0aGlzLmlzVmFsaWQoKSkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMubG9jYWxlRGF0YSgpLmludmFsaWREYXRlKCk7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgd2l0aFN1ZmZpeCA9IGZhbHNlLFxuICAgICAgICAgICAgdGggPSB0aHJlc2hvbGRzLFxuICAgICAgICAgICAgbG9jYWxlLFxuICAgICAgICAgICAgb3V0cHV0O1xuXG4gICAgICAgIGlmICh0eXBlb2YgYXJnV2l0aFN1ZmZpeCA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgIGFyZ1RocmVzaG9sZHMgPSBhcmdXaXRoU3VmZml4O1xuICAgICAgICAgICAgYXJnV2l0aFN1ZmZpeCA9IGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0eXBlb2YgYXJnV2l0aFN1ZmZpeCA9PT0gJ2Jvb2xlYW4nKSB7XG4gICAgICAgICAgICB3aXRoU3VmZml4ID0gYXJnV2l0aFN1ZmZpeDtcbiAgICAgICAgfVxuICAgICAgICBpZiAodHlwZW9mIGFyZ1RocmVzaG9sZHMgPT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICB0aCA9IE9iamVjdC5hc3NpZ24oe30sIHRocmVzaG9sZHMsIGFyZ1RocmVzaG9sZHMpO1xuICAgICAgICAgICAgaWYgKGFyZ1RocmVzaG9sZHMucyAhPSBudWxsICYmIGFyZ1RocmVzaG9sZHMuc3MgPT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIHRoLnNzID0gYXJnVGhyZXNob2xkcy5zIC0gMTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGxvY2FsZSA9IHRoaXMubG9jYWxlRGF0YSgpO1xuICAgICAgICBvdXRwdXQgPSByZWxhdGl2ZVRpbWUkMSh0aGlzLCAhd2l0aFN1ZmZpeCwgdGgsIGxvY2FsZSk7XG5cbiAgICAgICAgaWYgKHdpdGhTdWZmaXgpIHtcbiAgICAgICAgICAgIG91dHB1dCA9IGxvY2FsZS5wYXN0RnV0dXJlKCt0aGlzLCBvdXRwdXQpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGxvY2FsZS5wb3N0Zm9ybWF0KG91dHB1dCk7XG4gICAgfVxuXG4gICAgdmFyIGFicyQxID0gTWF0aC5hYnM7XG5cbiAgICBmdW5jdGlvbiBzaWduKHgpIHtcbiAgICAgICAgcmV0dXJuICh4ID4gMCkgLSAoeCA8IDApIHx8ICt4O1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHRvSVNPU3RyaW5nJDEoKSB7XG4gICAgICAgIC8vIGZvciBJU08gc3RyaW5ncyB3ZSBkbyBub3QgdXNlIHRoZSBub3JtYWwgYnViYmxpbmcgcnVsZXM6XG4gICAgICAgIC8vICAqIG1pbGxpc2Vjb25kcyBidWJibGUgdXAgdW50aWwgdGhleSBiZWNvbWUgaG91cnNcbiAgICAgICAgLy8gICogZGF5cyBkbyBub3QgYnViYmxlIGF0IGFsbFxuICAgICAgICAvLyAgKiBtb250aHMgYnViYmxlIHVwIHVudGlsIHRoZXkgYmVjb21lIHllYXJzXG4gICAgICAgIC8vIFRoaXMgaXMgYmVjYXVzZSB0aGVyZSBpcyBubyBjb250ZXh0LWZyZWUgY29udmVyc2lvbiBiZXR3ZWVuIGhvdXJzIGFuZCBkYXlzXG4gICAgICAgIC8vICh0aGluayBvZiBjbG9jayBjaGFuZ2VzKVxuICAgICAgICAvLyBhbmQgYWxzbyBub3QgYmV0d2VlbiBkYXlzIGFuZCBtb250aHMgKDI4LTMxIGRheXMgcGVyIG1vbnRoKVxuICAgICAgICBpZiAoIXRoaXMuaXNWYWxpZCgpKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5sb2NhbGVEYXRhKCkuaW52YWxpZERhdGUoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBzZWNvbmRzID0gYWJzJDEodGhpcy5fbWlsbGlzZWNvbmRzKSAvIDEwMDAsXG4gICAgICAgICAgICBkYXlzID0gYWJzJDEodGhpcy5fZGF5cyksXG4gICAgICAgICAgICBtb250aHMgPSBhYnMkMSh0aGlzLl9tb250aHMpLFxuICAgICAgICAgICAgbWludXRlcyxcbiAgICAgICAgICAgIGhvdXJzLFxuICAgICAgICAgICAgeWVhcnMsXG4gICAgICAgICAgICBzLFxuICAgICAgICAgICAgdG90YWwgPSB0aGlzLmFzU2Vjb25kcygpLFxuICAgICAgICAgICAgdG90YWxTaWduLFxuICAgICAgICAgICAgeW1TaWduLFxuICAgICAgICAgICAgZGF5c1NpZ24sXG4gICAgICAgICAgICBobXNTaWduO1xuXG4gICAgICAgIGlmICghdG90YWwpIHtcbiAgICAgICAgICAgIC8vIHRoaXMgaXMgdGhlIHNhbWUgYXMgQyMncyAoTm9kYSkgYW5kIHB5dGhvbiAoaXNvZGF0ZSkuLi5cbiAgICAgICAgICAgIC8vIGJ1dCBub3Qgb3RoZXIgSlMgKGdvb2cuZGF0ZSlcbiAgICAgICAgICAgIHJldHVybiAnUDBEJztcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIDM2MDAgc2Vjb25kcyAtPiA2MCBtaW51dGVzIC0+IDEgaG91clxuICAgICAgICBtaW51dGVzID0gYWJzRmxvb3Ioc2Vjb25kcyAvIDYwKTtcbiAgICAgICAgaG91cnMgPSBhYnNGbG9vcihtaW51dGVzIC8gNjApO1xuICAgICAgICBzZWNvbmRzICU9IDYwO1xuICAgICAgICBtaW51dGVzICU9IDYwO1xuXG4gICAgICAgIC8vIDEyIG1vbnRocyAtPiAxIHllYXJcbiAgICAgICAgeWVhcnMgPSBhYnNGbG9vcihtb250aHMgLyAxMik7XG4gICAgICAgIG1vbnRocyAlPSAxMjtcblxuICAgICAgICAvLyBpbnNwaXJlZCBieSBodHRwczovL2dpdGh1Yi5jb20vZG9yZGlsbGUvbW9tZW50LWlzb2R1cmF0aW9uL2Jsb2IvbWFzdGVyL21vbWVudC5pc29kdXJhdGlvbi5qc1xuICAgICAgICBzID0gc2Vjb25kcyA/IHNlY29uZHMudG9GaXhlZCgzKS5yZXBsYWNlKC9cXC4/MCskLywgJycpIDogJyc7XG5cbiAgICAgICAgdG90YWxTaWduID0gdG90YWwgPCAwID8gJy0nIDogJyc7XG4gICAgICAgIHltU2lnbiA9IHNpZ24odGhpcy5fbW9udGhzKSAhPT0gc2lnbih0b3RhbCkgPyAnLScgOiAnJztcbiAgICAgICAgZGF5c1NpZ24gPSBzaWduKHRoaXMuX2RheXMpICE9PSBzaWduKHRvdGFsKSA/ICctJyA6ICcnO1xuICAgICAgICBobXNTaWduID0gc2lnbih0aGlzLl9taWxsaXNlY29uZHMpICE9PSBzaWduKHRvdGFsKSA/ICctJyA6ICcnO1xuXG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICB0b3RhbFNpZ24gK1xuICAgICAgICAgICAgJ1AnICtcbiAgICAgICAgICAgICh5ZWFycyA/IHltU2lnbiArIHllYXJzICsgJ1knIDogJycpICtcbiAgICAgICAgICAgIChtb250aHMgPyB5bVNpZ24gKyBtb250aHMgKyAnTScgOiAnJykgK1xuICAgICAgICAgICAgKGRheXMgPyBkYXlzU2lnbiArIGRheXMgKyAnRCcgOiAnJykgK1xuICAgICAgICAgICAgKGhvdXJzIHx8IG1pbnV0ZXMgfHwgc2Vjb25kcyA/ICdUJyA6ICcnKSArXG4gICAgICAgICAgICAoaG91cnMgPyBobXNTaWduICsgaG91cnMgKyAnSCcgOiAnJykgK1xuICAgICAgICAgICAgKG1pbnV0ZXMgPyBobXNTaWduICsgbWludXRlcyArICdNJyA6ICcnKSArXG4gICAgICAgICAgICAoc2Vjb25kcyA/IGhtc1NpZ24gKyBzICsgJ1MnIDogJycpXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgdmFyIHByb3RvJDIgPSBEdXJhdGlvbi5wcm90b3R5cGU7XG5cbiAgICBwcm90byQyLmlzVmFsaWQgPSBpc1ZhbGlkJDE7XG4gICAgcHJvdG8kMi5hYnMgPSBhYnM7XG4gICAgcHJvdG8kMi5hZGQgPSBhZGQkMTtcbiAgICBwcm90byQyLnN1YnRyYWN0ID0gc3VidHJhY3QkMTtcbiAgICBwcm90byQyLmFzID0gYXM7XG4gICAgcHJvdG8kMi5hc01pbGxpc2Vjb25kcyA9IGFzTWlsbGlzZWNvbmRzO1xuICAgIHByb3RvJDIuYXNTZWNvbmRzID0gYXNTZWNvbmRzO1xuICAgIHByb3RvJDIuYXNNaW51dGVzID0gYXNNaW51dGVzO1xuICAgIHByb3RvJDIuYXNIb3VycyA9IGFzSG91cnM7XG4gICAgcHJvdG8kMi5hc0RheXMgPSBhc0RheXM7XG4gICAgcHJvdG8kMi5hc1dlZWtzID0gYXNXZWVrcztcbiAgICBwcm90byQyLmFzTW9udGhzID0gYXNNb250aHM7XG4gICAgcHJvdG8kMi5hc1F1YXJ0ZXJzID0gYXNRdWFydGVycztcbiAgICBwcm90byQyLmFzWWVhcnMgPSBhc1llYXJzO1xuICAgIHByb3RvJDIudmFsdWVPZiA9IHZhbHVlT2YkMTtcbiAgICBwcm90byQyLl9idWJibGUgPSBidWJibGU7XG4gICAgcHJvdG8kMi5jbG9uZSA9IGNsb25lJDE7XG4gICAgcHJvdG8kMi5nZXQgPSBnZXQkMjtcbiAgICBwcm90byQyLm1pbGxpc2Vjb25kcyA9IG1pbGxpc2Vjb25kcztcbiAgICBwcm90byQyLnNlY29uZHMgPSBzZWNvbmRzO1xuICAgIHByb3RvJDIubWludXRlcyA9IG1pbnV0ZXM7XG4gICAgcHJvdG8kMi5ob3VycyA9IGhvdXJzO1xuICAgIHByb3RvJDIuZGF5cyA9IGRheXM7XG4gICAgcHJvdG8kMi53ZWVrcyA9IHdlZWtzO1xuICAgIHByb3RvJDIubW9udGhzID0gbW9udGhzO1xuICAgIHByb3RvJDIueWVhcnMgPSB5ZWFycztcbiAgICBwcm90byQyLmh1bWFuaXplID0gaHVtYW5pemU7XG4gICAgcHJvdG8kMi50b0lTT1N0cmluZyA9IHRvSVNPU3RyaW5nJDE7XG4gICAgcHJvdG8kMi50b1N0cmluZyA9IHRvSVNPU3RyaW5nJDE7XG4gICAgcHJvdG8kMi50b0pTT04gPSB0b0lTT1N0cmluZyQxO1xuICAgIHByb3RvJDIubG9jYWxlID0gbG9jYWxlO1xuICAgIHByb3RvJDIubG9jYWxlRGF0YSA9IGxvY2FsZURhdGE7XG5cbiAgICBwcm90byQyLnRvSXNvU3RyaW5nID0gZGVwcmVjYXRlKFxuICAgICAgICAndG9Jc29TdHJpbmcoKSBpcyBkZXByZWNhdGVkLiBQbGVhc2UgdXNlIHRvSVNPU3RyaW5nKCkgaW5zdGVhZCAobm90aWNlIHRoZSBjYXBpdGFscyknLFxuICAgICAgICB0b0lTT1N0cmluZyQxXG4gICAgKTtcbiAgICBwcm90byQyLmxhbmcgPSBsYW5nO1xuXG4gICAgLy8gRk9STUFUVElOR1xuXG4gICAgYWRkRm9ybWF0VG9rZW4oJ1gnLCAwLCAwLCAndW5peCcpO1xuICAgIGFkZEZvcm1hdFRva2VuKCd4JywgMCwgMCwgJ3ZhbHVlT2YnKTtcblxuICAgIC8vIFBBUlNJTkdcblxuICAgIGFkZFJlZ2V4VG9rZW4oJ3gnLCBtYXRjaFNpZ25lZCk7XG4gICAgYWRkUmVnZXhUb2tlbignWCcsIG1hdGNoVGltZXN0YW1wKTtcbiAgICBhZGRQYXJzZVRva2VuKCdYJywgZnVuY3Rpb24gKGlucHV0LCBhcnJheSwgY29uZmlnKSB7XG4gICAgICAgIGNvbmZpZy5fZCA9IG5ldyBEYXRlKHBhcnNlRmxvYXQoaW5wdXQpICogMTAwMCk7XG4gICAgfSk7XG4gICAgYWRkUGFyc2VUb2tlbigneCcsIGZ1bmN0aW9uIChpbnB1dCwgYXJyYXksIGNvbmZpZykge1xuICAgICAgICBjb25maWcuX2QgPSBuZXcgRGF0ZSh0b0ludChpbnB1dCkpO1xuICAgIH0pO1xuXG4gICAgLy8hIG1vbWVudC5qc1xuXG4gICAgaG9va3MudmVyc2lvbiA9ICcyLjI3LjAnO1xuXG4gICAgc2V0SG9va0NhbGxiYWNrKGNyZWF0ZUxvY2FsKTtcblxuICAgIGhvb2tzLmZuID0gcHJvdG87XG4gICAgaG9va3MubWluID0gbWluO1xuICAgIGhvb2tzLm1heCA9IG1heDtcbiAgICBob29rcy5ub3cgPSBub3c7XG4gICAgaG9va3MudXRjID0gY3JlYXRlVVRDO1xuICAgIGhvb2tzLnVuaXggPSBjcmVhdGVVbml4O1xuICAgIGhvb2tzLm1vbnRocyA9IGxpc3RNb250aHM7XG4gICAgaG9va3MuaXNEYXRlID0gaXNEYXRlO1xuICAgIGhvb2tzLmxvY2FsZSA9IGdldFNldEdsb2JhbExvY2FsZTtcbiAgICBob29rcy5pbnZhbGlkID0gY3JlYXRlSW52YWxpZDtcbiAgICBob29rcy5kdXJhdGlvbiA9IGNyZWF0ZUR1cmF0aW9uO1xuICAgIGhvb2tzLmlzTW9tZW50ID0gaXNNb21lbnQ7XG4gICAgaG9va3Mud2Vla2RheXMgPSBsaXN0V2Vla2RheXM7XG4gICAgaG9va3MucGFyc2Vab25lID0gY3JlYXRlSW5ab25lO1xuICAgIGhvb2tzLmxvY2FsZURhdGEgPSBnZXRMb2NhbGU7XG4gICAgaG9va3MuaXNEdXJhdGlvbiA9IGlzRHVyYXRpb247XG4gICAgaG9va3MubW9udGhzU2hvcnQgPSBsaXN0TW9udGhzU2hvcnQ7XG4gICAgaG9va3Mud2Vla2RheXNNaW4gPSBsaXN0V2Vla2RheXNNaW47XG4gICAgaG9va3MuZGVmaW5lTG9jYWxlID0gZGVmaW5lTG9jYWxlO1xuICAgIGhvb2tzLnVwZGF0ZUxvY2FsZSA9IHVwZGF0ZUxvY2FsZTtcbiAgICBob29rcy5sb2NhbGVzID0gbGlzdExvY2FsZXM7XG4gICAgaG9va3Mud2Vla2RheXNTaG9ydCA9IGxpc3RXZWVrZGF5c1Nob3J0O1xuICAgIGhvb2tzLm5vcm1hbGl6ZVVuaXRzID0gbm9ybWFsaXplVW5pdHM7XG4gICAgaG9va3MucmVsYXRpdmVUaW1lUm91bmRpbmcgPSBnZXRTZXRSZWxhdGl2ZVRpbWVSb3VuZGluZztcbiAgICBob29rcy5yZWxhdGl2ZVRpbWVUaHJlc2hvbGQgPSBnZXRTZXRSZWxhdGl2ZVRpbWVUaHJlc2hvbGQ7XG4gICAgaG9va3MuY2FsZW5kYXJGb3JtYXQgPSBnZXRDYWxlbmRhckZvcm1hdDtcbiAgICBob29rcy5wcm90b3R5cGUgPSBwcm90bztcblxuICAgIC8vIGN1cnJlbnRseSBIVE1MNSBpbnB1dCB0eXBlIG9ubHkgc3VwcG9ydHMgMjQtaG91ciBmb3JtYXRzXG4gICAgaG9va3MuSFRNTDVfRk1UID0ge1xuICAgICAgICBEQVRFVElNRV9MT0NBTDogJ1lZWVktTU0tRERUSEg6bW0nLCAvLyA8aW5wdXQgdHlwZT1cImRhdGV0aW1lLWxvY2FsXCIgLz5cbiAgICAgICAgREFURVRJTUVfTE9DQUxfU0VDT05EUzogJ1lZWVktTU0tRERUSEg6bW06c3MnLCAvLyA8aW5wdXQgdHlwZT1cImRhdGV0aW1lLWxvY2FsXCIgc3RlcD1cIjFcIiAvPlxuICAgICAgICBEQVRFVElNRV9MT0NBTF9NUzogJ1lZWVktTU0tRERUSEg6bW06c3MuU1NTJywgLy8gPGlucHV0IHR5cGU9XCJkYXRldGltZS1sb2NhbFwiIHN0ZXA9XCIwLjAwMVwiIC8+XG4gICAgICAgIERBVEU6ICdZWVlZLU1NLUREJywgLy8gPGlucHV0IHR5cGU9XCJkYXRlXCIgLz5cbiAgICAgICAgVElNRTogJ0hIOm1tJywgLy8gPGlucHV0IHR5cGU9XCJ0aW1lXCIgLz5cbiAgICAgICAgVElNRV9TRUNPTkRTOiAnSEg6bW06c3MnLCAvLyA8aW5wdXQgdHlwZT1cInRpbWVcIiBzdGVwPVwiMVwiIC8+XG4gICAgICAgIFRJTUVfTVM6ICdISDptbTpzcy5TU1MnLCAvLyA8aW5wdXQgdHlwZT1cInRpbWVcIiBzdGVwPVwiMC4wMDFcIiAvPlxuICAgICAgICBXRUVLOiAnR0dHRy1bV11XVycsIC8vIDxpbnB1dCB0eXBlPVwid2Vla1wiIC8+XG4gICAgICAgIE1PTlRIOiAnWVlZWS1NTScsIC8vIDxpbnB1dCB0eXBlPVwibW9udGhcIiAvPlxuICAgIH07XG5cbiAgICByZXR1cm4gaG9va3M7XG5cbn0pKSk7XG4iLCIvLyBHZW5lcmF0ZWQgYnkgTGl2ZVNjcmlwdCAxLjYuMFxudmFyIGFwcGx5LCBjdXJyeSwgZmxpcCwgZml4LCBvdmVyLCBtZW1vaXplLCB0b1N0cmluZyQgPSB7fS50b1N0cmluZztcbmFwcGx5ID0gY3VycnkkKGZ1bmN0aW9uKGYsIGxpc3Qpe1xuICByZXR1cm4gZi5hcHBseShudWxsLCBsaXN0KTtcbn0pO1xuY3VycnkgPSBmdW5jdGlvbihmKXtcbiAgcmV0dXJuIGN1cnJ5JChmKTtcbn07XG5mbGlwID0gY3VycnkkKGZ1bmN0aW9uKGYsIHgsIHkpe1xuICByZXR1cm4gZih5LCB4KTtcbn0pO1xuZml4ID0gZnVuY3Rpb24oZil7XG4gIHJldHVybiBmdW5jdGlvbihnKXtcbiAgICByZXR1cm4gZnVuY3Rpb24oKXtcbiAgICAgIHJldHVybiBmKGcoZykpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7XG4gICAgfTtcbiAgfShmdW5jdGlvbihnKXtcbiAgICByZXR1cm4gZnVuY3Rpb24oKXtcbiAgICAgIHJldHVybiBmKGcoZykpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7XG4gICAgfTtcbiAgfSk7XG59O1xub3ZlciA9IGN1cnJ5JChmdW5jdGlvbihmLCBnLCB4LCB5KXtcbiAgcmV0dXJuIGYoZyh4KSwgZyh5KSk7XG59KTtcbm1lbW9pemUgPSBmdW5jdGlvbihmKXtcbiAgdmFyIG1lbW87XG4gIG1lbW8gPSB7fTtcbiAgcmV0dXJuIGZ1bmN0aW9uKCl7XG4gICAgdmFyIGFyZ3MsIHJlcyQsIGkkLCB0byQsIGtleSwgYXJnO1xuICAgIHJlcyQgPSBbXTtcbiAgICBmb3IgKGkkID0gMCwgdG8kID0gYXJndW1lbnRzLmxlbmd0aDsgaSQgPCB0byQ7ICsraSQpIHtcbiAgICAgIHJlcyQucHVzaChhcmd1bWVudHNbaSRdKTtcbiAgICB9XG4gICAgYXJncyA9IHJlcyQ7XG4gICAga2V5ID0gKGZ1bmN0aW9uKCl7XG4gICAgICB2YXIgaSQsIHJlZiQsIGxlbiQsIHJlc3VsdHMkID0gW107XG4gICAgICBmb3IgKGkkID0gMCwgbGVuJCA9IChyZWYkID0gYXJncykubGVuZ3RoOyBpJCA8IGxlbiQ7ICsraSQpIHtcbiAgICAgICAgYXJnID0gcmVmJFtpJF07XG4gICAgICAgIHJlc3VsdHMkLnB1c2goYXJnICsgdG9TdHJpbmckLmNhbGwoYXJnKS5zbGljZSg4LCAtMSkpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHJlc3VsdHMkO1xuICAgIH0oKSkuam9pbignJyk7XG4gICAgcmV0dXJuIG1lbW9ba2V5XSA9IGtleSBpbiBtZW1vXG4gICAgICA/IG1lbW9ba2V5XVxuICAgICAgOiBmLmFwcGx5KG51bGwsIGFyZ3MpO1xuICB9O1xufTtcbm1vZHVsZS5leHBvcnRzID0ge1xuICBjdXJyeTogY3VycnksXG4gIGZsaXA6IGZsaXAsXG4gIGZpeDogZml4LFxuICBhcHBseTogYXBwbHksXG4gIG92ZXI6IG92ZXIsXG4gIG1lbW9pemU6IG1lbW9pemVcbn07XG5mdW5jdGlvbiBjdXJyeSQoZiwgYm91bmQpe1xuICB2YXIgY29udGV4dCxcbiAgX2N1cnJ5ID0gZnVuY3Rpb24oYXJncykge1xuICAgIHJldHVybiBmLmxlbmd0aCA+IDEgPyBmdW5jdGlvbigpe1xuICAgICAgdmFyIHBhcmFtcyA9IGFyZ3MgPyBhcmdzLmNvbmNhdCgpIDogW107XG4gICAgICBjb250ZXh0ID0gYm91bmQgPyBjb250ZXh0IHx8IHRoaXMgOiB0aGlzO1xuICAgICAgcmV0dXJuIHBhcmFtcy5wdXNoLmFwcGx5KHBhcmFtcywgYXJndW1lbnRzKSA8XG4gICAgICAgICAgZi5sZW5ndGggJiYgYXJndW1lbnRzLmxlbmd0aCA/XG4gICAgICAgIF9jdXJyeS5jYWxsKGNvbnRleHQsIHBhcmFtcykgOiBmLmFwcGx5KGNvbnRleHQsIHBhcmFtcyk7XG4gICAgfSA6IGY7XG4gIH07XG4gIHJldHVybiBfY3VycnkoKTtcbn0iLCIvLyBHZW5lcmF0ZWQgYnkgTGl2ZVNjcmlwdCAxLjYuMFxudmFyIGVhY2gsIG1hcCwgY29tcGFjdCwgZmlsdGVyLCByZWplY3QsIHJlbW92ZSwgcGFydGl0aW9uLCBmaW5kLCBoZWFkLCBmaXJzdCwgdGFpbCwgbGFzdCwgaW5pdGlhbCwgZW1wdHksIHJldmVyc2UsIHVuaXF1ZSwgdW5pcXVlQnksIGZvbGQsIGZvbGRsLCBmb2xkMSwgZm9sZGwxLCBmb2xkciwgZm9sZHIxLCB1bmZvbGRyLCBjb25jYXQsIGNvbmNhdE1hcCwgZmxhdHRlbiwgZGlmZmVyZW5jZSwgaW50ZXJzZWN0aW9uLCB1bmlvbiwgY291bnRCeSwgZ3JvdXBCeSwgYW5kTGlzdCwgb3JMaXN0LCBhbnksIGFsbCwgc29ydCwgc29ydFdpdGgsIHNvcnRCeSwgc3VtLCBwcm9kdWN0LCBtZWFuLCBhdmVyYWdlLCBtYXhpbXVtLCBtaW5pbXVtLCBtYXhpbXVtQnksIG1pbmltdW1CeSwgc2Nhbiwgc2NhbmwsIHNjYW4xLCBzY2FubDEsIHNjYW5yLCBzY2FucjEsIHNsaWNlLCB0YWtlLCBkcm9wLCBzcGxpdEF0LCB0YWtlV2hpbGUsIGRyb3BXaGlsZSwgc3BhbiwgYnJlYWtMaXN0LCB6aXAsIHppcFdpdGgsIHppcEFsbCwgemlwQWxsV2l0aCwgYXQsIGVsZW1JbmRleCwgZWxlbUluZGljZXMsIGZpbmRJbmRleCwgZmluZEluZGljZXMsIHRvU3RyaW5nJCA9IHt9LnRvU3RyaW5nO1xuZWFjaCA9IGN1cnJ5JChmdW5jdGlvbihmLCB4cyl7XG4gIHZhciBpJCwgbGVuJCwgeDtcbiAgZm9yIChpJCA9IDAsIGxlbiQgPSB4cy5sZW5ndGg7IGkkIDwgbGVuJDsgKytpJCkge1xuICAgIHggPSB4c1tpJF07XG4gICAgZih4KTtcbiAgfVxuICByZXR1cm4geHM7XG59KTtcbm1hcCA9IGN1cnJ5JChmdW5jdGlvbihmLCB4cyl7XG4gIHZhciBpJCwgbGVuJCwgeCwgcmVzdWx0cyQgPSBbXTtcbiAgZm9yIChpJCA9IDAsIGxlbiQgPSB4cy5sZW5ndGg7IGkkIDwgbGVuJDsgKytpJCkge1xuICAgIHggPSB4c1tpJF07XG4gICAgcmVzdWx0cyQucHVzaChmKHgpKTtcbiAgfVxuICByZXR1cm4gcmVzdWx0cyQ7XG59KTtcbmNvbXBhY3QgPSBmdW5jdGlvbih4cyl7XG4gIHZhciBpJCwgbGVuJCwgeCwgcmVzdWx0cyQgPSBbXTtcbiAgZm9yIChpJCA9IDAsIGxlbiQgPSB4cy5sZW5ndGg7IGkkIDwgbGVuJDsgKytpJCkge1xuICAgIHggPSB4c1tpJF07XG4gICAgaWYgKHgpIHtcbiAgICAgIHJlc3VsdHMkLnB1c2goeCk7XG4gICAgfVxuICB9XG4gIHJldHVybiByZXN1bHRzJDtcbn07XG5maWx0ZXIgPSBjdXJyeSQoZnVuY3Rpb24oZiwgeHMpe1xuICB2YXIgaSQsIGxlbiQsIHgsIHJlc3VsdHMkID0gW107XG4gIGZvciAoaSQgPSAwLCBsZW4kID0geHMubGVuZ3RoOyBpJCA8IGxlbiQ7ICsraSQpIHtcbiAgICB4ID0geHNbaSRdO1xuICAgIGlmIChmKHgpKSB7XG4gICAgICByZXN1bHRzJC5wdXNoKHgpO1xuICAgIH1cbiAgfVxuICByZXR1cm4gcmVzdWx0cyQ7XG59KTtcbnJlamVjdCA9IGN1cnJ5JChmdW5jdGlvbihmLCB4cyl7XG4gIHZhciBpJCwgbGVuJCwgeCwgcmVzdWx0cyQgPSBbXTtcbiAgZm9yIChpJCA9IDAsIGxlbiQgPSB4cy5sZW5ndGg7IGkkIDwgbGVuJDsgKytpJCkge1xuICAgIHggPSB4c1tpJF07XG4gICAgaWYgKCFmKHgpKSB7XG4gICAgICByZXN1bHRzJC5wdXNoKHgpO1xuICAgIH1cbiAgfVxuICByZXR1cm4gcmVzdWx0cyQ7XG59KTtcbnJlbW92ZSA9IGN1cnJ5JChmdW5jdGlvbihlbCwgeHMpe1xuICB2YXIgaSwgeCQ7XG4gIGkgPSBlbGVtSW5kZXgoZWwsIHhzKTtcbiAgeCQgPSB4cy5zbGljZSgpO1xuICBpZiAoaSAhPSBudWxsKSB7XG4gICAgeCQuc3BsaWNlKGksIDEpO1xuICB9XG4gIHJldHVybiB4JDtcbn0pO1xucGFydGl0aW9uID0gY3VycnkkKGZ1bmN0aW9uKGYsIHhzKXtcbiAgdmFyIHBhc3NlZCwgZmFpbGVkLCBpJCwgbGVuJCwgeDtcbiAgcGFzc2VkID0gW107XG4gIGZhaWxlZCA9IFtdO1xuICBmb3IgKGkkID0gMCwgbGVuJCA9IHhzLmxlbmd0aDsgaSQgPCBsZW4kOyArK2kkKSB7XG4gICAgeCA9IHhzW2kkXTtcbiAgICAoZih4KSA/IHBhc3NlZCA6IGZhaWxlZCkucHVzaCh4KTtcbiAgfVxuICByZXR1cm4gW3Bhc3NlZCwgZmFpbGVkXTtcbn0pO1xuZmluZCA9IGN1cnJ5JChmdW5jdGlvbihmLCB4cyl7XG4gIHZhciBpJCwgbGVuJCwgeDtcbiAgZm9yIChpJCA9IDAsIGxlbiQgPSB4cy5sZW5ndGg7IGkkIDwgbGVuJDsgKytpJCkge1xuICAgIHggPSB4c1tpJF07XG4gICAgaWYgKGYoeCkpIHtcbiAgICAgIHJldHVybiB4O1xuICAgIH1cbiAgfVxufSk7XG5oZWFkID0gZmlyc3QgPSBmdW5jdGlvbih4cyl7XG4gIHJldHVybiB4c1swXTtcbn07XG50YWlsID0gZnVuY3Rpb24oeHMpe1xuICBpZiAoIXhzLmxlbmd0aCkge1xuICAgIHJldHVybjtcbiAgfVxuICByZXR1cm4geHMuc2xpY2UoMSk7XG59O1xubGFzdCA9IGZ1bmN0aW9uKHhzKXtcbiAgcmV0dXJuIHhzW3hzLmxlbmd0aCAtIDFdO1xufTtcbmluaXRpYWwgPSBmdW5jdGlvbih4cyl7XG4gIGlmICgheHMubGVuZ3RoKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIHJldHVybiB4cy5zbGljZSgwLCAtMSk7XG59O1xuZW1wdHkgPSBmdW5jdGlvbih4cyl7XG4gIHJldHVybiAheHMubGVuZ3RoO1xufTtcbnJldmVyc2UgPSBmdW5jdGlvbih4cyl7XG4gIHJldHVybiB4cy5jb25jYXQoKS5yZXZlcnNlKCk7XG59O1xudW5pcXVlID0gZnVuY3Rpb24oeHMpe1xuICB2YXIgcmVzdWx0LCBpJCwgbGVuJCwgeDtcbiAgcmVzdWx0ID0gW107XG4gIGZvciAoaSQgPSAwLCBsZW4kID0geHMubGVuZ3RoOyBpJCA8IGxlbiQ7ICsraSQpIHtcbiAgICB4ID0geHNbaSRdO1xuICAgIGlmICghaW4kKHgsIHJlc3VsdCkpIHtcbiAgICAgIHJlc3VsdC5wdXNoKHgpO1xuICAgIH1cbiAgfVxuICByZXR1cm4gcmVzdWx0O1xufTtcbnVuaXF1ZUJ5ID0gY3VycnkkKGZ1bmN0aW9uKGYsIHhzKXtcbiAgdmFyIHNlZW4sIGkkLCBsZW4kLCB4LCB2YWwsIHJlc3VsdHMkID0gW107XG4gIHNlZW4gPSBbXTtcbiAgZm9yIChpJCA9IDAsIGxlbiQgPSB4cy5sZW5ndGg7IGkkIDwgbGVuJDsgKytpJCkge1xuICAgIHggPSB4c1tpJF07XG4gICAgdmFsID0gZih4KTtcbiAgICBpZiAoaW4kKHZhbCwgc2VlbikpIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICBzZWVuLnB1c2godmFsKTtcbiAgICByZXN1bHRzJC5wdXNoKHgpO1xuICB9XG4gIHJldHVybiByZXN1bHRzJDtcbn0pO1xuZm9sZCA9IGZvbGRsID0gY3VycnkkKGZ1bmN0aW9uKGYsIG1lbW8sIHhzKXtcbiAgdmFyIGkkLCBsZW4kLCB4O1xuICBmb3IgKGkkID0gMCwgbGVuJCA9IHhzLmxlbmd0aDsgaSQgPCBsZW4kOyArK2kkKSB7XG4gICAgeCA9IHhzW2kkXTtcbiAgICBtZW1vID0gZihtZW1vLCB4KTtcbiAgfVxuICByZXR1cm4gbWVtbztcbn0pO1xuZm9sZDEgPSBmb2xkbDEgPSBjdXJyeSQoZnVuY3Rpb24oZiwgeHMpe1xuICByZXR1cm4gZm9sZChmLCB4c1swXSwgeHMuc2xpY2UoMSkpO1xufSk7XG5mb2xkciA9IGN1cnJ5JChmdW5jdGlvbihmLCBtZW1vLCB4cyl7XG4gIHZhciBpJCwgeDtcbiAgZm9yIChpJCA9IHhzLmxlbmd0aCAtIDE7IGkkID49IDA7IC0taSQpIHtcbiAgICB4ID0geHNbaSRdO1xuICAgIG1lbW8gPSBmKHgsIG1lbW8pO1xuICB9XG4gIHJldHVybiBtZW1vO1xufSk7XG5mb2xkcjEgPSBjdXJyeSQoZnVuY3Rpb24oZiwgeHMpe1xuICByZXR1cm4gZm9sZHIoZiwgeHNbeHMubGVuZ3RoIC0gMV0sIHhzLnNsaWNlKDAsIC0xKSk7XG59KTtcbnVuZm9sZHIgPSBjdXJyeSQoZnVuY3Rpb24oZiwgYil7XG4gIHZhciByZXN1bHQsIHgsIHRoYXQ7XG4gIHJlc3VsdCA9IFtdO1xuICB4ID0gYjtcbiAgd2hpbGUgKCh0aGF0ID0gZih4KSkgIT0gbnVsbCkge1xuICAgIHJlc3VsdC5wdXNoKHRoYXRbMF0pO1xuICAgIHggPSB0aGF0WzFdO1xuICB9XG4gIHJldHVybiByZXN1bHQ7XG59KTtcbmNvbmNhdCA9IGZ1bmN0aW9uKHhzcyl7XG4gIHJldHVybiBbXS5jb25jYXQuYXBwbHkoW10sIHhzcyk7XG59O1xuY29uY2F0TWFwID0gY3VycnkkKGZ1bmN0aW9uKGYsIHhzKXtcbiAgdmFyIHg7XG4gIHJldHVybiBbXS5jb25jYXQuYXBwbHkoW10sIChmdW5jdGlvbigpe1xuICAgIHZhciBpJCwgcmVmJCwgbGVuJCwgcmVzdWx0cyQgPSBbXTtcbiAgICBmb3IgKGkkID0gMCwgbGVuJCA9IChyZWYkID0geHMpLmxlbmd0aDsgaSQgPCBsZW4kOyArK2kkKSB7XG4gICAgICB4ID0gcmVmJFtpJF07XG4gICAgICByZXN1bHRzJC5wdXNoKGYoeCkpO1xuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0cyQ7XG4gIH0oKSkpO1xufSk7XG5mbGF0dGVuID0gZnVuY3Rpb24oeHMpe1xuICB2YXIgeDtcbiAgcmV0dXJuIFtdLmNvbmNhdC5hcHBseShbXSwgKGZ1bmN0aW9uKCl7XG4gICAgdmFyIGkkLCByZWYkLCBsZW4kLCByZXN1bHRzJCA9IFtdO1xuICAgIGZvciAoaSQgPSAwLCBsZW4kID0gKHJlZiQgPSB4cykubGVuZ3RoOyBpJCA8IGxlbiQ7ICsraSQpIHtcbiAgICAgIHggPSByZWYkW2kkXTtcbiAgICAgIGlmICh0b1N0cmluZyQuY2FsbCh4KS5zbGljZSg4LCAtMSkgPT09ICdBcnJheScpIHtcbiAgICAgICAgcmVzdWx0cyQucHVzaChmbGF0dGVuKHgpKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJlc3VsdHMkLnB1c2goeCk7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiByZXN1bHRzJDtcbiAgfSgpKSk7XG59O1xuZGlmZmVyZW5jZSA9IGZ1bmN0aW9uKHhzKXtcbiAgdmFyIHlzcywgcmVzJCwgaSQsIHRvJCwgcmVzdWx0cywgbGVuJCwgeCwgaiQsIGxlbjEkLCB5cztcbiAgcmVzJCA9IFtdO1xuICBmb3IgKGkkID0gMSwgdG8kID0gYXJndW1lbnRzLmxlbmd0aDsgaSQgPCB0byQ7ICsraSQpIHtcbiAgICByZXMkLnB1c2goYXJndW1lbnRzW2kkXSk7XG4gIH1cbiAgeXNzID0gcmVzJDtcbiAgcmVzdWx0cyA9IFtdO1xuICBvdXRlcjogZm9yIChpJCA9IDAsIGxlbiQgPSB4cy5sZW5ndGg7IGkkIDwgbGVuJDsgKytpJCkge1xuICAgIHggPSB4c1tpJF07XG4gICAgZm9yIChqJCA9IDAsIGxlbjEkID0geXNzLmxlbmd0aDsgaiQgPCBsZW4xJDsgKytqJCkge1xuICAgICAgeXMgPSB5c3NbaiRdO1xuICAgICAgaWYgKGluJCh4LCB5cykpIHtcbiAgICAgICAgY29udGludWUgb3V0ZXI7XG4gICAgICB9XG4gICAgfVxuICAgIHJlc3VsdHMucHVzaCh4KTtcbiAgfVxuICByZXR1cm4gcmVzdWx0cztcbn07XG5pbnRlcnNlY3Rpb24gPSBmdW5jdGlvbih4cyl7XG4gIHZhciB5c3MsIHJlcyQsIGkkLCB0byQsIHJlc3VsdHMsIGxlbiQsIHgsIGokLCBsZW4xJCwgeXM7XG4gIHJlcyQgPSBbXTtcbiAgZm9yIChpJCA9IDEsIHRvJCA9IGFyZ3VtZW50cy5sZW5ndGg7IGkkIDwgdG8kOyArK2kkKSB7XG4gICAgcmVzJC5wdXNoKGFyZ3VtZW50c1tpJF0pO1xuICB9XG4gIHlzcyA9IHJlcyQ7XG4gIHJlc3VsdHMgPSBbXTtcbiAgb3V0ZXI6IGZvciAoaSQgPSAwLCBsZW4kID0geHMubGVuZ3RoOyBpJCA8IGxlbiQ7ICsraSQpIHtcbiAgICB4ID0geHNbaSRdO1xuICAgIGZvciAoaiQgPSAwLCBsZW4xJCA9IHlzcy5sZW5ndGg7IGokIDwgbGVuMSQ7ICsraiQpIHtcbiAgICAgIHlzID0geXNzW2okXTtcbiAgICAgIGlmICghaW4kKHgsIHlzKSkge1xuICAgICAgICBjb250aW51ZSBvdXRlcjtcbiAgICAgIH1cbiAgICB9XG4gICAgcmVzdWx0cy5wdXNoKHgpO1xuICB9XG4gIHJldHVybiByZXN1bHRzO1xufTtcbnVuaW9uID0gZnVuY3Rpb24oKXtcbiAgdmFyIHhzcywgcmVzJCwgaSQsIHRvJCwgcmVzdWx0cywgbGVuJCwgeHMsIGokLCBsZW4xJCwgeDtcbiAgcmVzJCA9IFtdO1xuICBmb3IgKGkkID0gMCwgdG8kID0gYXJndW1lbnRzLmxlbmd0aDsgaSQgPCB0byQ7ICsraSQpIHtcbiAgICByZXMkLnB1c2goYXJndW1lbnRzW2kkXSk7XG4gIH1cbiAgeHNzID0gcmVzJDtcbiAgcmVzdWx0cyA9IFtdO1xuICBmb3IgKGkkID0gMCwgbGVuJCA9IHhzcy5sZW5ndGg7IGkkIDwgbGVuJDsgKytpJCkge1xuICAgIHhzID0geHNzW2kkXTtcbiAgICBmb3IgKGokID0gMCwgbGVuMSQgPSB4cy5sZW5ndGg7IGokIDwgbGVuMSQ7ICsraiQpIHtcbiAgICAgIHggPSB4c1tqJF07XG4gICAgICBpZiAoIWluJCh4LCByZXN1bHRzKSkge1xuICAgICAgICByZXN1bHRzLnB1c2goeCk7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIHJldHVybiByZXN1bHRzO1xufTtcbmNvdW50QnkgPSBjdXJyeSQoZnVuY3Rpb24oZiwgeHMpe1xuICB2YXIgcmVzdWx0cywgaSQsIGxlbiQsIHgsIGtleTtcbiAgcmVzdWx0cyA9IHt9O1xuICBmb3IgKGkkID0gMCwgbGVuJCA9IHhzLmxlbmd0aDsgaSQgPCBsZW4kOyArK2kkKSB7XG4gICAgeCA9IHhzW2kkXTtcbiAgICBrZXkgPSBmKHgpO1xuICAgIGlmIChrZXkgaW4gcmVzdWx0cykge1xuICAgICAgcmVzdWx0c1trZXldICs9IDE7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJlc3VsdHNba2V5XSA9IDE7XG4gICAgfVxuICB9XG4gIHJldHVybiByZXN1bHRzO1xufSk7XG5ncm91cEJ5ID0gY3VycnkkKGZ1bmN0aW9uKGYsIHhzKXtcbiAgdmFyIHJlc3VsdHMsIGkkLCBsZW4kLCB4LCBrZXk7XG4gIHJlc3VsdHMgPSB7fTtcbiAgZm9yIChpJCA9IDAsIGxlbiQgPSB4cy5sZW5ndGg7IGkkIDwgbGVuJDsgKytpJCkge1xuICAgIHggPSB4c1tpJF07XG4gICAga2V5ID0gZih4KTtcbiAgICBpZiAoa2V5IGluIHJlc3VsdHMpIHtcbiAgICAgIHJlc3VsdHNba2V5XS5wdXNoKHgpO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXN1bHRzW2tleV0gPSBbeF07XG4gICAgfVxuICB9XG4gIHJldHVybiByZXN1bHRzO1xufSk7XG5hbmRMaXN0ID0gZnVuY3Rpb24oeHMpe1xuICB2YXIgaSQsIGxlbiQsIHg7XG4gIGZvciAoaSQgPSAwLCBsZW4kID0geHMubGVuZ3RoOyBpJCA8IGxlbiQ7ICsraSQpIHtcbiAgICB4ID0geHNbaSRdO1xuICAgIGlmICgheCkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgfVxuICByZXR1cm4gdHJ1ZTtcbn07XG5vckxpc3QgPSBmdW5jdGlvbih4cyl7XG4gIHZhciBpJCwgbGVuJCwgeDtcbiAgZm9yIChpJCA9IDAsIGxlbiQgPSB4cy5sZW5ndGg7IGkkIDwgbGVuJDsgKytpJCkge1xuICAgIHggPSB4c1tpJF07XG4gICAgaWYgKHgpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgfVxuICByZXR1cm4gZmFsc2U7XG59O1xuYW55ID0gY3VycnkkKGZ1bmN0aW9uKGYsIHhzKXtcbiAgdmFyIGkkLCBsZW4kLCB4O1xuICBmb3IgKGkkID0gMCwgbGVuJCA9IHhzLmxlbmd0aDsgaSQgPCBsZW4kOyArK2kkKSB7XG4gICAgeCA9IHhzW2kkXTtcbiAgICBpZiAoZih4KSkge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICB9XG4gIHJldHVybiBmYWxzZTtcbn0pO1xuYWxsID0gY3VycnkkKGZ1bmN0aW9uKGYsIHhzKXtcbiAgdmFyIGkkLCBsZW4kLCB4O1xuICBmb3IgKGkkID0gMCwgbGVuJCA9IHhzLmxlbmd0aDsgaSQgPCBsZW4kOyArK2kkKSB7XG4gICAgeCA9IHhzW2kkXTtcbiAgICBpZiAoIWYoeCkpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHRydWU7XG59KTtcbnNvcnQgPSBmdW5jdGlvbih4cyl7XG4gIHJldHVybiB4cy5jb25jYXQoKS5zb3J0KGZ1bmN0aW9uKHgsIHkpe1xuICAgIGlmICh4ID4geSkge1xuICAgICAgcmV0dXJuIDE7XG4gICAgfSBlbHNlIGlmICh4IDwgeSkge1xuICAgICAgcmV0dXJuIC0xO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gMDtcbiAgICB9XG4gIH0pO1xufTtcbnNvcnRXaXRoID0gY3VycnkkKGZ1bmN0aW9uKGYsIHhzKXtcbiAgcmV0dXJuIHhzLmNvbmNhdCgpLnNvcnQoZik7XG59KTtcbnNvcnRCeSA9IGN1cnJ5JChmdW5jdGlvbihmLCB4cyl7XG4gIHJldHVybiB4cy5jb25jYXQoKS5zb3J0KGZ1bmN0aW9uKHgsIHkpe1xuICAgIGlmIChmKHgpID4gZih5KSkge1xuICAgICAgcmV0dXJuIDE7XG4gICAgfSBlbHNlIGlmIChmKHgpIDwgZih5KSkge1xuICAgICAgcmV0dXJuIC0xO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gMDtcbiAgICB9XG4gIH0pO1xufSk7XG5zdW0gPSBmdW5jdGlvbih4cyl7XG4gIHZhciByZXN1bHQsIGkkLCBsZW4kLCB4O1xuICByZXN1bHQgPSAwO1xuICBmb3IgKGkkID0gMCwgbGVuJCA9IHhzLmxlbmd0aDsgaSQgPCBsZW4kOyArK2kkKSB7XG4gICAgeCA9IHhzW2kkXTtcbiAgICByZXN1bHQgKz0geDtcbiAgfVxuICByZXR1cm4gcmVzdWx0O1xufTtcbnByb2R1Y3QgPSBmdW5jdGlvbih4cyl7XG4gIHZhciByZXN1bHQsIGkkLCBsZW4kLCB4O1xuICByZXN1bHQgPSAxO1xuICBmb3IgKGkkID0gMCwgbGVuJCA9IHhzLmxlbmd0aDsgaSQgPCBsZW4kOyArK2kkKSB7XG4gICAgeCA9IHhzW2kkXTtcbiAgICByZXN1bHQgKj0geDtcbiAgfVxuICByZXR1cm4gcmVzdWx0O1xufTtcbm1lYW4gPSBhdmVyYWdlID0gZnVuY3Rpb24oeHMpe1xuICB2YXIgc3VtLCBpJCwgbGVuJCwgeDtcbiAgc3VtID0gMDtcbiAgZm9yIChpJCA9IDAsIGxlbiQgPSB4cy5sZW5ndGg7IGkkIDwgbGVuJDsgKytpJCkge1xuICAgIHggPSB4c1tpJF07XG4gICAgc3VtICs9IHg7XG4gIH1cbiAgcmV0dXJuIHN1bSAvIHhzLmxlbmd0aDtcbn07XG5tYXhpbXVtID0gZnVuY3Rpb24oeHMpe1xuICB2YXIgbWF4LCBpJCwgcmVmJCwgbGVuJCwgeDtcbiAgbWF4ID0geHNbMF07XG4gIGZvciAoaSQgPSAwLCBsZW4kID0gKHJlZiQgPSB4cy5zbGljZSgxKSkubGVuZ3RoOyBpJCA8IGxlbiQ7ICsraSQpIHtcbiAgICB4ID0gcmVmJFtpJF07XG4gICAgaWYgKHggPiBtYXgpIHtcbiAgICAgIG1heCA9IHg7XG4gICAgfVxuICB9XG4gIHJldHVybiBtYXg7XG59O1xubWluaW11bSA9IGZ1bmN0aW9uKHhzKXtcbiAgdmFyIG1pbiwgaSQsIHJlZiQsIGxlbiQsIHg7XG4gIG1pbiA9IHhzWzBdO1xuICBmb3IgKGkkID0gMCwgbGVuJCA9IChyZWYkID0geHMuc2xpY2UoMSkpLmxlbmd0aDsgaSQgPCBsZW4kOyArK2kkKSB7XG4gICAgeCA9IHJlZiRbaSRdO1xuICAgIGlmICh4IDwgbWluKSB7XG4gICAgICBtaW4gPSB4O1xuICAgIH1cbiAgfVxuICByZXR1cm4gbWluO1xufTtcbm1heGltdW1CeSA9IGN1cnJ5JChmdW5jdGlvbihmLCB4cyl7XG4gIHZhciBtYXgsIGkkLCByZWYkLCBsZW4kLCB4O1xuICBtYXggPSB4c1swXTtcbiAgZm9yIChpJCA9IDAsIGxlbiQgPSAocmVmJCA9IHhzLnNsaWNlKDEpKS5sZW5ndGg7IGkkIDwgbGVuJDsgKytpJCkge1xuICAgIHggPSByZWYkW2kkXTtcbiAgICBpZiAoZih4KSA+IGYobWF4KSkge1xuICAgICAgbWF4ID0geDtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIG1heDtcbn0pO1xubWluaW11bUJ5ID0gY3VycnkkKGZ1bmN0aW9uKGYsIHhzKXtcbiAgdmFyIG1pbiwgaSQsIHJlZiQsIGxlbiQsIHg7XG4gIG1pbiA9IHhzWzBdO1xuICBmb3IgKGkkID0gMCwgbGVuJCA9IChyZWYkID0geHMuc2xpY2UoMSkpLmxlbmd0aDsgaSQgPCBsZW4kOyArK2kkKSB7XG4gICAgeCA9IHJlZiRbaSRdO1xuICAgIGlmIChmKHgpIDwgZihtaW4pKSB7XG4gICAgICBtaW4gPSB4O1xuICAgIH1cbiAgfVxuICByZXR1cm4gbWluO1xufSk7XG5zY2FuID0gc2NhbmwgPSBjdXJyeSQoZnVuY3Rpb24oZiwgbWVtbywgeHMpe1xuICB2YXIgbGFzdCwgeDtcbiAgbGFzdCA9IG1lbW87XG4gIHJldHVybiBbbWVtb10uY29uY2F0KChmdW5jdGlvbigpe1xuICAgIHZhciBpJCwgcmVmJCwgbGVuJCwgcmVzdWx0cyQgPSBbXTtcbiAgICBmb3IgKGkkID0gMCwgbGVuJCA9IChyZWYkID0geHMpLmxlbmd0aDsgaSQgPCBsZW4kOyArK2kkKSB7XG4gICAgICB4ID0gcmVmJFtpJF07XG4gICAgICByZXN1bHRzJC5wdXNoKGxhc3QgPSBmKGxhc3QsIHgpKTtcbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdHMkO1xuICB9KCkpKTtcbn0pO1xuc2NhbjEgPSBzY2FubDEgPSBjdXJyeSQoZnVuY3Rpb24oZiwgeHMpe1xuICBpZiAoIXhzLmxlbmd0aCkge1xuICAgIHJldHVybjtcbiAgfVxuICByZXR1cm4gc2NhbihmLCB4c1swXSwgeHMuc2xpY2UoMSkpO1xufSk7XG5zY2FuciA9IGN1cnJ5JChmdW5jdGlvbihmLCBtZW1vLCB4cyl7XG4gIHhzID0geHMuY29uY2F0KCkucmV2ZXJzZSgpO1xuICByZXR1cm4gc2NhbihmLCBtZW1vLCB4cykucmV2ZXJzZSgpO1xufSk7XG5zY2FucjEgPSBjdXJyeSQoZnVuY3Rpb24oZiwgeHMpe1xuICBpZiAoIXhzLmxlbmd0aCkge1xuICAgIHJldHVybjtcbiAgfVxuICB4cyA9IHhzLmNvbmNhdCgpLnJldmVyc2UoKTtcbiAgcmV0dXJuIHNjYW4oZiwgeHNbMF0sIHhzLnNsaWNlKDEpKS5yZXZlcnNlKCk7XG59KTtcbnNsaWNlID0gY3VycnkkKGZ1bmN0aW9uKHgsIHksIHhzKXtcbiAgcmV0dXJuIHhzLnNsaWNlKHgsIHkpO1xufSk7XG50YWtlID0gY3VycnkkKGZ1bmN0aW9uKG4sIHhzKXtcbiAgaWYgKG4gPD0gMCkge1xuICAgIHJldHVybiB4cy5zbGljZSgwLCAwKTtcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4geHMuc2xpY2UoMCwgbik7XG4gIH1cbn0pO1xuZHJvcCA9IGN1cnJ5JChmdW5jdGlvbihuLCB4cyl7XG4gIGlmIChuIDw9IDApIHtcbiAgICByZXR1cm4geHM7XG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIHhzLnNsaWNlKG4pO1xuICB9XG59KTtcbnNwbGl0QXQgPSBjdXJyeSQoZnVuY3Rpb24obiwgeHMpe1xuICByZXR1cm4gW3Rha2UobiwgeHMpLCBkcm9wKG4sIHhzKV07XG59KTtcbnRha2VXaGlsZSA9IGN1cnJ5JChmdW5jdGlvbihwLCB4cyl7XG4gIHZhciBsZW4sIGk7XG4gIGxlbiA9IHhzLmxlbmd0aDtcbiAgaWYgKCFsZW4pIHtcbiAgICByZXR1cm4geHM7XG4gIH1cbiAgaSA9IDA7XG4gIHdoaWxlIChpIDwgbGVuICYmIHAoeHNbaV0pKSB7XG4gICAgaSArPSAxO1xuICB9XG4gIHJldHVybiB4cy5zbGljZSgwLCBpKTtcbn0pO1xuZHJvcFdoaWxlID0gY3VycnkkKGZ1bmN0aW9uKHAsIHhzKXtcbiAgdmFyIGxlbiwgaTtcbiAgbGVuID0geHMubGVuZ3RoO1xuICBpZiAoIWxlbikge1xuICAgIHJldHVybiB4cztcbiAgfVxuICBpID0gMDtcbiAgd2hpbGUgKGkgPCBsZW4gJiYgcCh4c1tpXSkpIHtcbiAgICBpICs9IDE7XG4gIH1cbiAgcmV0dXJuIHhzLnNsaWNlKGkpO1xufSk7XG5zcGFuID0gY3VycnkkKGZ1bmN0aW9uKHAsIHhzKXtcbiAgcmV0dXJuIFt0YWtlV2hpbGUocCwgeHMpLCBkcm9wV2hpbGUocCwgeHMpXTtcbn0pO1xuYnJlYWtMaXN0ID0gY3VycnkkKGZ1bmN0aW9uKHAsIHhzKXtcbiAgcmV0dXJuIHNwYW4oY29tcG9zZSQocCwgbm90JCksIHhzKTtcbn0pO1xuemlwID0gY3VycnkkKGZ1bmN0aW9uKHhzLCB5cyl7XG4gIHZhciByZXN1bHQsIGxlbiwgaSQsIGxlbiQsIGksIHg7XG4gIHJlc3VsdCA9IFtdO1xuICBsZW4gPSB5cy5sZW5ndGg7XG4gIGZvciAoaSQgPSAwLCBsZW4kID0geHMubGVuZ3RoOyBpJCA8IGxlbiQ7ICsraSQpIHtcbiAgICBpID0gaSQ7XG4gICAgeCA9IHhzW2kkXTtcbiAgICBpZiAoaSA9PT0gbGVuKSB7XG4gICAgICBicmVhaztcbiAgICB9XG4gICAgcmVzdWx0LnB1c2goW3gsIHlzW2ldXSk7XG4gIH1cbiAgcmV0dXJuIHJlc3VsdDtcbn0pO1xuemlwV2l0aCA9IGN1cnJ5JChmdW5jdGlvbihmLCB4cywgeXMpe1xuICB2YXIgcmVzdWx0LCBsZW4sIGkkLCBsZW4kLCBpLCB4O1xuICByZXN1bHQgPSBbXTtcbiAgbGVuID0geXMubGVuZ3RoO1xuICBmb3IgKGkkID0gMCwgbGVuJCA9IHhzLmxlbmd0aDsgaSQgPCBsZW4kOyArK2kkKSB7XG4gICAgaSA9IGkkO1xuICAgIHggPSB4c1tpJF07XG4gICAgaWYgKGkgPT09IGxlbikge1xuICAgICAgYnJlYWs7XG4gICAgfVxuICAgIHJlc3VsdC5wdXNoKGYoeCwgeXNbaV0pKTtcbiAgfVxuICByZXR1cm4gcmVzdWx0O1xufSk7XG56aXBBbGwgPSBmdW5jdGlvbigpe1xuICB2YXIgeHNzLCByZXMkLCBpJCwgdG8kLCBtaW5MZW5ndGgsIGxlbiQsIHhzLCByZWYkLCBpLCBscmVzdWx0JCwgaiQsIHJlc3VsdHMkID0gW107XG4gIHJlcyQgPSBbXTtcbiAgZm9yIChpJCA9IDAsIHRvJCA9IGFyZ3VtZW50cy5sZW5ndGg7IGkkIDwgdG8kOyArK2kkKSB7XG4gICAgcmVzJC5wdXNoKGFyZ3VtZW50c1tpJF0pO1xuICB9XG4gIHhzcyA9IHJlcyQ7XG4gIG1pbkxlbmd0aCA9IHVuZGVmaW5lZDtcbiAgZm9yIChpJCA9IDAsIGxlbiQgPSB4c3MubGVuZ3RoOyBpJCA8IGxlbiQ7ICsraSQpIHtcbiAgICB4cyA9IHhzc1tpJF07XG4gICAgbWluTGVuZ3RoIDw9IChyZWYkID0geHMubGVuZ3RoKSB8fCAobWluTGVuZ3RoID0gcmVmJCk7XG4gIH1cbiAgZm9yIChpJCA9IDA7IGkkIDwgbWluTGVuZ3RoOyArK2kkKSB7XG4gICAgaSA9IGkkO1xuICAgIGxyZXN1bHQkID0gW107XG4gICAgZm9yIChqJCA9IDAsIGxlbiQgPSB4c3MubGVuZ3RoOyBqJCA8IGxlbiQ7ICsraiQpIHtcbiAgICAgIHhzID0geHNzW2okXTtcbiAgICAgIGxyZXN1bHQkLnB1c2goeHNbaV0pO1xuICAgIH1cbiAgICByZXN1bHRzJC5wdXNoKGxyZXN1bHQkKTtcbiAgfVxuICByZXR1cm4gcmVzdWx0cyQ7XG59O1xuemlwQWxsV2l0aCA9IGZ1bmN0aW9uKGYpe1xuICB2YXIgeHNzLCByZXMkLCBpJCwgdG8kLCBtaW5MZW5ndGgsIGxlbiQsIHhzLCByZWYkLCBpLCByZXN1bHRzJCA9IFtdO1xuICByZXMkID0gW107XG4gIGZvciAoaSQgPSAxLCB0byQgPSBhcmd1bWVudHMubGVuZ3RoOyBpJCA8IHRvJDsgKytpJCkge1xuICAgIHJlcyQucHVzaChhcmd1bWVudHNbaSRdKTtcbiAgfVxuICB4c3MgPSByZXMkO1xuICBtaW5MZW5ndGggPSB1bmRlZmluZWQ7XG4gIGZvciAoaSQgPSAwLCBsZW4kID0geHNzLmxlbmd0aDsgaSQgPCBsZW4kOyArK2kkKSB7XG4gICAgeHMgPSB4c3NbaSRdO1xuICAgIG1pbkxlbmd0aCA8PSAocmVmJCA9IHhzLmxlbmd0aCkgfHwgKG1pbkxlbmd0aCA9IHJlZiQpO1xuICB9XG4gIGZvciAoaSQgPSAwOyBpJCA8IG1pbkxlbmd0aDsgKytpJCkge1xuICAgIGkgPSBpJDtcbiAgICByZXN1bHRzJC5wdXNoKGYuYXBwbHkobnVsbCwgKGZuJCgpKSkpO1xuICB9XG4gIHJldHVybiByZXN1bHRzJDtcbiAgZnVuY3Rpb24gZm4kKCl7XG4gICAgdmFyIGkkLCByZWYkLCBsZW4kLCByZXN1bHRzJCA9IFtdO1xuICAgIGZvciAoaSQgPSAwLCBsZW4kID0gKHJlZiQgPSB4c3MpLmxlbmd0aDsgaSQgPCBsZW4kOyArK2kkKSB7XG4gICAgICB4cyA9IHJlZiRbaSRdO1xuICAgICAgcmVzdWx0cyQucHVzaCh4c1tpXSk7XG4gICAgfVxuICAgIHJldHVybiByZXN1bHRzJDtcbiAgfVxufTtcbmF0ID0gY3VycnkkKGZ1bmN0aW9uKG4sIHhzKXtcbiAgaWYgKG4gPCAwKSB7XG4gICAgcmV0dXJuIHhzW3hzLmxlbmd0aCArIG5dO1xuICB9IGVsc2Uge1xuICAgIHJldHVybiB4c1tuXTtcbiAgfVxufSk7XG5lbGVtSW5kZXggPSBjdXJyeSQoZnVuY3Rpb24oZWwsIHhzKXtcbiAgdmFyIGkkLCBsZW4kLCBpLCB4O1xuICBmb3IgKGkkID0gMCwgbGVuJCA9IHhzLmxlbmd0aDsgaSQgPCBsZW4kOyArK2kkKSB7XG4gICAgaSA9IGkkO1xuICAgIHggPSB4c1tpJF07XG4gICAgaWYgKHggPT09IGVsKSB7XG4gICAgICByZXR1cm4gaTtcbiAgICB9XG4gIH1cbn0pO1xuZWxlbUluZGljZXMgPSBjdXJyeSQoZnVuY3Rpb24oZWwsIHhzKXtcbiAgdmFyIGkkLCBsZW4kLCBpLCB4LCByZXN1bHRzJCA9IFtdO1xuICBmb3IgKGkkID0gMCwgbGVuJCA9IHhzLmxlbmd0aDsgaSQgPCBsZW4kOyArK2kkKSB7XG4gICAgaSA9IGkkO1xuICAgIHggPSB4c1tpJF07XG4gICAgaWYgKHggPT09IGVsKSB7XG4gICAgICByZXN1bHRzJC5wdXNoKGkpO1xuICAgIH1cbiAgfVxuICByZXR1cm4gcmVzdWx0cyQ7XG59KTtcbmZpbmRJbmRleCA9IGN1cnJ5JChmdW5jdGlvbihmLCB4cyl7XG4gIHZhciBpJCwgbGVuJCwgaSwgeDtcbiAgZm9yIChpJCA9IDAsIGxlbiQgPSB4cy5sZW5ndGg7IGkkIDwgbGVuJDsgKytpJCkge1xuICAgIGkgPSBpJDtcbiAgICB4ID0geHNbaSRdO1xuICAgIGlmIChmKHgpKSB7XG4gICAgICByZXR1cm4gaTtcbiAgICB9XG4gIH1cbn0pO1xuZmluZEluZGljZXMgPSBjdXJyeSQoZnVuY3Rpb24oZiwgeHMpe1xuICB2YXIgaSQsIGxlbiQsIGksIHgsIHJlc3VsdHMkID0gW107XG4gIGZvciAoaSQgPSAwLCBsZW4kID0geHMubGVuZ3RoOyBpJCA8IGxlbiQ7ICsraSQpIHtcbiAgICBpID0gaSQ7XG4gICAgeCA9IHhzW2kkXTtcbiAgICBpZiAoZih4KSkge1xuICAgICAgcmVzdWx0cyQucHVzaChpKTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHJlc3VsdHMkO1xufSk7XG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgZWFjaDogZWFjaCxcbiAgbWFwOiBtYXAsXG4gIGZpbHRlcjogZmlsdGVyLFxuICBjb21wYWN0OiBjb21wYWN0LFxuICByZWplY3Q6IHJlamVjdCxcbiAgcmVtb3ZlOiByZW1vdmUsXG4gIHBhcnRpdGlvbjogcGFydGl0aW9uLFxuICBmaW5kOiBmaW5kLFxuICBoZWFkOiBoZWFkLFxuICBmaXJzdDogZmlyc3QsXG4gIHRhaWw6IHRhaWwsXG4gIGxhc3Q6IGxhc3QsXG4gIGluaXRpYWw6IGluaXRpYWwsXG4gIGVtcHR5OiBlbXB0eSxcbiAgcmV2ZXJzZTogcmV2ZXJzZSxcbiAgZGlmZmVyZW5jZTogZGlmZmVyZW5jZSxcbiAgaW50ZXJzZWN0aW9uOiBpbnRlcnNlY3Rpb24sXG4gIHVuaW9uOiB1bmlvbixcbiAgY291bnRCeTogY291bnRCeSxcbiAgZ3JvdXBCeTogZ3JvdXBCeSxcbiAgZm9sZDogZm9sZCxcbiAgZm9sZDE6IGZvbGQxLFxuICBmb2xkbDogZm9sZGwsXG4gIGZvbGRsMTogZm9sZGwxLFxuICBmb2xkcjogZm9sZHIsXG4gIGZvbGRyMTogZm9sZHIxLFxuICB1bmZvbGRyOiB1bmZvbGRyLFxuICBhbmRMaXN0OiBhbmRMaXN0LFxuICBvckxpc3Q6IG9yTGlzdCxcbiAgYW55OiBhbnksXG4gIGFsbDogYWxsLFxuICB1bmlxdWU6IHVuaXF1ZSxcbiAgdW5pcXVlQnk6IHVuaXF1ZUJ5LFxuICBzb3J0OiBzb3J0LFxuICBzb3J0V2l0aDogc29ydFdpdGgsXG4gIHNvcnRCeTogc29ydEJ5LFxuICBzdW06IHN1bSxcbiAgcHJvZHVjdDogcHJvZHVjdCxcbiAgbWVhbjogbWVhbixcbiAgYXZlcmFnZTogYXZlcmFnZSxcbiAgY29uY2F0OiBjb25jYXQsXG4gIGNvbmNhdE1hcDogY29uY2F0TWFwLFxuICBmbGF0dGVuOiBmbGF0dGVuLFxuICBtYXhpbXVtOiBtYXhpbXVtLFxuICBtaW5pbXVtOiBtaW5pbXVtLFxuICBtYXhpbXVtQnk6IG1heGltdW1CeSxcbiAgbWluaW11bUJ5OiBtaW5pbXVtQnksXG4gIHNjYW46IHNjYW4sXG4gIHNjYW4xOiBzY2FuMSxcbiAgc2Nhbmw6IHNjYW5sLFxuICBzY2FubDE6IHNjYW5sMSxcbiAgc2NhbnI6IHNjYW5yLFxuICBzY2FucjE6IHNjYW5yMSxcbiAgc2xpY2U6IHNsaWNlLFxuICB0YWtlOiB0YWtlLFxuICBkcm9wOiBkcm9wLFxuICBzcGxpdEF0OiBzcGxpdEF0LFxuICB0YWtlV2hpbGU6IHRha2VXaGlsZSxcbiAgZHJvcFdoaWxlOiBkcm9wV2hpbGUsXG4gIHNwYW46IHNwYW4sXG4gIGJyZWFrTGlzdDogYnJlYWtMaXN0LFxuICB6aXA6IHppcCxcbiAgemlwV2l0aDogemlwV2l0aCxcbiAgemlwQWxsOiB6aXBBbGwsXG4gIHppcEFsbFdpdGg6IHppcEFsbFdpdGgsXG4gIGF0OiBhdCxcbiAgZWxlbUluZGV4OiBlbGVtSW5kZXgsXG4gIGVsZW1JbmRpY2VzOiBlbGVtSW5kaWNlcyxcbiAgZmluZEluZGV4OiBmaW5kSW5kZXgsXG4gIGZpbmRJbmRpY2VzOiBmaW5kSW5kaWNlc1xufTtcbmZ1bmN0aW9uIGN1cnJ5JChmLCBib3VuZCl7XG4gIHZhciBjb250ZXh0LFxuICBfY3VycnkgPSBmdW5jdGlvbihhcmdzKSB7XG4gICAgcmV0dXJuIGYubGVuZ3RoID4gMSA/IGZ1bmN0aW9uKCl7XG4gICAgICB2YXIgcGFyYW1zID0gYXJncyA/IGFyZ3MuY29uY2F0KCkgOiBbXTtcbiAgICAgIGNvbnRleHQgPSBib3VuZCA/IGNvbnRleHQgfHwgdGhpcyA6IHRoaXM7XG4gICAgICByZXR1cm4gcGFyYW1zLnB1c2guYXBwbHkocGFyYW1zLCBhcmd1bWVudHMpIDxcbiAgICAgICAgICBmLmxlbmd0aCAmJiBhcmd1bWVudHMubGVuZ3RoID9cbiAgICAgICAgX2N1cnJ5LmNhbGwoY29udGV4dCwgcGFyYW1zKSA6IGYuYXBwbHkoY29udGV4dCwgcGFyYW1zKTtcbiAgICB9IDogZjtcbiAgfTtcbiAgcmV0dXJuIF9jdXJyeSgpO1xufVxuZnVuY3Rpb24gaW4kKHgsIHhzKXtcbiAgdmFyIGkgPSAtMSwgbCA9IHhzLmxlbmd0aCA+Pj4gMDtcbiAgd2hpbGUgKCsraSA8IGwpIGlmICh4ID09PSB4c1tpXSkgcmV0dXJuIHRydWU7XG4gIHJldHVybiBmYWxzZTtcbn1cbmZ1bmN0aW9uIGNvbXBvc2UkKCkge1xuICB2YXIgZnVuY3Rpb25zID0gYXJndW1lbnRzO1xuICByZXR1cm4gZnVuY3Rpb24oKSB7XG4gICAgdmFyIGksIHJlc3VsdDtcbiAgICByZXN1bHQgPSBmdW5jdGlvbnNbMF0uYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICBmb3IgKGkgPSAxOyBpIDwgZnVuY3Rpb25zLmxlbmd0aDsgKytpKSB7XG4gICAgICByZXN1bHQgPSBmdW5jdGlvbnNbaV0ocmVzdWx0KTtcbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfTtcbn1cbmZ1bmN0aW9uIG5vdCQoeCl7IHJldHVybiAheDsgfSIsIi8vIEdlbmVyYXRlZCBieSBMaXZlU2NyaXB0IDEuNi4wXG52YXIgdmFsdWVzLCBrZXlzLCBwYWlyc1RvT2JqLCBvYmpUb1BhaXJzLCBsaXN0c1RvT2JqLCBvYmpUb0xpc3RzLCBlbXB0eSwgZWFjaCwgbWFwLCBjb21wYWN0LCBmaWx0ZXIsIHJlamVjdCwgcGFydGl0aW9uLCBmaW5kO1xudmFsdWVzID0gZnVuY3Rpb24ob2JqZWN0KXtcbiAgdmFyIGkkLCB4LCByZXN1bHRzJCA9IFtdO1xuICBmb3IgKGkkIGluIG9iamVjdCkge1xuICAgIHggPSBvYmplY3RbaSRdO1xuICAgIHJlc3VsdHMkLnB1c2goeCk7XG4gIH1cbiAgcmV0dXJuIHJlc3VsdHMkO1xufTtcbmtleXMgPSBmdW5jdGlvbihvYmplY3Qpe1xuICB2YXIgeCwgcmVzdWx0cyQgPSBbXTtcbiAgZm9yICh4IGluIG9iamVjdCkge1xuICAgIHJlc3VsdHMkLnB1c2goeCk7XG4gIH1cbiAgcmV0dXJuIHJlc3VsdHMkO1xufTtcbnBhaXJzVG9PYmogPSBmdW5jdGlvbihvYmplY3Qpe1xuICB2YXIgaSQsIGxlbiQsIHgsIHJlc3VsdE9iaiQgPSB7fTtcbiAgZm9yIChpJCA9IDAsIGxlbiQgPSBvYmplY3QubGVuZ3RoOyBpJCA8IGxlbiQ7ICsraSQpIHtcbiAgICB4ID0gb2JqZWN0W2kkXTtcbiAgICByZXN1bHRPYmokW3hbMF1dID0geFsxXTtcbiAgfVxuICByZXR1cm4gcmVzdWx0T2JqJDtcbn07XG5vYmpUb1BhaXJzID0gZnVuY3Rpb24ob2JqZWN0KXtcbiAgdmFyIGtleSwgdmFsdWUsIHJlc3VsdHMkID0gW107XG4gIGZvciAoa2V5IGluIG9iamVjdCkge1xuICAgIHZhbHVlID0gb2JqZWN0W2tleV07XG4gICAgcmVzdWx0cyQucHVzaChba2V5LCB2YWx1ZV0pO1xuICB9XG4gIHJldHVybiByZXN1bHRzJDtcbn07XG5saXN0c1RvT2JqID0gY3VycnkkKGZ1bmN0aW9uKGtleXMsIHZhbHVlcyl7XG4gIHZhciBpJCwgbGVuJCwgaSwga2V5LCByZXN1bHRPYmokID0ge307XG4gIGZvciAoaSQgPSAwLCBsZW4kID0ga2V5cy5sZW5ndGg7IGkkIDwgbGVuJDsgKytpJCkge1xuICAgIGkgPSBpJDtcbiAgICBrZXkgPSBrZXlzW2kkXTtcbiAgICByZXN1bHRPYmokW2tleV0gPSB2YWx1ZXNbaV07XG4gIH1cbiAgcmV0dXJuIHJlc3VsdE9iaiQ7XG59KTtcbm9ialRvTGlzdHMgPSBmdW5jdGlvbihvYmplY3Qpe1xuICB2YXIga2V5cywgdmFsdWVzLCBrZXksIHZhbHVlO1xuICBrZXlzID0gW107XG4gIHZhbHVlcyA9IFtdO1xuICBmb3IgKGtleSBpbiBvYmplY3QpIHtcbiAgICB2YWx1ZSA9IG9iamVjdFtrZXldO1xuICAgIGtleXMucHVzaChrZXkpO1xuICAgIHZhbHVlcy5wdXNoKHZhbHVlKTtcbiAgfVxuICByZXR1cm4gW2tleXMsIHZhbHVlc107XG59O1xuZW1wdHkgPSBmdW5jdGlvbihvYmplY3Qpe1xuICB2YXIgeDtcbiAgZm9yICh4IGluIG9iamVjdCkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuICByZXR1cm4gdHJ1ZTtcbn07XG5lYWNoID0gY3VycnkkKGZ1bmN0aW9uKGYsIG9iamVjdCl7XG4gIHZhciBpJCwgeDtcbiAgZm9yIChpJCBpbiBvYmplY3QpIHtcbiAgICB4ID0gb2JqZWN0W2kkXTtcbiAgICBmKHgpO1xuICB9XG4gIHJldHVybiBvYmplY3Q7XG59KTtcbm1hcCA9IGN1cnJ5JChmdW5jdGlvbihmLCBvYmplY3Qpe1xuICB2YXIgaywgeCwgcmVzdWx0T2JqJCA9IHt9O1xuICBmb3IgKGsgaW4gb2JqZWN0KSB7XG4gICAgeCA9IG9iamVjdFtrXTtcbiAgICByZXN1bHRPYmokW2tdID0gZih4KTtcbiAgfVxuICByZXR1cm4gcmVzdWx0T2JqJDtcbn0pO1xuY29tcGFjdCA9IGZ1bmN0aW9uKG9iamVjdCl7XG4gIHZhciBrLCB4LCByZXN1bHRPYmokID0ge307XG4gIGZvciAoayBpbiBvYmplY3QpIHtcbiAgICB4ID0gb2JqZWN0W2tdO1xuICAgIGlmICh4KSB7XG4gICAgICByZXN1bHRPYmokW2tdID0geDtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHJlc3VsdE9iaiQ7XG59O1xuZmlsdGVyID0gY3VycnkkKGZ1bmN0aW9uKGYsIG9iamVjdCl7XG4gIHZhciBrLCB4LCByZXN1bHRPYmokID0ge307XG4gIGZvciAoayBpbiBvYmplY3QpIHtcbiAgICB4ID0gb2JqZWN0W2tdO1xuICAgIGlmIChmKHgpKSB7XG4gICAgICByZXN1bHRPYmokW2tdID0geDtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHJlc3VsdE9iaiQ7XG59KTtcbnJlamVjdCA9IGN1cnJ5JChmdW5jdGlvbihmLCBvYmplY3Qpe1xuICB2YXIgaywgeCwgcmVzdWx0T2JqJCA9IHt9O1xuICBmb3IgKGsgaW4gb2JqZWN0KSB7XG4gICAgeCA9IG9iamVjdFtrXTtcbiAgICBpZiAoIWYoeCkpIHtcbiAgICAgIHJlc3VsdE9iaiRba10gPSB4O1xuICAgIH1cbiAgfVxuICByZXR1cm4gcmVzdWx0T2JqJDtcbn0pO1xucGFydGl0aW9uID0gY3VycnkkKGZ1bmN0aW9uKGYsIG9iamVjdCl7XG4gIHZhciBwYXNzZWQsIGZhaWxlZCwgaywgeDtcbiAgcGFzc2VkID0ge307XG4gIGZhaWxlZCA9IHt9O1xuICBmb3IgKGsgaW4gb2JqZWN0KSB7XG4gICAgeCA9IG9iamVjdFtrXTtcbiAgICAoZih4KSA/IHBhc3NlZCA6IGZhaWxlZClba10gPSB4O1xuICB9XG4gIHJldHVybiBbcGFzc2VkLCBmYWlsZWRdO1xufSk7XG5maW5kID0gY3VycnkkKGZ1bmN0aW9uKGYsIG9iamVjdCl7XG4gIHZhciBpJCwgeDtcbiAgZm9yIChpJCBpbiBvYmplY3QpIHtcbiAgICB4ID0gb2JqZWN0W2kkXTtcbiAgICBpZiAoZih4KSkge1xuICAgICAgcmV0dXJuIHg7XG4gICAgfVxuICB9XG59KTtcbm1vZHVsZS5leHBvcnRzID0ge1xuICB2YWx1ZXM6IHZhbHVlcyxcbiAga2V5czoga2V5cyxcbiAgcGFpcnNUb09iajogcGFpcnNUb09iaixcbiAgb2JqVG9QYWlyczogb2JqVG9QYWlycyxcbiAgbGlzdHNUb09iajogbGlzdHNUb09iaixcbiAgb2JqVG9MaXN0czogb2JqVG9MaXN0cyxcbiAgZW1wdHk6IGVtcHR5LFxuICBlYWNoOiBlYWNoLFxuICBtYXA6IG1hcCxcbiAgZmlsdGVyOiBmaWx0ZXIsXG4gIGNvbXBhY3Q6IGNvbXBhY3QsXG4gIHJlamVjdDogcmVqZWN0LFxuICBwYXJ0aXRpb246IHBhcnRpdGlvbixcbiAgZmluZDogZmluZFxufTtcbmZ1bmN0aW9uIGN1cnJ5JChmLCBib3VuZCl7XG4gIHZhciBjb250ZXh0LFxuICBfY3VycnkgPSBmdW5jdGlvbihhcmdzKSB7XG4gICAgcmV0dXJuIGYubGVuZ3RoID4gMSA/IGZ1bmN0aW9uKCl7XG4gICAgICB2YXIgcGFyYW1zID0gYXJncyA/IGFyZ3MuY29uY2F0KCkgOiBbXTtcbiAgICAgIGNvbnRleHQgPSBib3VuZCA/IGNvbnRleHQgfHwgdGhpcyA6IHRoaXM7XG4gICAgICByZXR1cm4gcGFyYW1zLnB1c2guYXBwbHkocGFyYW1zLCBhcmd1bWVudHMpIDxcbiAgICAgICAgICBmLmxlbmd0aCAmJiBhcmd1bWVudHMubGVuZ3RoID9cbiAgICAgICAgX2N1cnJ5LmNhbGwoY29udGV4dCwgcGFyYW1zKSA6IGYuYXBwbHkoY29udGV4dCwgcGFyYW1zKTtcbiAgICB9IDogZjtcbiAgfTtcbiAgcmV0dXJuIF9jdXJyeSgpO1xufSIsIi8vIEdlbmVyYXRlZCBieSBMaXZlU2NyaXB0IDEuNi4wXG52YXIgc3BsaXQsIGpvaW4sIGxpbmVzLCB1bmxpbmVzLCB3b3JkcywgdW53b3JkcywgY2hhcnMsIHVuY2hhcnMsIHJldmVyc2UsIHJlcGVhdCwgY2FwaXRhbGl6ZSwgY2FtZWxpemUsIGRhc2hlcml6ZTtcbnNwbGl0ID0gY3VycnkkKGZ1bmN0aW9uKHNlcCwgc3RyKXtcbiAgcmV0dXJuIHN0ci5zcGxpdChzZXApO1xufSk7XG5qb2luID0gY3VycnkkKGZ1bmN0aW9uKHNlcCwgeHMpe1xuICByZXR1cm4geHMuam9pbihzZXApO1xufSk7XG5saW5lcyA9IGZ1bmN0aW9uKHN0cil7XG4gIGlmICghc3RyLmxlbmd0aCkge1xuICAgIHJldHVybiBbXTtcbiAgfVxuICByZXR1cm4gc3RyLnNwbGl0KCdcXG4nKTtcbn07XG51bmxpbmVzID0gZnVuY3Rpb24oaXQpe1xuICByZXR1cm4gaXQuam9pbignXFxuJyk7XG59O1xud29yZHMgPSBmdW5jdGlvbihzdHIpe1xuICBpZiAoIXN0ci5sZW5ndGgpIHtcbiAgICByZXR1cm4gW107XG4gIH1cbiAgcmV0dXJuIHN0ci5zcGxpdCgvWyBdKy8pO1xufTtcbnVud29yZHMgPSBmdW5jdGlvbihpdCl7XG4gIHJldHVybiBpdC5qb2luKCcgJyk7XG59O1xuY2hhcnMgPSBmdW5jdGlvbihpdCl7XG4gIHJldHVybiBpdC5zcGxpdCgnJyk7XG59O1xudW5jaGFycyA9IGZ1bmN0aW9uKGl0KXtcbiAgcmV0dXJuIGl0LmpvaW4oJycpO1xufTtcbnJldmVyc2UgPSBmdW5jdGlvbihzdHIpe1xuICByZXR1cm4gc3RyLnNwbGl0KCcnKS5yZXZlcnNlKCkuam9pbignJyk7XG59O1xucmVwZWF0ID0gY3VycnkkKGZ1bmN0aW9uKG4sIHN0cil7XG4gIHZhciByZXN1bHQsIGkkO1xuICByZXN1bHQgPSAnJztcbiAgZm9yIChpJCA9IDA7IGkkIDwgbjsgKytpJCkge1xuICAgIHJlc3VsdCArPSBzdHI7XG4gIH1cbiAgcmV0dXJuIHJlc3VsdDtcbn0pO1xuY2FwaXRhbGl6ZSA9IGZ1bmN0aW9uKHN0cil7XG4gIHJldHVybiBzdHIuY2hhckF0KDApLnRvVXBwZXJDYXNlKCkgKyBzdHIuc2xpY2UoMSk7XG59O1xuY2FtZWxpemUgPSBmdW5jdGlvbihpdCl7XG4gIHJldHVybiBpdC5yZXBsYWNlKC9bLV9dKyguKT8vZywgZnVuY3Rpb24oYXJnJCwgYyl7XG4gICAgcmV0dXJuIChjICE9IG51bGwgPyBjIDogJycpLnRvVXBwZXJDYXNlKCk7XG4gIH0pO1xufTtcbmRhc2hlcml6ZSA9IGZ1bmN0aW9uKHN0cil7XG4gIHJldHVybiBzdHIucmVwbGFjZSgvKFteLUEtWl0pKFtBLVpdKykvZywgZnVuY3Rpb24oYXJnJCwgbG93ZXIsIHVwcGVyKXtcbiAgICByZXR1cm4gbG93ZXIgKyBcIi1cIiArICh1cHBlci5sZW5ndGggPiAxXG4gICAgICA/IHVwcGVyXG4gICAgICA6IHVwcGVyLnRvTG93ZXJDYXNlKCkpO1xuICB9KS5yZXBsYWNlKC9eKFtBLVpdKykvLCBmdW5jdGlvbihhcmckLCB1cHBlcil7XG4gICAgaWYgKHVwcGVyLmxlbmd0aCA+IDEpIHtcbiAgICAgIHJldHVybiB1cHBlciArIFwiLVwiO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gdXBwZXIudG9Mb3dlckNhc2UoKTtcbiAgICB9XG4gIH0pO1xufTtcbm1vZHVsZS5leHBvcnRzID0ge1xuICBzcGxpdDogc3BsaXQsXG4gIGpvaW46IGpvaW4sXG4gIGxpbmVzOiBsaW5lcyxcbiAgdW5saW5lczogdW5saW5lcyxcbiAgd29yZHM6IHdvcmRzLFxuICB1bndvcmRzOiB1bndvcmRzLFxuICBjaGFyczogY2hhcnMsXG4gIHVuY2hhcnM6IHVuY2hhcnMsXG4gIHJldmVyc2U6IHJldmVyc2UsXG4gIHJlcGVhdDogcmVwZWF0LFxuICBjYXBpdGFsaXplOiBjYXBpdGFsaXplLFxuICBjYW1lbGl6ZTogY2FtZWxpemUsXG4gIGRhc2hlcml6ZTogZGFzaGVyaXplXG59O1xuZnVuY3Rpb24gY3VycnkkKGYsIGJvdW5kKXtcbiAgdmFyIGNvbnRleHQsXG4gIF9jdXJyeSA9IGZ1bmN0aW9uKGFyZ3MpIHtcbiAgICByZXR1cm4gZi5sZW5ndGggPiAxID8gZnVuY3Rpb24oKXtcbiAgICAgIHZhciBwYXJhbXMgPSBhcmdzID8gYXJncy5jb25jYXQoKSA6IFtdO1xuICAgICAgY29udGV4dCA9IGJvdW5kID8gY29udGV4dCB8fCB0aGlzIDogdGhpcztcbiAgICAgIHJldHVybiBwYXJhbXMucHVzaC5hcHBseShwYXJhbXMsIGFyZ3VtZW50cykgPFxuICAgICAgICAgIGYubGVuZ3RoICYmIGFyZ3VtZW50cy5sZW5ndGggP1xuICAgICAgICBfY3VycnkuY2FsbChjb250ZXh0LCBwYXJhbXMpIDogZi5hcHBseShjb250ZXh0LCBwYXJhbXMpO1xuICAgIH0gOiBmO1xuICB9O1xuICByZXR1cm4gX2N1cnJ5KCk7XG59IiwiLy8gR2VuZXJhdGVkIGJ5IExpdmVTY3JpcHQgMS42LjBcbnZhciBtYXgsIG1pbiwgbmVnYXRlLCBhYnMsIHNpZ251bSwgcXVvdCwgcmVtLCBkaXYsIG1vZCwgcmVjaXAsIHBpLCB0YXUsIGV4cCwgc3FydCwgbG4sIHBvdywgc2luLCB0YW4sIGNvcywgYXNpbiwgYWNvcywgYXRhbiwgYXRhbjIsIHRydW5jYXRlLCByb3VuZCwgY2VpbGluZywgZmxvb3IsIGlzSXROYU4sIGV2ZW4sIG9kZCwgZ2NkLCBsY207XG5tYXggPSBjdXJyeSQoZnVuY3Rpb24oeCQsIHkkKXtcbiAgcmV0dXJuIHgkID4geSQgPyB4JCA6IHkkO1xufSk7XG5taW4gPSBjdXJyeSQoZnVuY3Rpb24oeCQsIHkkKXtcbiAgcmV0dXJuIHgkIDwgeSQgPyB4JCA6IHkkO1xufSk7XG5uZWdhdGUgPSBmdW5jdGlvbih4KXtcbiAgcmV0dXJuIC14O1xufTtcbmFicyA9IE1hdGguYWJzO1xuc2lnbnVtID0gZnVuY3Rpb24oeCl7XG4gIGlmICh4IDwgMCkge1xuICAgIHJldHVybiAtMTtcbiAgfSBlbHNlIGlmICh4ID4gMCkge1xuICAgIHJldHVybiAxO1xuICB9IGVsc2Uge1xuICAgIHJldHVybiAwO1xuICB9XG59O1xucXVvdCA9IGN1cnJ5JChmdW5jdGlvbih4LCB5KXtcbiAgcmV0dXJuIH5+KHggLyB5KTtcbn0pO1xucmVtID0gY3VycnkkKGZ1bmN0aW9uKHgkLCB5JCl7XG4gIHJldHVybiB4JCAlIHkkO1xufSk7XG5kaXYgPSBjdXJyeSQoZnVuY3Rpb24oeCwgeSl7XG4gIHJldHVybiBNYXRoLmZsb29yKHggLyB5KTtcbn0pO1xubW9kID0gY3VycnkkKGZ1bmN0aW9uKHgkLCB5JCl7XG4gIHZhciByZWYkO1xuICByZXR1cm4gKCh4JCkgJSAocmVmJCA9IHkkKSArIHJlZiQpICUgcmVmJDtcbn0pO1xucmVjaXAgPSAoZnVuY3Rpb24oaXQpe1xuICByZXR1cm4gMSAvIGl0O1xufSk7XG5waSA9IE1hdGguUEk7XG50YXUgPSBwaSAqIDI7XG5leHAgPSBNYXRoLmV4cDtcbnNxcnQgPSBNYXRoLnNxcnQ7XG5sbiA9IE1hdGgubG9nO1xucG93ID0gY3VycnkkKGZ1bmN0aW9uKHgkLCB5JCl7XG4gIHJldHVybiBNYXRoLnBvdyh4JCwgeSQpO1xufSk7XG5zaW4gPSBNYXRoLnNpbjtcbnRhbiA9IE1hdGgudGFuO1xuY29zID0gTWF0aC5jb3M7XG5hc2luID0gTWF0aC5hc2luO1xuYWNvcyA9IE1hdGguYWNvcztcbmF0YW4gPSBNYXRoLmF0YW47XG5hdGFuMiA9IGN1cnJ5JChmdW5jdGlvbih4LCB5KXtcbiAgcmV0dXJuIE1hdGguYXRhbjIoeCwgeSk7XG59KTtcbnRydW5jYXRlID0gZnVuY3Rpb24oeCl7XG4gIHJldHVybiB+fng7XG59O1xucm91bmQgPSBNYXRoLnJvdW5kO1xuY2VpbGluZyA9IE1hdGguY2VpbDtcbmZsb29yID0gTWF0aC5mbG9vcjtcbmlzSXROYU4gPSBmdW5jdGlvbih4KXtcbiAgcmV0dXJuIHggIT09IHg7XG59O1xuZXZlbiA9IGZ1bmN0aW9uKHgpe1xuICByZXR1cm4geCAlIDIgPT09IDA7XG59O1xub2RkID0gZnVuY3Rpb24oeCl7XG4gIHJldHVybiB4ICUgMiAhPT0gMDtcbn07XG5nY2QgPSBjdXJyeSQoZnVuY3Rpb24oeCwgeSl7XG4gIHZhciB6O1xuICB4ID0gTWF0aC5hYnMoeCk7XG4gIHkgPSBNYXRoLmFicyh5KTtcbiAgd2hpbGUgKHkgIT09IDApIHtcbiAgICB6ID0geCAlIHk7XG4gICAgeCA9IHk7XG4gICAgeSA9IHo7XG4gIH1cbiAgcmV0dXJuIHg7XG59KTtcbmxjbSA9IGN1cnJ5JChmdW5jdGlvbih4LCB5KXtcbiAgcmV0dXJuIE1hdGguYWJzKE1hdGguZmxvb3IoeCAvIGdjZCh4LCB5KSAqIHkpKTtcbn0pO1xubW9kdWxlLmV4cG9ydHMgPSB7XG4gIG1heDogbWF4LFxuICBtaW46IG1pbixcbiAgbmVnYXRlOiBuZWdhdGUsXG4gIGFiczogYWJzLFxuICBzaWdudW06IHNpZ251bSxcbiAgcXVvdDogcXVvdCxcbiAgcmVtOiByZW0sXG4gIGRpdjogZGl2LFxuICBtb2Q6IG1vZCxcbiAgcmVjaXA6IHJlY2lwLFxuICBwaTogcGksXG4gIHRhdTogdGF1LFxuICBleHA6IGV4cCxcbiAgc3FydDogc3FydCxcbiAgbG46IGxuLFxuICBwb3c6IHBvdyxcbiAgc2luOiBzaW4sXG4gIHRhbjogdGFuLFxuICBjb3M6IGNvcyxcbiAgYWNvczogYWNvcyxcbiAgYXNpbjogYXNpbixcbiAgYXRhbjogYXRhbixcbiAgYXRhbjI6IGF0YW4yLFxuICB0cnVuY2F0ZTogdHJ1bmNhdGUsXG4gIHJvdW5kOiByb3VuZCxcbiAgY2VpbGluZzogY2VpbGluZyxcbiAgZmxvb3I6IGZsb29yLFxuICBpc0l0TmFOOiBpc0l0TmFOLFxuICBldmVuOiBldmVuLFxuICBvZGQ6IG9kZCxcbiAgZ2NkOiBnY2QsXG4gIGxjbTogbGNtXG59O1xuZnVuY3Rpb24gY3VycnkkKGYsIGJvdW5kKXtcbiAgdmFyIGNvbnRleHQsXG4gIF9jdXJyeSA9IGZ1bmN0aW9uKGFyZ3MpIHtcbiAgICByZXR1cm4gZi5sZW5ndGggPiAxID8gZnVuY3Rpb24oKXtcbiAgICAgIHZhciBwYXJhbXMgPSBhcmdzID8gYXJncy5jb25jYXQoKSA6IFtdO1xuICAgICAgY29udGV4dCA9IGJvdW5kID8gY29udGV4dCB8fCB0aGlzIDogdGhpcztcbiAgICAgIHJldHVybiBwYXJhbXMucHVzaC5hcHBseShwYXJhbXMsIGFyZ3VtZW50cykgPFxuICAgICAgICAgIGYubGVuZ3RoICYmIGFyZ3VtZW50cy5sZW5ndGggP1xuICAgICAgICBfY3VycnkuY2FsbChjb250ZXh0LCBwYXJhbXMpIDogZi5hcHBseShjb250ZXh0LCBwYXJhbXMpO1xuICAgIH0gOiBmO1xuICB9O1xuICByZXR1cm4gX2N1cnJ5KCk7XG59IiwiLy8gR2VuZXJhdGVkIGJ5IExpdmVTY3JpcHQgMS42LjBcbnZhciBGdW5jLCBMaXN0LCBPYmosIFN0ciwgTnVtLCBpZCwgaXNUeXBlLCByZXBsaWNhdGUsIHByZWx1ZGUsIHRvU3RyaW5nJCA9IHt9LnRvU3RyaW5nO1xuRnVuYyA9IHJlcXVpcmUoJy4vRnVuYy5qcycpO1xuTGlzdCA9IHJlcXVpcmUoJy4vTGlzdC5qcycpO1xuT2JqID0gcmVxdWlyZSgnLi9PYmouanMnKTtcblN0ciA9IHJlcXVpcmUoJy4vU3RyLmpzJyk7XG5OdW0gPSByZXF1aXJlKCcuL051bS5qcycpO1xuaWQgPSBmdW5jdGlvbih4KXtcbiAgcmV0dXJuIHg7XG59O1xuaXNUeXBlID0gY3VycnkkKGZ1bmN0aW9uKHR5cGUsIHgpe1xuICByZXR1cm4gdG9TdHJpbmckLmNhbGwoeCkuc2xpY2UoOCwgLTEpID09PSB0eXBlO1xufSk7XG5yZXBsaWNhdGUgPSBjdXJyeSQoZnVuY3Rpb24obiwgeCl7XG4gIHZhciBpJCwgcmVzdWx0cyQgPSBbXTtcbiAgZm9yIChpJCA9IDA7IGkkIDwgbjsgKytpJCkge1xuICAgIHJlc3VsdHMkLnB1c2goeCk7XG4gIH1cbiAgcmV0dXJuIHJlc3VsdHMkO1xufSk7XG5TdHIuZW1wdHkgPSBMaXN0LmVtcHR5O1xuU3RyLnNsaWNlID0gTGlzdC5zbGljZTtcblN0ci50YWtlID0gTGlzdC50YWtlO1xuU3RyLmRyb3AgPSBMaXN0LmRyb3A7XG5TdHIuc3BsaXRBdCA9IExpc3Quc3BsaXRBdDtcblN0ci50YWtlV2hpbGUgPSBMaXN0LnRha2VXaGlsZTtcblN0ci5kcm9wV2hpbGUgPSBMaXN0LmRyb3BXaGlsZTtcblN0ci5zcGFuID0gTGlzdC5zcGFuO1xuU3RyLmJyZWFrU3RyID0gTGlzdC5icmVha0xpc3Q7XG5wcmVsdWRlID0ge1xuICBGdW5jOiBGdW5jLFxuICBMaXN0OiBMaXN0LFxuICBPYmo6IE9iaixcbiAgU3RyOiBTdHIsXG4gIE51bTogTnVtLFxuICBpZDogaWQsXG4gIGlzVHlwZTogaXNUeXBlLFxuICByZXBsaWNhdGU6IHJlcGxpY2F0ZVxufTtcbnByZWx1ZGUuZWFjaCA9IExpc3QuZWFjaDtcbnByZWx1ZGUubWFwID0gTGlzdC5tYXA7XG5wcmVsdWRlLmZpbHRlciA9IExpc3QuZmlsdGVyO1xucHJlbHVkZS5jb21wYWN0ID0gTGlzdC5jb21wYWN0O1xucHJlbHVkZS5yZWplY3QgPSBMaXN0LnJlamVjdDtcbnByZWx1ZGUucGFydGl0aW9uID0gTGlzdC5wYXJ0aXRpb247XG5wcmVsdWRlLmZpbmQgPSBMaXN0LmZpbmQ7XG5wcmVsdWRlLmhlYWQgPSBMaXN0LmhlYWQ7XG5wcmVsdWRlLmZpcnN0ID0gTGlzdC5maXJzdDtcbnByZWx1ZGUudGFpbCA9IExpc3QudGFpbDtcbnByZWx1ZGUubGFzdCA9IExpc3QubGFzdDtcbnByZWx1ZGUuaW5pdGlhbCA9IExpc3QuaW5pdGlhbDtcbnByZWx1ZGUuZW1wdHkgPSBMaXN0LmVtcHR5O1xucHJlbHVkZS5yZXZlcnNlID0gTGlzdC5yZXZlcnNlO1xucHJlbHVkZS5kaWZmZXJlbmNlID0gTGlzdC5kaWZmZXJlbmNlO1xucHJlbHVkZS5pbnRlcnNlY3Rpb24gPSBMaXN0LmludGVyc2VjdGlvbjtcbnByZWx1ZGUudW5pb24gPSBMaXN0LnVuaW9uO1xucHJlbHVkZS5jb3VudEJ5ID0gTGlzdC5jb3VudEJ5O1xucHJlbHVkZS5ncm91cEJ5ID0gTGlzdC5ncm91cEJ5O1xucHJlbHVkZS5mb2xkID0gTGlzdC5mb2xkO1xucHJlbHVkZS5mb2xkbCA9IExpc3QuZm9sZGw7XG5wcmVsdWRlLmZvbGQxID0gTGlzdC5mb2xkMTtcbnByZWx1ZGUuZm9sZGwxID0gTGlzdC5mb2xkbDE7XG5wcmVsdWRlLmZvbGRyID0gTGlzdC5mb2xkcjtcbnByZWx1ZGUuZm9sZHIxID0gTGlzdC5mb2xkcjE7XG5wcmVsdWRlLnVuZm9sZHIgPSBMaXN0LnVuZm9sZHI7XG5wcmVsdWRlLmFuZExpc3QgPSBMaXN0LmFuZExpc3Q7XG5wcmVsdWRlLm9yTGlzdCA9IExpc3Qub3JMaXN0O1xucHJlbHVkZS5hbnkgPSBMaXN0LmFueTtcbnByZWx1ZGUuYWxsID0gTGlzdC5hbGw7XG5wcmVsdWRlLnVuaXF1ZSA9IExpc3QudW5pcXVlO1xucHJlbHVkZS51bmlxdWVCeSA9IExpc3QudW5pcXVlQnk7XG5wcmVsdWRlLnNvcnQgPSBMaXN0LnNvcnQ7XG5wcmVsdWRlLnNvcnRXaXRoID0gTGlzdC5zb3J0V2l0aDtcbnByZWx1ZGUuc29ydEJ5ID0gTGlzdC5zb3J0Qnk7XG5wcmVsdWRlLnN1bSA9IExpc3Quc3VtO1xucHJlbHVkZS5wcm9kdWN0ID0gTGlzdC5wcm9kdWN0O1xucHJlbHVkZS5tZWFuID0gTGlzdC5tZWFuO1xucHJlbHVkZS5hdmVyYWdlID0gTGlzdC5hdmVyYWdlO1xucHJlbHVkZS5jb25jYXQgPSBMaXN0LmNvbmNhdDtcbnByZWx1ZGUuY29uY2F0TWFwID0gTGlzdC5jb25jYXRNYXA7XG5wcmVsdWRlLmZsYXR0ZW4gPSBMaXN0LmZsYXR0ZW47XG5wcmVsdWRlLm1heGltdW0gPSBMaXN0Lm1heGltdW07XG5wcmVsdWRlLm1pbmltdW0gPSBMaXN0Lm1pbmltdW07XG5wcmVsdWRlLm1heGltdW1CeSA9IExpc3QubWF4aW11bUJ5O1xucHJlbHVkZS5taW5pbXVtQnkgPSBMaXN0Lm1pbmltdW1CeTtcbnByZWx1ZGUuc2NhbiA9IExpc3Quc2NhbjtcbnByZWx1ZGUuc2NhbmwgPSBMaXN0LnNjYW5sO1xucHJlbHVkZS5zY2FuMSA9IExpc3Quc2NhbjE7XG5wcmVsdWRlLnNjYW5sMSA9IExpc3Quc2NhbmwxO1xucHJlbHVkZS5zY2FuciA9IExpc3Quc2NhbnI7XG5wcmVsdWRlLnNjYW5yMSA9IExpc3Quc2NhbnIxO1xucHJlbHVkZS5zbGljZSA9IExpc3Quc2xpY2U7XG5wcmVsdWRlLnRha2UgPSBMaXN0LnRha2U7XG5wcmVsdWRlLmRyb3AgPSBMaXN0LmRyb3A7XG5wcmVsdWRlLnNwbGl0QXQgPSBMaXN0LnNwbGl0QXQ7XG5wcmVsdWRlLnRha2VXaGlsZSA9IExpc3QudGFrZVdoaWxlO1xucHJlbHVkZS5kcm9wV2hpbGUgPSBMaXN0LmRyb3BXaGlsZTtcbnByZWx1ZGUuc3BhbiA9IExpc3Quc3BhbjtcbnByZWx1ZGUuYnJlYWtMaXN0ID0gTGlzdC5icmVha0xpc3Q7XG5wcmVsdWRlLnppcCA9IExpc3QuemlwO1xucHJlbHVkZS56aXBXaXRoID0gTGlzdC56aXBXaXRoO1xucHJlbHVkZS56aXBBbGwgPSBMaXN0LnppcEFsbDtcbnByZWx1ZGUuemlwQWxsV2l0aCA9IExpc3QuemlwQWxsV2l0aDtcbnByZWx1ZGUuYXQgPSBMaXN0LmF0O1xucHJlbHVkZS5lbGVtSW5kZXggPSBMaXN0LmVsZW1JbmRleDtcbnByZWx1ZGUuZWxlbUluZGljZXMgPSBMaXN0LmVsZW1JbmRpY2VzO1xucHJlbHVkZS5maW5kSW5kZXggPSBMaXN0LmZpbmRJbmRleDtcbnByZWx1ZGUuZmluZEluZGljZXMgPSBMaXN0LmZpbmRJbmRpY2VzO1xucHJlbHVkZS5hcHBseSA9IEZ1bmMuYXBwbHk7XG5wcmVsdWRlLmN1cnJ5ID0gRnVuYy5jdXJyeTtcbnByZWx1ZGUuZmxpcCA9IEZ1bmMuZmxpcDtcbnByZWx1ZGUuZml4ID0gRnVuYy5maXg7XG5wcmVsdWRlLm92ZXIgPSBGdW5jLm92ZXI7XG5wcmVsdWRlLnNwbGl0ID0gU3RyLnNwbGl0O1xucHJlbHVkZS5qb2luID0gU3RyLmpvaW47XG5wcmVsdWRlLmxpbmVzID0gU3RyLmxpbmVzO1xucHJlbHVkZS51bmxpbmVzID0gU3RyLnVubGluZXM7XG5wcmVsdWRlLndvcmRzID0gU3RyLndvcmRzO1xucHJlbHVkZS51bndvcmRzID0gU3RyLnVud29yZHM7XG5wcmVsdWRlLmNoYXJzID0gU3RyLmNoYXJzO1xucHJlbHVkZS51bmNoYXJzID0gU3RyLnVuY2hhcnM7XG5wcmVsdWRlLnJlcGVhdCA9IFN0ci5yZXBlYXQ7XG5wcmVsdWRlLmNhcGl0YWxpemUgPSBTdHIuY2FwaXRhbGl6ZTtcbnByZWx1ZGUuY2FtZWxpemUgPSBTdHIuY2FtZWxpemU7XG5wcmVsdWRlLmRhc2hlcml6ZSA9IFN0ci5kYXNoZXJpemU7XG5wcmVsdWRlLnZhbHVlcyA9IE9iai52YWx1ZXM7XG5wcmVsdWRlLmtleXMgPSBPYmoua2V5cztcbnByZWx1ZGUucGFpcnNUb09iaiA9IE9iai5wYWlyc1RvT2JqO1xucHJlbHVkZS5vYmpUb1BhaXJzID0gT2JqLm9ialRvUGFpcnM7XG5wcmVsdWRlLmxpc3RzVG9PYmogPSBPYmoubGlzdHNUb09iajtcbnByZWx1ZGUub2JqVG9MaXN0cyA9IE9iai5vYmpUb0xpc3RzO1xucHJlbHVkZS5tYXggPSBOdW0ubWF4O1xucHJlbHVkZS5taW4gPSBOdW0ubWluO1xucHJlbHVkZS5uZWdhdGUgPSBOdW0ubmVnYXRlO1xucHJlbHVkZS5hYnMgPSBOdW0uYWJzO1xucHJlbHVkZS5zaWdudW0gPSBOdW0uc2lnbnVtO1xucHJlbHVkZS5xdW90ID0gTnVtLnF1b3Q7XG5wcmVsdWRlLnJlbSA9IE51bS5yZW07XG5wcmVsdWRlLmRpdiA9IE51bS5kaXY7XG5wcmVsdWRlLm1vZCA9IE51bS5tb2Q7XG5wcmVsdWRlLnJlY2lwID0gTnVtLnJlY2lwO1xucHJlbHVkZS5waSA9IE51bS5waTtcbnByZWx1ZGUudGF1ID0gTnVtLnRhdTtcbnByZWx1ZGUuZXhwID0gTnVtLmV4cDtcbnByZWx1ZGUuc3FydCA9IE51bS5zcXJ0O1xucHJlbHVkZS5sbiA9IE51bS5sbjtcbnByZWx1ZGUucG93ID0gTnVtLnBvdztcbnByZWx1ZGUuc2luID0gTnVtLnNpbjtcbnByZWx1ZGUudGFuID0gTnVtLnRhbjtcbnByZWx1ZGUuY29zID0gTnVtLmNvcztcbnByZWx1ZGUuYWNvcyA9IE51bS5hY29zO1xucHJlbHVkZS5hc2luID0gTnVtLmFzaW47XG5wcmVsdWRlLmF0YW4gPSBOdW0uYXRhbjtcbnByZWx1ZGUuYXRhbjIgPSBOdW0uYXRhbjI7XG5wcmVsdWRlLnRydW5jYXRlID0gTnVtLnRydW5jYXRlO1xucHJlbHVkZS5yb3VuZCA9IE51bS5yb3VuZDtcbnByZWx1ZGUuY2VpbGluZyA9IE51bS5jZWlsaW5nO1xucHJlbHVkZS5mbG9vciA9IE51bS5mbG9vcjtcbnByZWx1ZGUuaXNJdE5hTiA9IE51bS5pc0l0TmFOO1xucHJlbHVkZS5ldmVuID0gTnVtLmV2ZW47XG5wcmVsdWRlLm9kZCA9IE51bS5vZGQ7XG5wcmVsdWRlLmdjZCA9IE51bS5nY2Q7XG5wcmVsdWRlLmxjbSA9IE51bS5sY207XG5wcmVsdWRlLlZFUlNJT04gPSAnMS4yLjEnO1xubW9kdWxlLmV4cG9ydHMgPSBwcmVsdWRlO1xuZnVuY3Rpb24gY3VycnkkKGYsIGJvdW5kKXtcbiAgdmFyIGNvbnRleHQsXG4gIF9jdXJyeSA9IGZ1bmN0aW9uKGFyZ3MpIHtcbiAgICByZXR1cm4gZi5sZW5ndGggPiAxID8gZnVuY3Rpb24oKXtcbiAgICAgIHZhciBwYXJhbXMgPSBhcmdzID8gYXJncy5jb25jYXQoKSA6IFtdO1xuICAgICAgY29udGV4dCA9IGJvdW5kID8gY29udGV4dCB8fCB0aGlzIDogdGhpcztcbiAgICAgIHJldHVybiBwYXJhbXMucHVzaC5hcHBseShwYXJhbXMsIGFyZ3VtZW50cykgPFxuICAgICAgICAgIGYubGVuZ3RoICYmIGFyZ3VtZW50cy5sZW5ndGggP1xuICAgICAgICBfY3VycnkuY2FsbChjb250ZXh0LCBwYXJhbXMpIDogZi5hcHBseShjb250ZXh0LCBwYXJhbXMpO1xuICAgIH0gOiBmO1xuICB9O1xuICByZXR1cm4gX2N1cnJ5KCk7XG59IiwicmVxdWlyZSEgJ3ByZWx1ZGUtbHMnOiB7cmVqZWN0LCBtYXhpbXVtLCBtYXB9XG5cblxuZXhwb3J0IGNsYXNzIEV2ZW50RW1pdHRlclxuICAgIC0+XG4gICAgICAgIEBfZXZlbnRzID0ge31cbiAgICAgICAgQF9vbmVfdGltZV9ldmVudHMgPSB7fVxuXG4gICAgb25jZTogKHR5cGUsIGNhbGxiYWNrKSAhLT5cbiAgICAgICAgYWRkLWxpc3RlbmVyID0gKHR5cGUsIGNhbGxiYWNrKSB+PlxuICAgICAgICAgICAgaWYgdHlwZW9mISBAX29uZV90aW1lX2V2ZW50c1t0eXBlXSBpc250IFxcQXJyYXlcbiAgICAgICAgICAgICAgICBAX29uZV90aW1lX2V2ZW50c1t0eXBlXSA9IFtdXG4gICAgICAgICAgICBAX29uZV90aW1lX2V2ZW50c1t0eXBlXS5wdXNoIGNhbGxiYWNrLmJpbmQgdGhpc1xuXG4gICAgICAgIHN3aXRjaCB0eXBlb2YhIHR5cGVcbiAgICAgICAgICAgIHdoZW4gXFxTdHJpbmcgPT5cbiAgICAgICAgICAgICAgICBhZGQtbGlzdGVuZXIgdHlwZSwgY2FsbGJhY2tcbiAgICAgICAgICAgIHdoZW4gXFxPYmplY3QgPT5cbiAgICAgICAgICAgICAgICBmb3IgbmFtZSwgY2FsbGJhY2sgb2YgdHlwZVxuICAgICAgICAgICAgICAgICAgICBhZGQtbGlzdGVuZXIgbmFtZSwgY2FsbGJhY2tcblxuXG4gICAgb246ICh0eXBlLCBpZCwgY2FsbGJhY2spIC0+XG4gICAgICAgIFwiXCJcIlxuICAgICAgICB1c2FnZTpcblxuICAgICAgICAgICAgd2l0aCBzaW1wbGUgc3RyaW5nIG5hbWU6XG5cbiAgICAgICAgICAgICAgICAub24gJ25hbWUnLCBmblxuXG4gICAgICAgICAgICBvciB3aXRoIGFuIG9iamVjdDpcblxuICAgICAgICAgICAgICAgIC5vbiBkb1xuICAgICAgICAgICAgICAgICAgICAnbmFtZTEnOiBmblxuICAgICAgICAgICAgICAgICAgICAnbmFtZTInOiBmbjJcbiAgICAgICAgXCJcIlwiXG4gICAgICAgIGlmIHR5cGVvZiEgaWQgaXMgXFxGdW5jdGlvblxuICAgICAgICAgICAgY2FsbGJhY2sgPSBpZFxuICAgICAgICAgICAgX2lkID0gWy4uaWQgZm9yIEBfZXZlbnRzXVxuICAgICAgICAgICAgICAgIHw+IG1hcCBwYXJzZS1pbnQgXG4gICAgICAgICAgICAgICAgfD4gbWF4aW11bSBcbiAgICAgICAgICAgIGlkID0gKF9pZCBvciAwKSArIDFcblxuICAgICAgICBhZGQtbGlzdGVuZXIgPSAodHlwZSwgaWQsIGNhbGxiYWNrKSB+PlxuICAgICAgICAgICAgQF9ldmVudHNbXVt0eXBlXS5wdXNoIHtpZCwgY2I6IGNhbGxiYWNrLmJpbmQgdGhpc31cbiAgICAgICAgICAgIHJldHVybiBcbiAgICAgICAgICAgICAgICBjYW5jZWw6IH4+IFxuICAgICAgICAgICAgICAgICAgICBAY2FuY2VsIGlkXG5cbiAgICAgICAgY29udHJvbCA9IG51bGwgXG4gICAgICAgIHN3aXRjaCB0eXBlb2YhIHR5cGVcbiAgICAgICAgICAgIHdoZW4gXFxTdHJpbmcgPT5cbiAgICAgICAgICAgICAgICBjb250cm9sID0gYWRkLWxpc3RlbmVyIHR5cGUsIGlkLCBjYWxsYmFja1xuICAgICAgICAgICAgd2hlbiBcXE9iamVjdCA9PlxuICAgICAgICAgICAgICAgIGZvciBuYW1lLCBjYWxsYmFjayBvZiB0eXBlXG4gICAgICAgICAgICAgICAgICAgIGFkZC1saXN0ZW5lciBuYW1lLCBpZCwgY2FsbGJhY2tcbiAgICAgICAgcmV0dXJuIGNvbnRyb2wgXG5cbiAgICBvZmY6ICh0eXBlKSAtPlxuICAgICAgICBAX2V2ZW50c1t0eXBlXSA9IFtdXG5cbiAgICBjYW5jZWw6IChpZCkgIS0+XG4gICAgICAgICMgcmVtb3ZlIGEgaGFuZGxlciB3aXRoIGEgc3BlY2lmaWMgaWQgZnJvbSBAX2V2ZW50c1xuICAgICAgICBmb3IgdHlwZSwgbGlzdGVuZXJzIG9mIEBfZXZlbnRzXG4gICAgICAgICAgICBmb3IgaSwgbGlzdGVuZXIgb2YgbGlzdGVuZXJzXG4gICAgICAgICAgICAgICAgaWYgbGlzdGVuZXIuaWQgaXMgaWRcbiAgICAgICAgICAgICAgICAgICAgbGlzdGVuZXJzLnNwbGljZSBpLCAxXG4gICAgICAgICAgICAgICAgICAgICNjb25zb2xlLmxvZyBcInJlbW92aW5nICN7aWR9IGZyb20gdHlwZTogI3t0eXBlfVwiXG4gICAgICAgICAgICAgICAgICAgIGJyZWFrXG5cbiAgICB0cmlnZ2VyOiAodHlwZSwgLi4uYXJncykgLT5cbiAgICAgICAgXCJcIlwiXG4gICAgICAgIHVzYWdlOlxuXG4gICAgICAgICAgICAudHJpZ2dlciBcImV2ZW50TmFtZVwiLCAuLi54XG5cbiAgICAgICAgXCJcIlwiXG4gICAgICAgIGlmIEBfZXZlbnRzW3R5cGVdXG4gICAgICAgICAgICBmb3IgbGV0IGhhbmRsZXIgaW4gdGhhdFxuICAgICAgICAgICAgICAgIDx+IHNldC1pbW1lZGlhdGVcbiAgICAgICAgICAgICAgICBoYW5kbGVyLmNiIC4uLmFyZ3NcblxuICAgICAgICBpZiBAX29uZV90aW1lX2V2ZW50c1t0eXBlXVxuICAgICAgICAgICAgZm9yIGkgaW4gWzEgdG8gdGhhdC5sZW5ndGhdXG4gICAgICAgICAgICAgICAgaGFuZGxlciA9IHRoYXQuc2hpZnQhXG4gICAgICAgICAgICAgICAgaGFuZGxlciAuLi5hcmdzXG5cbiAgICBoYXMtbGlzdGVuZXI6IChldikgLT5cbiAgICAgICAgaWYgQF9ldmVudHNbZXZdXG4gICAgICAgICAgICBmb3IgdGhhdFxuICAgICAgICAgICAgICAgIGlmIHR5cGVvZiEgLi5jYiBpcyBcXEZ1bmN0aW9uXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlXG4gICAgICAgIHJldHVybiBmYWxzZVxuIiwiIyBmb3IgZGVidWdnaW5nIHB1cnBvc2VzXG5yZXF1aXJlISBjb2xvcnM6IHtcbiAgICBncmVlbiwgZ3JheSwgeWVsbG93LCBtYWdlbnRhXG4gICAgYmctcmVkLCBiZy15ZWxsb3csIGN5YW4sIGJnLWN5YW4sIGJnLWdyZWVuXG59XG5yZXF1aXJlISBtb21lbnRcbnJlcXVpcmUhICdwcmVsdWRlLWxzJzoge21hcH1cbnJlcXVpcmUhICcuL2V2ZW50LWVtaXR0ZXInOiB7RXZlbnRFbWl0dGVyfVxuXG5cbk5FRURfU1RBQ0tfVFJBQ0UgPSBub1xuXG5mbXQgPSAnSEg6bW06c3MuU1NTJ1xuXG5zdGFydC10aW1lID0gbmV3IG1vbWVudFxuXG5hbGlnbi1sZWZ0ID0gKHdpZHRoLCBpbnApIC0+XG4gICAgeCA9IChpbnAgKyBcIiBcIiAqIHdpZHRoKS5zbGljZSAwLCB3aWR0aFxuXG5nZXQtdGltZXN0YW1wID0gLT5cbiAgICAjIGN1cnJlbnQgdGltZVxuICAgIChuZXcgbW9tZW50KS5mb3JtYXQgZm10XG5cbiAgICAjIGRpZmZlcmVudGlhbCB0aW1lXG4gICAgI21vbWVudC51dGMobW9tZW50KChuZXcgbW9tZW50KSwgZm10KS5kaWZmKG1vbWVudChzdGFydFRpbWUsIGZtdCkpKS5mb3JtYXQoZm10KVxuXG5nZXQtcHJlZml4ID0gKF9zb3VyY2UsIGNvbG9yKSAtPlxuICAgIGNvbG9yID0gZ3JheSB1bmxlc3MgY29sb3JcbiAgICBwYWRkZWQgPSBhbGlnbi1sZWZ0IDE1LCBcIiN7X3NvdXJjZX1cIlxuICAgIChjb2xvciBcIlsje2dldC10aW1lc3RhbXAhfV1cIikgKyBcIiAje3BhZGRlZH0gOlwiXG5cbklTX05PREUgPSBkbyAtPlxuICAgIGlzTm9kZSA9IG5vXG4gICAgaWYgdHlwZW9mIHByb2Nlc3MgaXMgXFxvYmplY3RcbiAgICAgICAgaWYgdHlwZW9mIHByb2Nlc3MudmVyc2lvbnMgaXMgXFxvYmplY3RcbiAgICAgICAgICAgIGlmIHR5cGVvZiBwcm9jZXNzLnZlcnNpb25zLm5vZGUgaXNudCBcXHVuZGVmaW5lZFxuICAgICAgICAgICAgICAgIGlzTm9kZSA9IHllc1xuICAgIHJldHVybiBpc05vZGVcblxuY2xhc3MgTG9nTWFuYWdlciBleHRlbmRzIEV2ZW50RW1pdHRlclxuICAgIEBAaW5zdGFuY2UgPSBudWxsXG4gICAgLT5cbiAgICAgICAgcmV0dXJuIEBAaW5zdGFuY2UgaWYgQEBpbnN0YW5jZVxuICAgICAgICBzdXBlciFcbiAgICAgICAgQEBpbnN0YW5jZSA6PSB0aGlzXG4gICAgICAgIEBsb2dnZXJzID0gW11cblxuICAgIHJlZ2lzdGVyOiAoY3R4KSAtPlxuICAgICAgICBAbG9nZ2Vycy5wdXNoIGN0eFxuXG5cbmV4cG9ydCBjbGFzcyBMb2dnZXIgZXh0ZW5kcyBFdmVudEVtaXR0ZXJcbiAgICAoc291cmNlLW5hbWUsIG9wdHM9e30pIC0+XG4gICAgICAgIHN1cGVyIVxuICAgICAgICBAbmFtZSA9IHNvdXJjZS1uYW1lXG4gICAgICAgIEBtZ3IgPSBuZXcgTG9nTWFuYWdlciFcbiAgICAgICAgQHByZWZpeCA9IG51bGxcbiAgICAgICAgQGVycm9yID0gQGVyclxuXG4gICAgZ2V0LXByZWZpeDogKGNvbG9yKSAtPlxuICAgICAgICBnZXQtcHJlZml4IChcIiN7aWYgQHByZWZpeCA9PiBcIiN7QHByZWZpeH0vXCIgZWxzZSAnJ30je0BuYW1lfVwiKSwgY29sb3JcblxuICAgIGxvZzogKC4uLmFyZ3MpIH4+XG4gICAgICAgIHByZWZpeCA9IGdldC1wcmVmaXggQG5hbWVcbiAgICAgICAgaWYgSVNfTk9ERVxuICAgICAgICAgICAgY29uc29sZS5sb2cuY2FsbCBjb25zb2xlLCBwcmVmaXgsIC4uLmFyZ3NcbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgX2FyZ3MgPSBbXVxuICAgICAgICAgICAgbXkgPSBcIiVjXCJcbiAgICAgICAgICAgIGZvciBhcmcgaW4gW3ByZWZpeF0gKysgYXJnc1xuICAgICAgICAgICAgICAgIF9hcmdzLnB1c2ggYXJnXG4gICAgICAgICAgICAgICAgbXkgKz0gXCIgXCIgKyBpZiB0eXBlb2YhIGFyZyBpcyBcXFN0cmluZ1xuICAgICAgICAgICAgICAgICAgICBcIiVzXCJcbiAgICAgICAgICAgICAgICBlbHNlIGlmIHR5cGVvZiEgYXJnIGlzIFxcTnVtYmVyXG4gICAgICAgICAgICAgICAgICAgIFwiJWRcIlxuICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAgXCIlT1wiXG5cbiAgICAgICAgICAgIGlmIE5FRURfU1RBQ0tfVFJBQ0VcbiAgICAgICAgICAgICAgICBjb25zb2xlLmdyb3VwLWNvbGxhcHNlZCBteSwgXCJmb250LXdlaWdodDogbm9ybWFsO1wiIC4uLl9hcmdzXG4gICAgICAgICAgICAgICAgY29uc29sZS50cmFjZSBwcmVmaXhcbiAgICAgICAgICAgICAgICBjb25zb2xlLmdyb3VwLWVuZCFcbiAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICBsb2cgPSBGdW5jdGlvbi5wcm90b3R5cGUuYmluZC5jYWxsKGNvbnNvbGUubG9nLCBjb25zb2xlKVxuICAgICAgICAgICAgICAgIGxvZy5jYWxsIGNvbnNvbGUsIG15LCBcImZvbnQtd2VpZ2h0OiBub3JtYWw7XCIgLi4uX2FyZ3NcblxuICAgIHN1Y2Nlc3M6ICguLi5hcmdzKSB+PlxuICAgICAgICBjb25zb2xlLmxvZy5hcHBseSBjb25zb2xlLCAoW0BnZXQtcHJlZml4IGJnLWdyZWVuXSArKyBhcmdzKVxuXG4gICAgZXJyOiAoLi4uYXJncykgfj5cbiAgICAgICAgY29uc29sZS5lcnJvci5hcHBseSBjb25zb2xlLCAoW0BnZXQtcHJlZml4IGJnLXJlZF0gKysgYXJncylcbiAgICAgICAgQHRyaWdnZXIgXFxlcnIsIC4uLmFyZ3NcbiAgICAgICAgQG1nci50cmlnZ2VyIFxcZXJyLCAuLi5hcmdzXG5cbiAgICB3YXJuOiAoLi4uYXJncykgfj5cbiAgICAgICAgY29uc29sZS53YXJuLmFwcGx5IGNvbnNvbGUsIFtAZ2V0LXByZWZpeChiZy15ZWxsb3cpLCB5ZWxsb3coJ1tXQVJOSU5HXScpXSArKyBhcmdzXG5cbiAgICBpbmZvOiAoLi4uYXJncykgfj5cbiAgICAgICAgY29uc29sZS5pbmZvLmFwcGx5IGNvbnNvbGUsIFtAZ2V0LXByZWZpeCEsIGN5YW4oJ1tJXScpXSArKyBhcmdzXG5cbiAgICB0b2RvOiAoLi4uYXJncykgfj5cbiAgICAgICAgY29uc29sZS53YXJuLmFwcGx5IGNvbnNvbGUsIFtAZ2V0LXByZWZpeCEsIG1hZ2VudGEoJ1tUT0RPXScpXSArKyBhcmdzXG5cbiAgICBkZWJ1ZzogKC4uLmFyZ3MpIH4+XG4gICAgICAgIGNvbnNvbGUud2Fybi5hcHBseSBjb25zb2xlLCBbQGdldC1wcmVmaXghLCB5ZWxsb3coJ1tEXScpXSArKyBhcmdzXG4iLCIoZnVuY3Rpb24gKGdsb2JhbCwgdW5kZWZpbmVkKSB7XG4gICAgXCJ1c2Ugc3RyaWN0XCI7XG5cbiAgICBpZiAoZ2xvYmFsLnNldEltbWVkaWF0ZSkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdmFyIG5leHRIYW5kbGUgPSAxOyAvLyBTcGVjIHNheXMgZ3JlYXRlciB0aGFuIHplcm9cbiAgICB2YXIgdGFza3NCeUhhbmRsZSA9IHt9O1xuICAgIHZhciBjdXJyZW50bHlSdW5uaW5nQVRhc2sgPSBmYWxzZTtcbiAgICB2YXIgZG9jID0gZ2xvYmFsLmRvY3VtZW50O1xuICAgIHZhciByZWdpc3RlckltbWVkaWF0ZTtcblxuICAgIGZ1bmN0aW9uIHNldEltbWVkaWF0ZShjYWxsYmFjaykge1xuICAgICAgLy8gQ2FsbGJhY2sgY2FuIGVpdGhlciBiZSBhIGZ1bmN0aW9uIG9yIGEgc3RyaW5nXG4gICAgICBpZiAodHlwZW9mIGNhbGxiYWNrICE9PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgY2FsbGJhY2sgPSBuZXcgRnVuY3Rpb24oXCJcIiArIGNhbGxiYWNrKTtcbiAgICAgIH1cbiAgICAgIC8vIENvcHkgZnVuY3Rpb24gYXJndW1lbnRzXG4gICAgICB2YXIgYXJncyA9IG5ldyBBcnJheShhcmd1bWVudHMubGVuZ3RoIC0gMSk7XG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGFyZ3MubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICBhcmdzW2ldID0gYXJndW1lbnRzW2kgKyAxXTtcbiAgICAgIH1cbiAgICAgIC8vIFN0b3JlIGFuZCByZWdpc3RlciB0aGUgdGFza1xuICAgICAgdmFyIHRhc2sgPSB7IGNhbGxiYWNrOiBjYWxsYmFjaywgYXJnczogYXJncyB9O1xuICAgICAgdGFza3NCeUhhbmRsZVtuZXh0SGFuZGxlXSA9IHRhc2s7XG4gICAgICByZWdpc3RlckltbWVkaWF0ZShuZXh0SGFuZGxlKTtcbiAgICAgIHJldHVybiBuZXh0SGFuZGxlKys7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gY2xlYXJJbW1lZGlhdGUoaGFuZGxlKSB7XG4gICAgICAgIGRlbGV0ZSB0YXNrc0J5SGFuZGxlW2hhbmRsZV07XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gcnVuKHRhc2spIHtcbiAgICAgICAgdmFyIGNhbGxiYWNrID0gdGFzay5jYWxsYmFjaztcbiAgICAgICAgdmFyIGFyZ3MgPSB0YXNrLmFyZ3M7XG4gICAgICAgIHN3aXRjaCAoYXJncy5sZW5ndGgpIHtcbiAgICAgICAgY2FzZSAwOlxuICAgICAgICAgICAgY2FsbGJhY2soKTtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIDE6XG4gICAgICAgICAgICBjYWxsYmFjayhhcmdzWzBdKTtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIDI6XG4gICAgICAgICAgICBjYWxsYmFjayhhcmdzWzBdLCBhcmdzWzFdKTtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIDM6XG4gICAgICAgICAgICBjYWxsYmFjayhhcmdzWzBdLCBhcmdzWzFdLCBhcmdzWzJdKTtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgY2FsbGJhY2suYXBwbHkodW5kZWZpbmVkLCBhcmdzKTtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gcnVuSWZQcmVzZW50KGhhbmRsZSkge1xuICAgICAgICAvLyBGcm9tIHRoZSBzcGVjOiBcIldhaXQgdW50aWwgYW55IGludm9jYXRpb25zIG9mIHRoaXMgYWxnb3JpdGhtIHN0YXJ0ZWQgYmVmb3JlIHRoaXMgb25lIGhhdmUgY29tcGxldGVkLlwiXG4gICAgICAgIC8vIFNvIGlmIHdlJ3JlIGN1cnJlbnRseSBydW5uaW5nIGEgdGFzaywgd2UnbGwgbmVlZCB0byBkZWxheSB0aGlzIGludm9jYXRpb24uXG4gICAgICAgIGlmIChjdXJyZW50bHlSdW5uaW5nQVRhc2spIHtcbiAgICAgICAgICAgIC8vIERlbGF5IGJ5IGRvaW5nIGEgc2V0VGltZW91dC4gc2V0SW1tZWRpYXRlIHdhcyB0cmllZCBpbnN0ZWFkLCBidXQgaW4gRmlyZWZveCA3IGl0IGdlbmVyYXRlZCBhXG4gICAgICAgICAgICAvLyBcInRvbyBtdWNoIHJlY3Vyc2lvblwiIGVycm9yLlxuICAgICAgICAgICAgc2V0VGltZW91dChydW5JZlByZXNlbnQsIDAsIGhhbmRsZSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB2YXIgdGFzayA9IHRhc2tzQnlIYW5kbGVbaGFuZGxlXTtcbiAgICAgICAgICAgIGlmICh0YXNrKSB7XG4gICAgICAgICAgICAgICAgY3VycmVudGx5UnVubmluZ0FUYXNrID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICBydW4odGFzayk7XG4gICAgICAgICAgICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgICAgICAgICAgICAgY2xlYXJJbW1lZGlhdGUoaGFuZGxlKTtcbiAgICAgICAgICAgICAgICAgICAgY3VycmVudGx5UnVubmluZ0FUYXNrID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gaW5zdGFsbE5leHRUaWNrSW1wbGVtZW50YXRpb24oKSB7XG4gICAgICAgIHJlZ2lzdGVySW1tZWRpYXRlID0gZnVuY3Rpb24oaGFuZGxlKSB7XG4gICAgICAgICAgICBwcm9jZXNzLm5leHRUaWNrKGZ1bmN0aW9uICgpIHsgcnVuSWZQcmVzZW50KGhhbmRsZSk7IH0pO1xuICAgICAgICB9O1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGNhblVzZVBvc3RNZXNzYWdlKCkge1xuICAgICAgICAvLyBUaGUgdGVzdCBhZ2FpbnN0IGBpbXBvcnRTY3JpcHRzYCBwcmV2ZW50cyB0aGlzIGltcGxlbWVudGF0aW9uIGZyb20gYmVpbmcgaW5zdGFsbGVkIGluc2lkZSBhIHdlYiB3b3JrZXIsXG4gICAgICAgIC8vIHdoZXJlIGBnbG9iYWwucG9zdE1lc3NhZ2VgIG1lYW5zIHNvbWV0aGluZyBjb21wbGV0ZWx5IGRpZmZlcmVudCBhbmQgY2FuJ3QgYmUgdXNlZCBmb3IgdGhpcyBwdXJwb3NlLlxuICAgICAgICBpZiAoZ2xvYmFsLnBvc3RNZXNzYWdlICYmICFnbG9iYWwuaW1wb3J0U2NyaXB0cykge1xuICAgICAgICAgICAgdmFyIHBvc3RNZXNzYWdlSXNBc3luY2hyb25vdXMgPSB0cnVlO1xuICAgICAgICAgICAgdmFyIG9sZE9uTWVzc2FnZSA9IGdsb2JhbC5vbm1lc3NhZ2U7XG4gICAgICAgICAgICBnbG9iYWwub25tZXNzYWdlID0gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgcG9zdE1lc3NhZ2VJc0FzeW5jaHJvbm91cyA9IGZhbHNlO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGdsb2JhbC5wb3N0TWVzc2FnZShcIlwiLCBcIipcIik7XG4gICAgICAgICAgICBnbG9iYWwub25tZXNzYWdlID0gb2xkT25NZXNzYWdlO1xuICAgICAgICAgICAgcmV0dXJuIHBvc3RNZXNzYWdlSXNBc3luY2hyb25vdXM7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiBpbnN0YWxsUG9zdE1lc3NhZ2VJbXBsZW1lbnRhdGlvbigpIHtcbiAgICAgICAgLy8gSW5zdGFsbHMgYW4gZXZlbnQgaGFuZGxlciBvbiBgZ2xvYmFsYCBmb3IgdGhlIGBtZXNzYWdlYCBldmVudDogc2VlXG4gICAgICAgIC8vICogaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4vRE9NL3dpbmRvdy5wb3N0TWVzc2FnZVxuICAgICAgICAvLyAqIGh0dHA6Ly93d3cud2hhdHdnLm9yZy9zcGVjcy93ZWItYXBwcy9jdXJyZW50LXdvcmsvbXVsdGlwYWdlL2NvbW1zLmh0bWwjY3Jvc3NEb2N1bWVudE1lc3NhZ2VzXG5cbiAgICAgICAgdmFyIG1lc3NhZ2VQcmVmaXggPSBcInNldEltbWVkaWF0ZSRcIiArIE1hdGgucmFuZG9tKCkgKyBcIiRcIjtcbiAgICAgICAgdmFyIG9uR2xvYmFsTWVzc2FnZSA9IGZ1bmN0aW9uKGV2ZW50KSB7XG4gICAgICAgICAgICBpZiAoZXZlbnQuc291cmNlID09PSBnbG9iYWwgJiZcbiAgICAgICAgICAgICAgICB0eXBlb2YgZXZlbnQuZGF0YSA9PT0gXCJzdHJpbmdcIiAmJlxuICAgICAgICAgICAgICAgIGV2ZW50LmRhdGEuaW5kZXhPZihtZXNzYWdlUHJlZml4KSA9PT0gMCkge1xuICAgICAgICAgICAgICAgIHJ1bklmUHJlc2VudCgrZXZlbnQuZGF0YS5zbGljZShtZXNzYWdlUHJlZml4Lmxlbmd0aCkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuXG4gICAgICAgIGlmIChnbG9iYWwuYWRkRXZlbnRMaXN0ZW5lcikge1xuICAgICAgICAgICAgZ2xvYmFsLmFkZEV2ZW50TGlzdGVuZXIoXCJtZXNzYWdlXCIsIG9uR2xvYmFsTWVzc2FnZSwgZmFsc2UpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZ2xvYmFsLmF0dGFjaEV2ZW50KFwib25tZXNzYWdlXCIsIG9uR2xvYmFsTWVzc2FnZSk7XG4gICAgICAgIH1cblxuICAgICAgICByZWdpc3RlckltbWVkaWF0ZSA9IGZ1bmN0aW9uKGhhbmRsZSkge1xuICAgICAgICAgICAgZ2xvYmFsLnBvc3RNZXNzYWdlKG1lc3NhZ2VQcmVmaXggKyBoYW5kbGUsIFwiKlwiKTtcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBpbnN0YWxsTWVzc2FnZUNoYW5uZWxJbXBsZW1lbnRhdGlvbigpIHtcbiAgICAgICAgdmFyIGNoYW5uZWwgPSBuZXcgTWVzc2FnZUNoYW5uZWwoKTtcbiAgICAgICAgY2hhbm5lbC5wb3J0MS5vbm1lc3NhZ2UgPSBmdW5jdGlvbihldmVudCkge1xuICAgICAgICAgICAgdmFyIGhhbmRsZSA9IGV2ZW50LmRhdGE7XG4gICAgICAgICAgICBydW5JZlByZXNlbnQoaGFuZGxlKTtcbiAgICAgICAgfTtcblxuICAgICAgICByZWdpc3RlckltbWVkaWF0ZSA9IGZ1bmN0aW9uKGhhbmRsZSkge1xuICAgICAgICAgICAgY2hhbm5lbC5wb3J0Mi5wb3N0TWVzc2FnZShoYW5kbGUpO1xuICAgICAgICB9O1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGluc3RhbGxSZWFkeVN0YXRlQ2hhbmdlSW1wbGVtZW50YXRpb24oKSB7XG4gICAgICAgIHZhciBodG1sID0gZG9jLmRvY3VtZW50RWxlbWVudDtcbiAgICAgICAgcmVnaXN0ZXJJbW1lZGlhdGUgPSBmdW5jdGlvbihoYW5kbGUpIHtcbiAgICAgICAgICAgIC8vIENyZWF0ZSBhIDxzY3JpcHQ+IGVsZW1lbnQ7IGl0cyByZWFkeXN0YXRlY2hhbmdlIGV2ZW50IHdpbGwgYmUgZmlyZWQgYXN5bmNocm9ub3VzbHkgb25jZSBpdCBpcyBpbnNlcnRlZFxuICAgICAgICAgICAgLy8gaW50byB0aGUgZG9jdW1lbnQuIERvIHNvLCB0aHVzIHF1ZXVpbmcgdXAgdGhlIHRhc2suIFJlbWVtYmVyIHRvIGNsZWFuIHVwIG9uY2UgaXQncyBiZWVuIGNhbGxlZC5cbiAgICAgICAgICAgIHZhciBzY3JpcHQgPSBkb2MuY3JlYXRlRWxlbWVudChcInNjcmlwdFwiKTtcbiAgICAgICAgICAgIHNjcmlwdC5vbnJlYWR5c3RhdGVjaGFuZ2UgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgcnVuSWZQcmVzZW50KGhhbmRsZSk7XG4gICAgICAgICAgICAgICAgc2NyaXB0Lm9ucmVhZHlzdGF0ZWNoYW5nZSA9IG51bGw7XG4gICAgICAgICAgICAgICAgaHRtbC5yZW1vdmVDaGlsZChzY3JpcHQpO1xuICAgICAgICAgICAgICAgIHNjcmlwdCA9IG51bGw7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgaHRtbC5hcHBlbmRDaGlsZChzY3JpcHQpO1xuICAgICAgICB9O1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGluc3RhbGxTZXRUaW1lb3V0SW1wbGVtZW50YXRpb24oKSB7XG4gICAgICAgIHJlZ2lzdGVySW1tZWRpYXRlID0gZnVuY3Rpb24oaGFuZGxlKSB7XG4gICAgICAgICAgICBzZXRUaW1lb3V0KHJ1bklmUHJlc2VudCwgMCwgaGFuZGxlKTtcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICAvLyBJZiBzdXBwb3J0ZWQsIHdlIHNob3VsZCBhdHRhY2ggdG8gdGhlIHByb3RvdHlwZSBvZiBnbG9iYWwsIHNpbmNlIHRoYXQgaXMgd2hlcmUgc2V0VGltZW91dCBldCBhbC4gbGl2ZS5cbiAgICB2YXIgYXR0YWNoVG8gPSBPYmplY3QuZ2V0UHJvdG90eXBlT2YgJiYgT2JqZWN0LmdldFByb3RvdHlwZU9mKGdsb2JhbCk7XG4gICAgYXR0YWNoVG8gPSBhdHRhY2hUbyAmJiBhdHRhY2hUby5zZXRUaW1lb3V0ID8gYXR0YWNoVG8gOiBnbG9iYWw7XG5cbiAgICAvLyBEb24ndCBnZXQgZm9vbGVkIGJ5IGUuZy4gYnJvd3NlcmlmeSBlbnZpcm9ubWVudHMuXG4gICAgaWYgKHt9LnRvU3RyaW5nLmNhbGwoZ2xvYmFsLnByb2Nlc3MpID09PSBcIltvYmplY3QgcHJvY2Vzc11cIikge1xuICAgICAgICAvLyBGb3IgTm9kZS5qcyBiZWZvcmUgMC45XG4gICAgICAgIGluc3RhbGxOZXh0VGlja0ltcGxlbWVudGF0aW9uKCk7XG5cbiAgICB9IGVsc2UgaWYgKGNhblVzZVBvc3RNZXNzYWdlKCkpIHtcbiAgICAgICAgLy8gRm9yIG5vbi1JRTEwIG1vZGVybiBicm93c2Vyc1xuICAgICAgICBpbnN0YWxsUG9zdE1lc3NhZ2VJbXBsZW1lbnRhdGlvbigpO1xuXG4gICAgfSBlbHNlIGlmIChnbG9iYWwuTWVzc2FnZUNoYW5uZWwpIHtcbiAgICAgICAgLy8gRm9yIHdlYiB3b3JrZXJzLCB3aGVyZSBzdXBwb3J0ZWRcbiAgICAgICAgaW5zdGFsbE1lc3NhZ2VDaGFubmVsSW1wbGVtZW50YXRpb24oKTtcblxuICAgIH0gZWxzZSBpZiAoZG9jICYmIFwib25yZWFkeXN0YXRlY2hhbmdlXCIgaW4gZG9jLmNyZWF0ZUVsZW1lbnQoXCJzY3JpcHRcIikpIHtcbiAgICAgICAgLy8gRm9yIElFIDbigJM4XG4gICAgICAgIGluc3RhbGxSZWFkeVN0YXRlQ2hhbmdlSW1wbGVtZW50YXRpb24oKTtcblxuICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIEZvciBvbGRlciBicm93c2Vyc1xuICAgICAgICBpbnN0YWxsU2V0VGltZW91dEltcGxlbWVudGF0aW9uKCk7XG4gICAgfVxuXG4gICAgYXR0YWNoVG8uc2V0SW1tZWRpYXRlID0gc2V0SW1tZWRpYXRlO1xuICAgIGF0dGFjaFRvLmNsZWFySW1tZWRpYXRlID0gY2xlYXJJbW1lZGlhdGU7XG59KHR5cGVvZiBzZWxmID09PSBcInVuZGVmaW5lZFwiID8gdHlwZW9mIGdsb2JhbCA9PT0gXCJ1bmRlZmluZWRcIiA/IHRoaXMgOiBnbG9iYWwgOiBzZWxmKSk7XG4iLCJleHBvcnQgc2xlZXAgPSAobXMsIGYpIC0+IHNldC10aW1lb3V0IGYsIG1zXG5leHBvcnQgY2xlYXItdGltZXIgPSAoeCkgLT4gY2xlYXItaW50ZXJ2YWwgeFxucmVxdWlyZShcInNldGltbWVkaWF0ZVwiKVxuIiwiXG5leHBvcnRzLmlzQnJvd3NlciA9IHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnO1xuIiwiXG52YXIgUHJvY2Vzc29yID0gZnVuY3Rpb24gUHJvY2Vzc29yKG9wdGlvbnMpe1xuICB0aGlzLnNlbGZPcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgdGhpcy5waXBlcyA9IHt9O1xufTtcblxuUHJvY2Vzc29yLnByb3RvdHlwZS5vcHRpb25zID0gZnVuY3Rpb24ob3B0aW9ucykge1xuICBpZiAob3B0aW9ucykge1xuICAgIHRoaXMuc2VsZk9wdGlvbnMgPSBvcHRpb25zO1xuICB9XG4gIHJldHVybiB0aGlzLnNlbGZPcHRpb25zO1xufTtcblxuUHJvY2Vzc29yLnByb3RvdHlwZS5waXBlID0gZnVuY3Rpb24obmFtZSwgcGlwZSkge1xuICBpZiAodHlwZW9mIG5hbWUgPT09ICdzdHJpbmcnKSB7XG4gICAgaWYgKHR5cGVvZiBwaXBlID09PSAndW5kZWZpbmVkJykge1xuICAgICAgcmV0dXJuIHRoaXMucGlwZXNbbmFtZV07XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMucGlwZXNbbmFtZV0gPSBwaXBlO1xuICAgIH1cbiAgfVxuICBpZiAobmFtZSAmJiBuYW1lLm5hbWUpIHtcbiAgICBwaXBlID0gbmFtZTtcbiAgICBpZiAocGlwZS5wcm9jZXNzb3IgPT09IHRoaXMpIHsgcmV0dXJuIHBpcGU7IH1cbiAgICB0aGlzLnBpcGVzW3BpcGUubmFtZV0gPSBwaXBlO1xuICB9XG4gIHBpcGUucHJvY2Vzc29yID0gdGhpcztcbiAgcmV0dXJuIHBpcGU7XG59O1xuXG5Qcm9jZXNzb3IucHJvdG90eXBlLnByb2Nlc3MgPSBmdW5jdGlvbihpbnB1dCwgcGlwZSkge1xuICB2YXIgY29udGV4dCA9IGlucHV0O1xuICBjb250ZXh0Lm9wdGlvbnMgPSB0aGlzLm9wdGlvbnMoKTtcbiAgdmFyIG5leHRQaXBlID0gcGlwZSB8fCBpbnB1dC5waXBlIHx8ICdkZWZhdWx0JztcbiAgdmFyIGxhc3RQaXBlLCBsYXN0Q29udGV4dDtcbiAgd2hpbGUgKG5leHRQaXBlKSB7XG4gICAgaWYgKHR5cGVvZiBjb250ZXh0Lm5leHRBZnRlckNoaWxkcmVuICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgLy8gY2hpbGRyZW4gcHJvY2Vzc2VkIGFuZCBjb21pbmcgYmFjayB0byBwYXJlbnRcbiAgICAgIGNvbnRleHQubmV4dCA9IGNvbnRleHQubmV4dEFmdGVyQ2hpbGRyZW47XG4gICAgICBjb250ZXh0Lm5leHRBZnRlckNoaWxkcmVuID0gbnVsbDtcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIG5leHRQaXBlID09PSAnc3RyaW5nJykge1xuICAgICAgbmV4dFBpcGUgPSB0aGlzLnBpcGUobmV4dFBpcGUpO1xuICAgIH1cbiAgICBuZXh0UGlwZS5wcm9jZXNzKGNvbnRleHQpO1xuICAgIGxhc3RDb250ZXh0ID0gY29udGV4dDtcbiAgICBsYXN0UGlwZSA9IG5leHRQaXBlO1xuICAgIG5leHRQaXBlID0gbnVsbDtcbiAgICBpZiAoY29udGV4dCkge1xuICAgICAgaWYgKGNvbnRleHQubmV4dCkge1xuICAgICAgICBjb250ZXh0ID0gY29udGV4dC5uZXh0O1xuICAgICAgICBuZXh0UGlwZSA9IGxhc3RDb250ZXh0Lm5leHRQaXBlIHx8IGNvbnRleHQucGlwZSB8fCBsYXN0UGlwZTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgcmV0dXJuIGNvbnRleHQuaGFzUmVzdWx0ID8gY29udGV4dC5yZXN1bHQgOiB1bmRlZmluZWQ7XG59O1xuXG5leHBvcnRzLlByb2Nlc3NvciA9IFByb2Nlc3NvcjtcbiIsInZhciBQaXBlID0gZnVuY3Rpb24gUGlwZShuYW1lKSB7XG4gIHRoaXMubmFtZSA9IG5hbWU7XG4gIHRoaXMuZmlsdGVycyA9IFtdO1xufTtcblxuUGlwZS5wcm90b3R5cGUucHJvY2VzcyA9IGZ1bmN0aW9uKGlucHV0KSB7XG4gIGlmICghdGhpcy5wcm9jZXNzb3IpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2FkZCB0aGlzIHBpcGUgdG8gYSBwcm9jZXNzb3IgYmVmb3JlIHVzaW5nIGl0Jyk7XG4gIH1cbiAgdmFyIGRlYnVnID0gdGhpcy5kZWJ1ZztcbiAgdmFyIGxlbmd0aCA9IHRoaXMuZmlsdGVycy5sZW5ndGg7XG4gIHZhciBjb250ZXh0ID0gaW5wdXQ7XG4gIGZvciAodmFyIGluZGV4ID0gMDsgaW5kZXggPCBsZW5ndGg7IGluZGV4KyspIHtcbiAgICB2YXIgZmlsdGVyID0gdGhpcy5maWx0ZXJzW2luZGV4XTtcbiAgICBpZiAoZGVidWcpIHtcbiAgICAgIHRoaXMubG9nKCdmaWx0ZXI6ICcgKyBmaWx0ZXIuZmlsdGVyTmFtZSk7XG4gICAgfVxuICAgIGZpbHRlcihjb250ZXh0KTtcbiAgICBpZiAodHlwZW9mIGNvbnRleHQgPT09ICdvYmplY3QnICYmIGNvbnRleHQuZXhpdGluZykge1xuICAgICAgY29udGV4dC5leGl0aW5nID0gZmFsc2U7XG4gICAgICBicmVhaztcbiAgICB9XG4gIH1cbiAgaWYgKCFjb250ZXh0Lm5leHQgJiYgdGhpcy5yZXN1bHRDaGVjaykge1xuICAgIHRoaXMucmVzdWx0Q2hlY2soY29udGV4dCk7XG4gIH1cbn07XG5cblBpcGUucHJvdG90eXBlLmxvZyA9IGZ1bmN0aW9uKG1zZykge1xuICBjb25zb2xlLmxvZygnW2pzb25kaWZmcGF0Y2hdICcgKyB0aGlzLm5hbWUgKyAnIHBpcGUsICcgKyBtc2cpO1xufTtcblxuUGlwZS5wcm90b3R5cGUuYXBwZW5kID0gZnVuY3Rpb24oKSB7XG4gIHRoaXMuZmlsdGVycy5wdXNoLmFwcGx5KHRoaXMuZmlsdGVycywgYXJndW1lbnRzKTtcbiAgcmV0dXJuIHRoaXM7XG59O1xuXG5QaXBlLnByb3RvdHlwZS5wcmVwZW5kID0gZnVuY3Rpb24oKSB7XG4gIHRoaXMuZmlsdGVycy51bnNoaWZ0LmFwcGx5KHRoaXMuZmlsdGVycywgYXJndW1lbnRzKTtcbiAgcmV0dXJuIHRoaXM7XG59O1xuXG5QaXBlLnByb3RvdHlwZS5pbmRleE9mID0gZnVuY3Rpb24oZmlsdGVyTmFtZSkge1xuICBpZiAoIWZpbHRlck5hbWUpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2EgZmlsdGVyIG5hbWUgaXMgcmVxdWlyZWQnKTtcbiAgfVxuICBmb3IgKHZhciBpbmRleCA9IDA7IGluZGV4IDwgdGhpcy5maWx0ZXJzLmxlbmd0aDsgaW5kZXgrKykge1xuICAgIHZhciBmaWx0ZXIgPSB0aGlzLmZpbHRlcnNbaW5kZXhdO1xuICAgIGlmIChmaWx0ZXIuZmlsdGVyTmFtZSA9PT0gZmlsdGVyTmFtZSkge1xuICAgICAgcmV0dXJuIGluZGV4O1xuICAgIH1cbiAgfVxuICB0aHJvdyBuZXcgRXJyb3IoJ2ZpbHRlciBub3QgZm91bmQ6ICcgKyBmaWx0ZXJOYW1lKTtcbn07XG5cblBpcGUucHJvdG90eXBlLmxpc3QgPSBmdW5jdGlvbigpIHtcbiAgdmFyIG5hbWVzID0gW107XG4gIGZvciAodmFyIGluZGV4ID0gMDsgaW5kZXggPCB0aGlzLmZpbHRlcnMubGVuZ3RoOyBpbmRleCsrKSB7XG4gICAgdmFyIGZpbHRlciA9IHRoaXMuZmlsdGVyc1tpbmRleF07XG4gICAgbmFtZXMucHVzaChmaWx0ZXIuZmlsdGVyTmFtZSk7XG4gIH1cbiAgcmV0dXJuIG5hbWVzO1xufTtcblxuUGlwZS5wcm90b3R5cGUuYWZ0ZXIgPSBmdW5jdGlvbihmaWx0ZXJOYW1lKSB7XG4gIHZhciBpbmRleCA9IHRoaXMuaW5kZXhPZihmaWx0ZXJOYW1lKTtcbiAgdmFyIHBhcmFtcyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywgMSk7XG4gIGlmICghcGFyYW1zLmxlbmd0aCkge1xuICAgIHRocm93IG5ldyBFcnJvcignYSBmaWx0ZXIgaXMgcmVxdWlyZWQnKTtcbiAgfVxuICBwYXJhbXMudW5zaGlmdChpbmRleCArIDEsIDApO1xuICBBcnJheS5wcm90b3R5cGUuc3BsaWNlLmFwcGx5KHRoaXMuZmlsdGVycywgcGFyYW1zKTtcbiAgcmV0dXJuIHRoaXM7XG59O1xuXG5QaXBlLnByb3RvdHlwZS5iZWZvcmUgPSBmdW5jdGlvbihmaWx0ZXJOYW1lKSB7XG4gIHZhciBpbmRleCA9IHRoaXMuaW5kZXhPZihmaWx0ZXJOYW1lKTtcbiAgdmFyIHBhcmFtcyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywgMSk7XG4gIGlmICghcGFyYW1zLmxlbmd0aCkge1xuICAgIHRocm93IG5ldyBFcnJvcignYSBmaWx0ZXIgaXMgcmVxdWlyZWQnKTtcbiAgfVxuICBwYXJhbXMudW5zaGlmdChpbmRleCwgMCk7XG4gIEFycmF5LnByb3RvdHlwZS5zcGxpY2UuYXBwbHkodGhpcy5maWx0ZXJzLCBwYXJhbXMpO1xuICByZXR1cm4gdGhpcztcbn07XG5cblBpcGUucHJvdG90eXBlLnJlcGxhY2UgPSBmdW5jdGlvbihmaWx0ZXJOYW1lKSB7XG4gIHZhciBpbmRleCA9IHRoaXMuaW5kZXhPZihmaWx0ZXJOYW1lKTtcbiAgdmFyIHBhcmFtcyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywgMSk7XG4gIGlmICghcGFyYW1zLmxlbmd0aCkge1xuICAgIHRocm93IG5ldyBFcnJvcignYSBmaWx0ZXIgaXMgcmVxdWlyZWQnKTtcbiAgfVxuICBwYXJhbXMudW5zaGlmdChpbmRleCwgMSk7XG4gIEFycmF5LnByb3RvdHlwZS5zcGxpY2UuYXBwbHkodGhpcy5maWx0ZXJzLCBwYXJhbXMpO1xuICByZXR1cm4gdGhpcztcbn07XG5cblBpcGUucHJvdG90eXBlLnJlbW92ZSA9IGZ1bmN0aW9uKGZpbHRlck5hbWUpIHtcbiAgdmFyIGluZGV4ID0gdGhpcy5pbmRleE9mKGZpbHRlck5hbWUpO1xuICB0aGlzLmZpbHRlcnMuc3BsaWNlKGluZGV4LCAxKTtcbiAgcmV0dXJuIHRoaXM7XG59O1xuXG5QaXBlLnByb3RvdHlwZS5jbGVhciA9IGZ1bmN0aW9uKCkge1xuICB0aGlzLmZpbHRlcnMubGVuZ3RoID0gMDtcbiAgcmV0dXJuIHRoaXM7XG59O1xuXG5QaXBlLnByb3RvdHlwZS5zaG91bGRIYXZlUmVzdWx0ID0gZnVuY3Rpb24oc2hvdWxkKSB7XG4gIGlmIChzaG91bGQgPT09IGZhbHNlKSB7XG4gICAgdGhpcy5yZXN1bHRDaGVjayA9IG51bGw7XG4gICAgcmV0dXJuO1xuICB9XG4gIGlmICh0aGlzLnJlc3VsdENoZWNrKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIHZhciBwaXBlID0gdGhpcztcbiAgdGhpcy5yZXN1bHRDaGVjayA9IGZ1bmN0aW9uKGNvbnRleHQpIHtcbiAgICBpZiAoIWNvbnRleHQuaGFzUmVzdWx0KSB7XG4gICAgICBjb25zb2xlLmxvZyhjb250ZXh0KTtcbiAgICAgIHZhciBlcnJvciA9IG5ldyBFcnJvcihwaXBlLm5hbWUgKyAnIGZhaWxlZCcpO1xuICAgICAgZXJyb3Iubm9SZXN1bHQgPSB0cnVlO1xuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxuICB9O1xuICByZXR1cm4gdGhpcztcbn07XG5cbmV4cG9ydHMuUGlwZSA9IFBpcGU7XG4iLCJcbnZhciBQaXBlID0gcmVxdWlyZSgnLi4vcGlwZScpLlBpcGU7XG5cbnZhciBDb250ZXh0ID0gZnVuY3Rpb24gQ29udGV4dCgpe1xufTtcblxuQ29udGV4dC5wcm90b3R5cGUuc2V0UmVzdWx0ID0gZnVuY3Rpb24ocmVzdWx0KSB7XG5cdHRoaXMucmVzdWx0ID0gcmVzdWx0O1xuXHR0aGlzLmhhc1Jlc3VsdCA9IHRydWU7XG5cdHJldHVybiB0aGlzO1xufTtcblxuQ29udGV4dC5wcm90b3R5cGUuZXhpdCA9IGZ1bmN0aW9uKCkge1xuXHR0aGlzLmV4aXRpbmcgPSB0cnVlO1xuXHRyZXR1cm4gdGhpcztcbn07XG5cbkNvbnRleHQucHJvdG90eXBlLnN3aXRjaFRvID0gZnVuY3Rpb24obmV4dCwgcGlwZSkge1xuXHRpZiAodHlwZW9mIG5leHQgPT09ICdzdHJpbmcnIHx8IG5leHQgaW5zdGFuY2VvZiBQaXBlKSB7XG5cdFx0dGhpcy5uZXh0UGlwZSA9IG5leHQ7XG5cdH0gZWxzZSB7XG5cdFx0dGhpcy5uZXh0ID0gbmV4dDtcblx0XHRpZiAocGlwZSkge1xuXHRcdFx0dGhpcy5uZXh0UGlwZSA9IHBpcGU7XG5cdFx0fVxuXHR9XG5cdHJldHVybiB0aGlzO1xufTtcblxuQ29udGV4dC5wcm90b3R5cGUucHVzaCA9IGZ1bmN0aW9uKGNoaWxkLCBuYW1lKSB7XG5cdGNoaWxkLnBhcmVudCA9IHRoaXM7XG5cdGlmICh0eXBlb2YgbmFtZSAhPT0gJ3VuZGVmaW5lZCcpIHtcblx0XHRjaGlsZC5jaGlsZE5hbWUgPSBuYW1lO1xuXHR9XG5cdGNoaWxkLnJvb3QgPSB0aGlzLnJvb3QgfHwgdGhpcztcblx0Y2hpbGQub3B0aW9ucyA9IGNoaWxkLm9wdGlvbnMgfHwgdGhpcy5vcHRpb25zO1xuXHRpZiAoIXRoaXMuY2hpbGRyZW4pIHtcblx0XHR0aGlzLmNoaWxkcmVuID0gW2NoaWxkXTtcblx0XHR0aGlzLm5leHRBZnRlckNoaWxkcmVuID0gdGhpcy5uZXh0IHx8IG51bGw7XG5cdFx0dGhpcy5uZXh0ID0gY2hpbGQ7XG5cdH0gZWxzZSB7XG5cdFx0dGhpcy5jaGlsZHJlblt0aGlzLmNoaWxkcmVuLmxlbmd0aCAtIDFdLm5leHQgPSBjaGlsZDtcblx0XHR0aGlzLmNoaWxkcmVuLnB1c2goY2hpbGQpO1xuXHR9XG5cdGNoaWxkLm5leHQgPSB0aGlzO1xuXHRyZXR1cm4gdGhpcztcbn07XG5cbmV4cG9ydHMuQ29udGV4dCA9IENvbnRleHQ7XG4iLCJcbnZhciBpc0FycmF5ID0gKHR5cGVvZiBBcnJheS5pc0FycmF5ID09PSAnZnVuY3Rpb24nKSA/XG4gIC8vIHVzZSBuYXRpdmUgZnVuY3Rpb25cbiAgQXJyYXkuaXNBcnJheSA6XG4gIC8vIHVzZSBpbnN0YW5jZW9mIG9wZXJhdG9yXG4gIGZ1bmN0aW9uKGEpIHtcbiAgICByZXR1cm4gYSBpbnN0YW5jZW9mIEFycmF5O1xuICB9O1xuXG5mdW5jdGlvbiBjbG9uZVJlZ0V4cChyZSkge1xuICB2YXIgcmVnZXhNYXRjaCA9IC9eXFwvKC4qKVxcLyhbZ2lteXVdKikkLy5leGVjKHJlLnRvU3RyaW5nKCkpO1xuICByZXR1cm4gbmV3IFJlZ0V4cChyZWdleE1hdGNoWzFdLCByZWdleE1hdGNoWzJdKTtcbn1cblxuZnVuY3Rpb24gY2xvbmUoYXJnKSB7XG4gIGlmICh0eXBlb2YgYXJnICE9PSAnb2JqZWN0Jykge1xuICAgIHJldHVybiBhcmc7XG4gIH1cbiAgaWYgKGFyZyA9PT0gbnVsbCkge1xuICAgIHJldHVybiBudWxsO1xuICB9XG4gIGlmIChpc0FycmF5KGFyZykpIHtcbiAgICByZXR1cm4gYXJnLm1hcChjbG9uZSk7XG4gIH1cbiAgaWYgKGFyZyBpbnN0YW5jZW9mIERhdGUpIHtcbiAgICByZXR1cm4gbmV3IERhdGUoYXJnLmdldFRpbWUoKSk7XG4gIH1cbiAgaWYgKGFyZyBpbnN0YW5jZW9mIFJlZ0V4cCkge1xuICAgIHJldHVybiBjbG9uZVJlZ0V4cChhcmcpO1xuICB9XG4gIHZhciBjbG9uZWQgPSB7fTtcbiAgZm9yICh2YXIgbmFtZSBpbiBhcmcpIHtcbiAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGFyZywgbmFtZSkpIHtcbiAgICAgIGNsb25lZFtuYW1lXSA9IGNsb25lKGFyZ1tuYW1lXSk7XG4gICAgfVxuICB9XG4gIHJldHVybiBjbG9uZWQ7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gY2xvbmU7XG4iLCJ2YXIgQ29udGV4dCA9IHJlcXVpcmUoJy4vY29udGV4dCcpLkNvbnRleHQ7XG52YXIgZGVmYXVsdENsb25lID0gcmVxdWlyZSgnLi4vY2xvbmUnKTtcblxudmFyIERpZmZDb250ZXh0ID0gZnVuY3Rpb24gRGlmZkNvbnRleHQobGVmdCwgcmlnaHQpIHtcbiAgdGhpcy5sZWZ0ID0gbGVmdDtcbiAgdGhpcy5yaWdodCA9IHJpZ2h0O1xuICB0aGlzLnBpcGUgPSAnZGlmZic7XG59O1xuXG5EaWZmQ29udGV4dC5wcm90b3R5cGUgPSBuZXcgQ29udGV4dCgpO1xuXG5EaWZmQ29udGV4dC5wcm90b3R5cGUuc2V0UmVzdWx0ID0gZnVuY3Rpb24ocmVzdWx0KSB7XG4gIGlmICh0aGlzLm9wdGlvbnMuY2xvbmVEaWZmVmFsdWVzICYmIHR5cGVvZiByZXN1bHQgPT09ICdvYmplY3QnKSB7XG4gICAgdmFyIGNsb25lID0gdHlwZW9mIHRoaXMub3B0aW9ucy5jbG9uZURpZmZWYWx1ZXMgPT09ICdmdW5jdGlvbicgP1xuICAgICAgdGhpcy5vcHRpb25zLmNsb25lRGlmZlZhbHVlcyA6IGRlZmF1bHRDbG9uZTtcbiAgICBpZiAodHlwZW9mIHJlc3VsdFswXSA9PT0gJ29iamVjdCcpIHtcbiAgICAgIHJlc3VsdFswXSA9IGNsb25lKHJlc3VsdFswXSk7XG4gICAgfVxuICAgIGlmICh0eXBlb2YgcmVzdWx0WzFdID09PSAnb2JqZWN0Jykge1xuICAgICAgcmVzdWx0WzFdID0gY2xvbmUocmVzdWx0WzFdKTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIENvbnRleHQucHJvdG90eXBlLnNldFJlc3VsdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xufTtcblxuZXhwb3J0cy5EaWZmQ29udGV4dCA9IERpZmZDb250ZXh0O1xuIiwidmFyIENvbnRleHQgPSByZXF1aXJlKCcuL2NvbnRleHQnKS5Db250ZXh0O1xuXG52YXIgUGF0Y2hDb250ZXh0ID0gZnVuY3Rpb24gUGF0Y2hDb250ZXh0KGxlZnQsIGRlbHRhKSB7XG4gIHRoaXMubGVmdCA9IGxlZnQ7XG4gIHRoaXMuZGVsdGEgPSBkZWx0YTtcbiAgdGhpcy5waXBlID0gJ3BhdGNoJztcbn07XG5cblBhdGNoQ29udGV4dC5wcm90b3R5cGUgPSBuZXcgQ29udGV4dCgpO1xuXG5leHBvcnRzLlBhdGNoQ29udGV4dCA9IFBhdGNoQ29udGV4dDtcbiIsInZhciBDb250ZXh0ID0gcmVxdWlyZSgnLi9jb250ZXh0JykuQ29udGV4dDtcblxudmFyIFJldmVyc2VDb250ZXh0ID0gZnVuY3Rpb24gUmV2ZXJzZUNvbnRleHQoZGVsdGEpIHtcbiAgdGhpcy5kZWx0YSA9IGRlbHRhO1xuICB0aGlzLnBpcGUgPSAncmV2ZXJzZSc7XG59O1xuXG5SZXZlcnNlQ29udGV4dC5wcm90b3R5cGUgPSBuZXcgQ29udGV4dCgpO1xuXG5leHBvcnRzLlJldmVyc2VDb250ZXh0ID0gUmV2ZXJzZUNvbnRleHQ7XG4iLCJ2YXIgaXNBcnJheSA9ICh0eXBlb2YgQXJyYXkuaXNBcnJheSA9PT0gJ2Z1bmN0aW9uJykgP1xuICAvLyB1c2UgbmF0aXZlIGZ1bmN0aW9uXG4gIEFycmF5LmlzQXJyYXkgOlxuICAvLyB1c2UgaW5zdGFuY2VvZiBvcGVyYXRvclxuICBmdW5jdGlvbihhKSB7XG4gICAgcmV0dXJuIGEgaW5zdGFuY2VvZiBBcnJheTtcbiAgfTtcblxudmFyIGRpZmZGaWx0ZXIgPSBmdW5jdGlvbiB0cml2aWFsTWF0Y2hlc0RpZmZGaWx0ZXIoY29udGV4dCkge1xuICBpZiAoY29udGV4dC5sZWZ0ID09PSBjb250ZXh0LnJpZ2h0KSB7XG4gICAgY29udGV4dC5zZXRSZXN1bHQodW5kZWZpbmVkKS5leGl0KCk7XG4gICAgcmV0dXJuO1xuICB9XG4gIGlmICh0eXBlb2YgY29udGV4dC5sZWZ0ID09PSAndW5kZWZpbmVkJykge1xuICAgIGlmICh0eXBlb2YgY29udGV4dC5yaWdodCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdmdW5jdGlvbnMgYXJlIG5vdCBzdXBwb3J0ZWQnKTtcbiAgICB9XG4gICAgY29udGV4dC5zZXRSZXN1bHQoW2NvbnRleHQucmlnaHRdKS5leGl0KCk7XG4gICAgcmV0dXJuO1xuICB9XG4gIGlmICh0eXBlb2YgY29udGV4dC5yaWdodCA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBjb250ZXh0LnNldFJlc3VsdChbY29udGV4dC5sZWZ0LCAwLCAwXSkuZXhpdCgpO1xuICAgIHJldHVybjtcbiAgfVxuICBpZiAodHlwZW9mIGNvbnRleHQubGVmdCA9PT0gJ2Z1bmN0aW9uJyB8fCB0eXBlb2YgY29udGV4dC5yaWdodCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgIHRocm93IG5ldyBFcnJvcignZnVuY3Rpb25zIGFyZSBub3Qgc3VwcG9ydGVkJyk7XG4gIH1cbiAgY29udGV4dC5sZWZ0VHlwZSA9IGNvbnRleHQubGVmdCA9PT0gbnVsbCA/ICdudWxsJyA6IHR5cGVvZiBjb250ZXh0LmxlZnQ7XG4gIGNvbnRleHQucmlnaHRUeXBlID0gY29udGV4dC5yaWdodCA9PT0gbnVsbCA/ICdudWxsJyA6IHR5cGVvZiBjb250ZXh0LnJpZ2h0O1xuICBpZiAoY29udGV4dC5sZWZ0VHlwZSAhPT0gY29udGV4dC5yaWdodFR5cGUpIHtcbiAgICBjb250ZXh0LnNldFJlc3VsdChbY29udGV4dC5sZWZ0LCBjb250ZXh0LnJpZ2h0XSkuZXhpdCgpO1xuICAgIHJldHVybjtcbiAgfVxuICBpZiAoY29udGV4dC5sZWZ0VHlwZSA9PT0gJ2Jvb2xlYW4nIHx8IGNvbnRleHQubGVmdFR5cGUgPT09ICdudW1iZXInKSB7XG4gICAgY29udGV4dC5zZXRSZXN1bHQoW2NvbnRleHQubGVmdCwgY29udGV4dC5yaWdodF0pLmV4aXQoKTtcbiAgICByZXR1cm47XG4gIH1cbiAgaWYgKGNvbnRleHQubGVmdFR5cGUgPT09ICdvYmplY3QnKSB7XG4gICAgY29udGV4dC5sZWZ0SXNBcnJheSA9IGlzQXJyYXkoY29udGV4dC5sZWZ0KTtcbiAgfVxuICBpZiAoY29udGV4dC5yaWdodFR5cGUgPT09ICdvYmplY3QnKSB7XG4gICAgY29udGV4dC5yaWdodElzQXJyYXkgPSBpc0FycmF5KGNvbnRleHQucmlnaHQpO1xuICB9XG4gIGlmIChjb250ZXh0LmxlZnRJc0FycmF5ICE9PSBjb250ZXh0LnJpZ2h0SXNBcnJheSkge1xuICAgIGNvbnRleHQuc2V0UmVzdWx0KFtjb250ZXh0LmxlZnQsIGNvbnRleHQucmlnaHRdKS5leGl0KCk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgaWYgKGNvbnRleHQubGVmdCBpbnN0YW5jZW9mIFJlZ0V4cCkge1xuICAgIGlmIChjb250ZXh0LnJpZ2h0IGluc3RhbmNlb2YgUmVnRXhwKSB7XG4gICAgICBjb250ZXh0LnNldFJlc3VsdChbY29udGV4dC5sZWZ0LnRvU3RyaW5nKCksIGNvbnRleHQucmlnaHQudG9TdHJpbmcoKV0pLmV4aXQoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29udGV4dC5zZXRSZXN1bHQoW2NvbnRleHQubGVmdCwgY29udGV4dC5yaWdodF0pLmV4aXQoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gIH1cbn07XG5kaWZmRmlsdGVyLmZpbHRlck5hbWUgPSAndHJpdmlhbCc7XG5cbnZhciBwYXRjaEZpbHRlciA9IGZ1bmN0aW9uIHRyaXZpYWxNYXRjaGVzUGF0Y2hGaWx0ZXIoY29udGV4dCkge1xuICBpZiAodHlwZW9mIGNvbnRleHQuZGVsdGEgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgY29udGV4dC5zZXRSZXN1bHQoY29udGV4dC5sZWZ0KS5leGl0KCk7XG4gICAgcmV0dXJuO1xuICB9XG4gIGNvbnRleHQubmVzdGVkID0gIWlzQXJyYXkoY29udGV4dC5kZWx0YSk7XG4gIGlmIChjb250ZXh0Lm5lc3RlZCkge1xuICAgIHJldHVybjtcbiAgfVxuICBpZiAoY29udGV4dC5kZWx0YS5sZW5ndGggPT09IDEpIHtcbiAgICBjb250ZXh0LnNldFJlc3VsdChjb250ZXh0LmRlbHRhWzBdKS5leGl0KCk7XG4gICAgcmV0dXJuO1xuICB9XG4gIGlmIChjb250ZXh0LmRlbHRhLmxlbmd0aCA9PT0gMikge1xuICAgIGlmIChjb250ZXh0LmxlZnQgaW5zdGFuY2VvZiBSZWdFeHApIHtcbiAgICAgIHZhciByZWdleEFyZ3MgPSAvXlxcLyguKilcXC8oW2dpbXl1XSspJC8uZXhlYyhjb250ZXh0LmRlbHRhWzFdKTtcbiAgICAgIGlmIChyZWdleEFyZ3MpIHtcbiAgICAgICAgY29udGV4dC5zZXRSZXN1bHQobmV3IFJlZ0V4cChyZWdleEFyZ3NbMV0sIHJlZ2V4QXJnc1syXSkpLmV4aXQoKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgIH1cbiAgICBjb250ZXh0LnNldFJlc3VsdChjb250ZXh0LmRlbHRhWzFdKS5leGl0KCk7XG4gICAgcmV0dXJuO1xuICB9XG4gIGlmIChjb250ZXh0LmRlbHRhLmxlbmd0aCA9PT0gMyAmJiBjb250ZXh0LmRlbHRhWzJdID09PSAwKSB7XG4gICAgY29udGV4dC5zZXRSZXN1bHQodW5kZWZpbmVkKS5leGl0KCk7XG4gICAgcmV0dXJuO1xuICB9XG59O1xucGF0Y2hGaWx0ZXIuZmlsdGVyTmFtZSA9ICd0cml2aWFsJztcblxudmFyIHJldmVyc2VGaWx0ZXIgPSBmdW5jdGlvbiB0cml2aWFsUmVmZXJzZUZpbHRlcihjb250ZXh0KSB7XG4gIGlmICh0eXBlb2YgY29udGV4dC5kZWx0YSA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBjb250ZXh0LnNldFJlc3VsdChjb250ZXh0LmRlbHRhKS5leGl0KCk7XG4gICAgcmV0dXJuO1xuICB9XG4gIGNvbnRleHQubmVzdGVkID0gIWlzQXJyYXkoY29udGV4dC5kZWx0YSk7XG4gIGlmIChjb250ZXh0Lm5lc3RlZCkge1xuICAgIHJldHVybjtcbiAgfVxuICBpZiAoY29udGV4dC5kZWx0YS5sZW5ndGggPT09IDEpIHtcbiAgICBjb250ZXh0LnNldFJlc3VsdChbY29udGV4dC5kZWx0YVswXSwgMCwgMF0pLmV4aXQoKTtcbiAgICByZXR1cm47XG4gIH1cbiAgaWYgKGNvbnRleHQuZGVsdGEubGVuZ3RoID09PSAyKSB7XG4gICAgY29udGV4dC5zZXRSZXN1bHQoW2NvbnRleHQuZGVsdGFbMV0sIGNvbnRleHQuZGVsdGFbMF1dKS5leGl0KCk7XG4gICAgcmV0dXJuO1xuICB9XG4gIGlmIChjb250ZXh0LmRlbHRhLmxlbmd0aCA9PT0gMyAmJiBjb250ZXh0LmRlbHRhWzJdID09PSAwKSB7XG4gICAgY29udGV4dC5zZXRSZXN1bHQoW2NvbnRleHQuZGVsdGFbMF1dKS5leGl0KCk7XG4gICAgcmV0dXJuO1xuICB9XG59O1xucmV2ZXJzZUZpbHRlci5maWx0ZXJOYW1lID0gJ3RyaXZpYWwnO1xuXG5leHBvcnRzLmRpZmZGaWx0ZXIgPSBkaWZmRmlsdGVyO1xuZXhwb3J0cy5wYXRjaEZpbHRlciA9IHBhdGNoRmlsdGVyO1xuZXhwb3J0cy5yZXZlcnNlRmlsdGVyID0gcmV2ZXJzZUZpbHRlcjtcbiIsInZhciBEaWZmQ29udGV4dCA9IHJlcXVpcmUoJy4uL2NvbnRleHRzL2RpZmYnKS5EaWZmQ29udGV4dDtcbnZhciBQYXRjaENvbnRleHQgPSByZXF1aXJlKCcuLi9jb250ZXh0cy9wYXRjaCcpLlBhdGNoQ29udGV4dDtcbnZhciBSZXZlcnNlQ29udGV4dCA9IHJlcXVpcmUoJy4uL2NvbnRleHRzL3JldmVyc2UnKS5SZXZlcnNlQ29udGV4dDtcblxudmFyIGNvbGxlY3RDaGlsZHJlbkRpZmZGaWx0ZXIgPSBmdW5jdGlvbiBjb2xsZWN0Q2hpbGRyZW5EaWZmRmlsdGVyKGNvbnRleHQpIHtcbiAgaWYgKCFjb250ZXh0IHx8ICFjb250ZXh0LmNoaWxkcmVuKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIHZhciBsZW5ndGggPSBjb250ZXh0LmNoaWxkcmVuLmxlbmd0aDtcbiAgdmFyIGNoaWxkO1xuICB2YXIgcmVzdWx0ID0gY29udGV4dC5yZXN1bHQ7XG4gIGZvciAodmFyIGluZGV4ID0gMDsgaW5kZXggPCBsZW5ndGg7IGluZGV4KyspIHtcbiAgICBjaGlsZCA9IGNvbnRleHQuY2hpbGRyZW5baW5kZXhdO1xuICAgIGlmICh0eXBlb2YgY2hpbGQucmVzdWx0ID09PSAndW5kZWZpbmVkJykge1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIHJlc3VsdCA9IHJlc3VsdCB8fCB7fTtcbiAgICByZXN1bHRbY2hpbGQuY2hpbGROYW1lXSA9IGNoaWxkLnJlc3VsdDtcbiAgfVxuICBpZiAocmVzdWx0ICYmIGNvbnRleHQubGVmdElzQXJyYXkpIHtcbiAgICByZXN1bHQuX3QgPSAnYSc7XG4gIH1cbiAgY29udGV4dC5zZXRSZXN1bHQocmVzdWx0KS5leGl0KCk7XG59O1xuY29sbGVjdENoaWxkcmVuRGlmZkZpbHRlci5maWx0ZXJOYW1lID0gJ2NvbGxlY3RDaGlsZHJlbic7XG5cbnZhciBvYmplY3RzRGlmZkZpbHRlciA9IGZ1bmN0aW9uIG9iamVjdHNEaWZmRmlsdGVyKGNvbnRleHQpIHtcbiAgaWYgKGNvbnRleHQubGVmdElzQXJyYXkgfHwgY29udGV4dC5sZWZ0VHlwZSAhPT0gJ29iamVjdCcpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICB2YXIgbmFtZSwgY2hpbGQsIHByb3BlcnR5RmlsdGVyID0gY29udGV4dC5vcHRpb25zLnByb3BlcnR5RmlsdGVyO1xuICBmb3IgKG5hbWUgaW4gY29udGV4dC5sZWZ0KSB7XG4gICAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoY29udGV4dC5sZWZ0LCBuYW1lKSkge1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIGlmIChwcm9wZXJ0eUZpbHRlciAmJiAhcHJvcGVydHlGaWx0ZXIobmFtZSwgY29udGV4dCkpIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICBjaGlsZCA9IG5ldyBEaWZmQ29udGV4dChjb250ZXh0LmxlZnRbbmFtZV0sIGNvbnRleHQucmlnaHRbbmFtZV0pO1xuICAgIGNvbnRleHQucHVzaChjaGlsZCwgbmFtZSk7XG4gIH1cbiAgZm9yIChuYW1lIGluIGNvbnRleHQucmlnaHQpIHtcbiAgICBpZiAoIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChjb250ZXh0LnJpZ2h0LCBuYW1lKSkge1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIGlmIChwcm9wZXJ0eUZpbHRlciAmJiAhcHJvcGVydHlGaWx0ZXIobmFtZSwgY29udGV4dCkpIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICBpZiAodHlwZW9mIGNvbnRleHQubGVmdFtuYW1lXSA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgIGNoaWxkID0gbmV3IERpZmZDb250ZXh0KHVuZGVmaW5lZCwgY29udGV4dC5yaWdodFtuYW1lXSk7XG4gICAgICBjb250ZXh0LnB1c2goY2hpbGQsIG5hbWUpO1xuICAgIH1cbiAgfVxuXG4gIGlmICghY29udGV4dC5jaGlsZHJlbiB8fCBjb250ZXh0LmNoaWxkcmVuLmxlbmd0aCA9PT0gMCkge1xuICAgIGNvbnRleHQuc2V0UmVzdWx0KHVuZGVmaW5lZCkuZXhpdCgpO1xuICAgIHJldHVybjtcbiAgfVxuICBjb250ZXh0LmV4aXQoKTtcbn07XG5vYmplY3RzRGlmZkZpbHRlci5maWx0ZXJOYW1lID0gJ29iamVjdHMnO1xuXG52YXIgcGF0Y2hGaWx0ZXIgPSBmdW5jdGlvbiBuZXN0ZWRQYXRjaEZpbHRlcihjb250ZXh0KSB7XG4gIGlmICghY29udGV4dC5uZXN0ZWQpIHtcbiAgICByZXR1cm47XG4gIH1cbiAgaWYgKGNvbnRleHQuZGVsdGEuX3QpIHtcbiAgICByZXR1cm47XG4gIH1cbiAgdmFyIG5hbWUsIGNoaWxkO1xuICBmb3IgKG5hbWUgaW4gY29udGV4dC5kZWx0YSkge1xuICAgIGNoaWxkID0gbmV3IFBhdGNoQ29udGV4dChjb250ZXh0LmxlZnRbbmFtZV0sIGNvbnRleHQuZGVsdGFbbmFtZV0pO1xuICAgIGNvbnRleHQucHVzaChjaGlsZCwgbmFtZSk7XG4gIH1cbiAgY29udGV4dC5leGl0KCk7XG59O1xucGF0Y2hGaWx0ZXIuZmlsdGVyTmFtZSA9ICdvYmplY3RzJztcblxudmFyIGNvbGxlY3RDaGlsZHJlblBhdGNoRmlsdGVyID0gZnVuY3Rpb24gY29sbGVjdENoaWxkcmVuUGF0Y2hGaWx0ZXIoY29udGV4dCkge1xuICBpZiAoIWNvbnRleHQgfHwgIWNvbnRleHQuY2hpbGRyZW4pIHtcbiAgICByZXR1cm47XG4gIH1cbiAgaWYgKGNvbnRleHQuZGVsdGEuX3QpIHtcbiAgICByZXR1cm47XG4gIH1cbiAgdmFyIGxlbmd0aCA9IGNvbnRleHQuY2hpbGRyZW4ubGVuZ3RoO1xuICB2YXIgY2hpbGQ7XG4gIGZvciAodmFyIGluZGV4ID0gMDsgaW5kZXggPCBsZW5ndGg7IGluZGV4KyspIHtcbiAgICBjaGlsZCA9IGNvbnRleHQuY2hpbGRyZW5baW5kZXhdO1xuICAgIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoY29udGV4dC5sZWZ0LCBjaGlsZC5jaGlsZE5hbWUpICYmIGNoaWxkLnJlc3VsdCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICBkZWxldGUgY29udGV4dC5sZWZ0W2NoaWxkLmNoaWxkTmFtZV07XG4gICAgfSBlbHNlIGlmIChjb250ZXh0LmxlZnRbY2hpbGQuY2hpbGROYW1lXSAhPT0gY2hpbGQucmVzdWx0KSB7XG4gICAgICBjb250ZXh0LmxlZnRbY2hpbGQuY2hpbGROYW1lXSA9IGNoaWxkLnJlc3VsdDtcbiAgICB9XG4gIH1cbiAgY29udGV4dC5zZXRSZXN1bHQoY29udGV4dC5sZWZ0KS5leGl0KCk7XG59O1xuY29sbGVjdENoaWxkcmVuUGF0Y2hGaWx0ZXIuZmlsdGVyTmFtZSA9ICdjb2xsZWN0Q2hpbGRyZW4nO1xuXG52YXIgcmV2ZXJzZUZpbHRlciA9IGZ1bmN0aW9uIG5lc3RlZFJldmVyc2VGaWx0ZXIoY29udGV4dCkge1xuICBpZiAoIWNvbnRleHQubmVzdGVkKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIGlmIChjb250ZXh0LmRlbHRhLl90KSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIHZhciBuYW1lLCBjaGlsZDtcbiAgZm9yIChuYW1lIGluIGNvbnRleHQuZGVsdGEpIHtcbiAgICBjaGlsZCA9IG5ldyBSZXZlcnNlQ29udGV4dChjb250ZXh0LmRlbHRhW25hbWVdKTtcbiAgICBjb250ZXh0LnB1c2goY2hpbGQsIG5hbWUpO1xuICB9XG4gIGNvbnRleHQuZXhpdCgpO1xufTtcbnJldmVyc2VGaWx0ZXIuZmlsdGVyTmFtZSA9ICdvYmplY3RzJztcblxudmFyIGNvbGxlY3RDaGlsZHJlblJldmVyc2VGaWx0ZXIgPSBmdW5jdGlvbiBjb2xsZWN0Q2hpbGRyZW5SZXZlcnNlRmlsdGVyKGNvbnRleHQpIHtcbiAgaWYgKCFjb250ZXh0IHx8ICFjb250ZXh0LmNoaWxkcmVuKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIGlmIChjb250ZXh0LmRlbHRhLl90KSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIHZhciBsZW5ndGggPSBjb250ZXh0LmNoaWxkcmVuLmxlbmd0aDtcbiAgdmFyIGNoaWxkO1xuICB2YXIgZGVsdGEgPSB7fTtcbiAgZm9yICh2YXIgaW5kZXggPSAwOyBpbmRleCA8IGxlbmd0aDsgaW5kZXgrKykge1xuICAgIGNoaWxkID0gY29udGV4dC5jaGlsZHJlbltpbmRleF07XG4gICAgaWYgKGRlbHRhW2NoaWxkLmNoaWxkTmFtZV0gIT09IGNoaWxkLnJlc3VsdCkge1xuICAgICAgZGVsdGFbY2hpbGQuY2hpbGROYW1lXSA9IGNoaWxkLnJlc3VsdDtcbiAgICB9XG4gIH1cbiAgY29udGV4dC5zZXRSZXN1bHQoZGVsdGEpLmV4aXQoKTtcbn07XG5jb2xsZWN0Q2hpbGRyZW5SZXZlcnNlRmlsdGVyLmZpbHRlck5hbWUgPSAnY29sbGVjdENoaWxkcmVuJztcblxuZXhwb3J0cy5jb2xsZWN0Q2hpbGRyZW5EaWZmRmlsdGVyID0gY29sbGVjdENoaWxkcmVuRGlmZkZpbHRlcjtcbmV4cG9ydHMub2JqZWN0c0RpZmZGaWx0ZXIgPSBvYmplY3RzRGlmZkZpbHRlcjtcbmV4cG9ydHMucGF0Y2hGaWx0ZXIgPSBwYXRjaEZpbHRlcjtcbmV4cG9ydHMuY29sbGVjdENoaWxkcmVuUGF0Y2hGaWx0ZXIgPSBjb2xsZWN0Q2hpbGRyZW5QYXRjaEZpbHRlcjtcbmV4cG9ydHMucmV2ZXJzZUZpbHRlciA9IHJldmVyc2VGaWx0ZXI7XG5leHBvcnRzLmNvbGxlY3RDaGlsZHJlblJldmVyc2VGaWx0ZXIgPSBjb2xsZWN0Q2hpbGRyZW5SZXZlcnNlRmlsdGVyO1xuIiwiLypcblxuTENTIGltcGxlbWVudGF0aW9uIHRoYXQgc3VwcG9ydHMgYXJyYXlzIG9yIHN0cmluZ3NcblxucmVmZXJlbmNlOiBodHRwOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0xvbmdlc3RfY29tbW9uX3N1YnNlcXVlbmNlX3Byb2JsZW1cblxuKi9cblxudmFyIGRlZmF1bHRNYXRjaCA9IGZ1bmN0aW9uKGFycmF5MSwgYXJyYXkyLCBpbmRleDEsIGluZGV4Mikge1xuICByZXR1cm4gYXJyYXkxW2luZGV4MV0gPT09IGFycmF5MltpbmRleDJdO1xufTtcblxudmFyIGxlbmd0aE1hdHJpeCA9IGZ1bmN0aW9uKGFycmF5MSwgYXJyYXkyLCBtYXRjaCwgY29udGV4dCkge1xuICB2YXIgbGVuMSA9IGFycmF5MS5sZW5ndGg7XG4gIHZhciBsZW4yID0gYXJyYXkyLmxlbmd0aDtcbiAgdmFyIHgsIHk7XG5cbiAgLy8gaW5pdGlhbGl6ZSBlbXB0eSBtYXRyaXggb2YgbGVuMSsxIHggbGVuMisxXG4gIHZhciBtYXRyaXggPSBbbGVuMSArIDFdO1xuICBmb3IgKHggPSAwOyB4IDwgbGVuMSArIDE7IHgrKykge1xuICAgIG1hdHJpeFt4XSA9IFtsZW4yICsgMV07XG4gICAgZm9yICh5ID0gMDsgeSA8IGxlbjIgKyAxOyB5KyspIHtcbiAgICAgIG1hdHJpeFt4XVt5XSA9IDA7XG4gICAgfVxuICB9XG4gIG1hdHJpeC5tYXRjaCA9IG1hdGNoO1xuICAvLyBzYXZlIHNlcXVlbmNlIGxlbmd0aHMgZm9yIGVhY2ggY29vcmRpbmF0ZVxuICBmb3IgKHggPSAxOyB4IDwgbGVuMSArIDE7IHgrKykge1xuICAgIGZvciAoeSA9IDE7IHkgPCBsZW4yICsgMTsgeSsrKSB7XG4gICAgICBpZiAobWF0Y2goYXJyYXkxLCBhcnJheTIsIHggLSAxLCB5IC0gMSwgY29udGV4dCkpIHtcbiAgICAgICAgbWF0cml4W3hdW3ldID0gbWF0cml4W3ggLSAxXVt5IC0gMV0gKyAxO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbWF0cml4W3hdW3ldID0gTWF0aC5tYXgobWF0cml4W3ggLSAxXVt5XSwgbWF0cml4W3hdW3kgLSAxXSk7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIHJldHVybiBtYXRyaXg7XG59O1xuXG52YXIgYmFja3RyYWNrID0gZnVuY3Rpb24obWF0cml4LCBhcnJheTEsIGFycmF5MiwgaW5kZXgxLCBpbmRleDIsIGNvbnRleHQpIHtcbiAgaWYgKGluZGV4MSA9PT0gMCB8fCBpbmRleDIgPT09IDApIHtcbiAgICByZXR1cm4ge1xuICAgICAgc2VxdWVuY2U6IFtdLFxuICAgICAgaW5kaWNlczE6IFtdLFxuICAgICAgaW5kaWNlczI6IFtdXG4gICAgfTtcbiAgfVxuXG4gIGlmIChtYXRyaXgubWF0Y2goYXJyYXkxLCBhcnJheTIsIGluZGV4MSAtIDEsIGluZGV4MiAtIDEsIGNvbnRleHQpKSB7XG4gICAgdmFyIHN1YnNlcXVlbmNlID0gYmFja3RyYWNrKG1hdHJpeCwgYXJyYXkxLCBhcnJheTIsIGluZGV4MSAtIDEsIGluZGV4MiAtIDEsIGNvbnRleHQpO1xuICAgIHN1YnNlcXVlbmNlLnNlcXVlbmNlLnB1c2goYXJyYXkxW2luZGV4MSAtIDFdKTtcbiAgICBzdWJzZXF1ZW5jZS5pbmRpY2VzMS5wdXNoKGluZGV4MSAtIDEpO1xuICAgIHN1YnNlcXVlbmNlLmluZGljZXMyLnB1c2goaW5kZXgyIC0gMSk7XG4gICAgcmV0dXJuIHN1YnNlcXVlbmNlO1xuICB9XG5cbiAgaWYgKG1hdHJpeFtpbmRleDFdW2luZGV4MiAtIDFdID4gbWF0cml4W2luZGV4MSAtIDFdW2luZGV4Ml0pIHtcbiAgICByZXR1cm4gYmFja3RyYWNrKG1hdHJpeCwgYXJyYXkxLCBhcnJheTIsIGluZGV4MSwgaW5kZXgyIC0gMSwgY29udGV4dCk7XG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIGJhY2t0cmFjayhtYXRyaXgsIGFycmF5MSwgYXJyYXkyLCBpbmRleDEgLSAxLCBpbmRleDIsIGNvbnRleHQpO1xuICB9XG59O1xuXG52YXIgZ2V0ID0gZnVuY3Rpb24oYXJyYXkxLCBhcnJheTIsIG1hdGNoLCBjb250ZXh0KSB7XG4gIGNvbnRleHQgPSBjb250ZXh0IHx8IHt9O1xuICB2YXIgbWF0cml4ID0gbGVuZ3RoTWF0cml4KGFycmF5MSwgYXJyYXkyLCBtYXRjaCB8fCBkZWZhdWx0TWF0Y2gsIGNvbnRleHQpO1xuICB2YXIgcmVzdWx0ID0gYmFja3RyYWNrKG1hdHJpeCwgYXJyYXkxLCBhcnJheTIsIGFycmF5MS5sZW5ndGgsIGFycmF5Mi5sZW5ndGgsIGNvbnRleHQpO1xuICBpZiAodHlwZW9mIGFycmF5MSA9PT0gJ3N0cmluZycgJiYgdHlwZW9mIGFycmF5MiA9PT0gJ3N0cmluZycpIHtcbiAgICByZXN1bHQuc2VxdWVuY2UgPSByZXN1bHQuc2VxdWVuY2Uuam9pbignJyk7XG4gIH1cbiAgcmV0dXJuIHJlc3VsdDtcbn07XG5cbmV4cG9ydHMuZ2V0ID0gZ2V0O1xuIiwidmFyIERpZmZDb250ZXh0ID0gcmVxdWlyZSgnLi4vY29udGV4dHMvZGlmZicpLkRpZmZDb250ZXh0O1xudmFyIFBhdGNoQ29udGV4dCA9IHJlcXVpcmUoJy4uL2NvbnRleHRzL3BhdGNoJykuUGF0Y2hDb250ZXh0O1xudmFyIFJldmVyc2VDb250ZXh0ID0gcmVxdWlyZSgnLi4vY29udGV4dHMvcmV2ZXJzZScpLlJldmVyc2VDb250ZXh0O1xuXG52YXIgbGNzID0gcmVxdWlyZSgnLi9sY3MnKTtcblxudmFyIEFSUkFZX01PVkUgPSAzO1xuXG52YXIgaXNBcnJheSA9ICh0eXBlb2YgQXJyYXkuaXNBcnJheSA9PT0gJ2Z1bmN0aW9uJykgP1xuICAvLyB1c2UgbmF0aXZlIGZ1bmN0aW9uXG4gIEFycmF5LmlzQXJyYXkgOlxuICAvLyB1c2UgaW5zdGFuY2VvZiBvcGVyYXRvclxuICBmdW5jdGlvbihhKSB7XG4gICAgcmV0dXJuIGEgaW5zdGFuY2VvZiBBcnJheTtcbiAgfTtcblxudmFyIGFycmF5SW5kZXhPZiA9IHR5cGVvZiBBcnJheS5wcm90b3R5cGUuaW5kZXhPZiA9PT0gJ2Z1bmN0aW9uJyA/XG4gIGZ1bmN0aW9uKGFycmF5LCBpdGVtKSB7XG4gICAgcmV0dXJuIGFycmF5LmluZGV4T2YoaXRlbSk7XG4gIH0gOiBmdW5jdGlvbihhcnJheSwgaXRlbSkge1xuICAgIHZhciBsZW5ndGggPSBhcnJheS5sZW5ndGg7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgICAgaWYgKGFycmF5W2ldID09PSBpdGVtKSB7XG4gICAgICAgIHJldHVybiBpO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gLTE7XG4gIH07XG5cbmZ1bmN0aW9uIGFycmF5c0hhdmVNYXRjaEJ5UmVmKGFycmF5MSwgYXJyYXkyLCBsZW4xLCBsZW4yKSB7XG4gIGZvciAodmFyIGluZGV4MSA9IDA7IGluZGV4MSA8IGxlbjE7IGluZGV4MSsrKSB7XG4gICAgdmFyIHZhbDEgPSBhcnJheTFbaW5kZXgxXTtcbiAgICBmb3IgKHZhciBpbmRleDIgPSAwOyBpbmRleDIgPCBsZW4yOyBpbmRleDIrKykge1xuICAgICAgdmFyIHZhbDIgPSBhcnJheTJbaW5kZXgyXTtcbiAgICAgIGlmIChpbmRleDEgIT09IGluZGV4MiAmJiB2YWwxID09PSB2YWwyKSB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuICAgIH1cbiAgfVxufVxuXG5mdW5jdGlvbiBtYXRjaEl0ZW1zKGFycmF5MSwgYXJyYXkyLCBpbmRleDEsIGluZGV4MiwgY29udGV4dCkge1xuICB2YXIgdmFsdWUxID0gYXJyYXkxW2luZGV4MV07XG4gIHZhciB2YWx1ZTIgPSBhcnJheTJbaW5kZXgyXTtcbiAgaWYgKHZhbHVlMSA9PT0gdmFsdWUyKSB7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cbiAgaWYgKHR5cGVvZiB2YWx1ZTEgIT09ICdvYmplY3QnIHx8IHR5cGVvZiB2YWx1ZTIgIT09ICdvYmplY3QnKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIHZhciBvYmplY3RIYXNoID0gY29udGV4dC5vYmplY3RIYXNoO1xuICBpZiAoIW9iamVjdEhhc2gpIHtcbiAgICAvLyBubyB3YXkgdG8gbWF0Y2ggb2JqZWN0cyB3YXMgcHJvdmlkZWQsIHRyeSBtYXRjaCBieSBwb3NpdGlvblxuICAgIHJldHVybiBjb250ZXh0Lm1hdGNoQnlQb3NpdGlvbiAmJiBpbmRleDEgPT09IGluZGV4MjtcbiAgfVxuICB2YXIgaGFzaDE7XG4gIHZhciBoYXNoMjtcbiAgaWYgKHR5cGVvZiBpbmRleDEgPT09ICdudW1iZXInKSB7XG4gICAgY29udGV4dC5oYXNoQ2FjaGUxID0gY29udGV4dC5oYXNoQ2FjaGUxIHx8IFtdO1xuICAgIGhhc2gxID0gY29udGV4dC5oYXNoQ2FjaGUxW2luZGV4MV07XG4gICAgaWYgKHR5cGVvZiBoYXNoMSA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgIGNvbnRleHQuaGFzaENhY2hlMVtpbmRleDFdID0gaGFzaDEgPSBvYmplY3RIYXNoKHZhbHVlMSwgaW5kZXgxKTtcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgaGFzaDEgPSBvYmplY3RIYXNoKHZhbHVlMSk7XG4gIH1cbiAgaWYgKHR5cGVvZiBoYXNoMSA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgaWYgKHR5cGVvZiBpbmRleDIgPT09ICdudW1iZXInKSB7XG4gICAgY29udGV4dC5oYXNoQ2FjaGUyID0gY29udGV4dC5oYXNoQ2FjaGUyIHx8IFtdO1xuICAgIGhhc2gyID0gY29udGV4dC5oYXNoQ2FjaGUyW2luZGV4Ml07XG4gICAgaWYgKHR5cGVvZiBoYXNoMiA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgIGNvbnRleHQuaGFzaENhY2hlMltpbmRleDJdID0gaGFzaDIgPSBvYmplY3RIYXNoKHZhbHVlMiwgaW5kZXgyKTtcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgaGFzaDIgPSBvYmplY3RIYXNoKHZhbHVlMik7XG4gIH1cbiAgaWYgKHR5cGVvZiBoYXNoMiA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgcmV0dXJuIGhhc2gxID09PSBoYXNoMjtcbn1cblxudmFyIGRpZmZGaWx0ZXIgPSBmdW5jdGlvbiBhcnJheXNEaWZmRmlsdGVyKGNvbnRleHQpIHtcbiAgaWYgKCFjb250ZXh0LmxlZnRJc0FycmF5KSB7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgdmFyIG1hdGNoQ29udGV4dCA9IHtcbiAgICBvYmplY3RIYXNoOiBjb250ZXh0Lm9wdGlvbnMgJiYgY29udGV4dC5vcHRpb25zLm9iamVjdEhhc2gsXG4gICAgbWF0Y2hCeVBvc2l0aW9uOiBjb250ZXh0Lm9wdGlvbnMgJiYgY29udGV4dC5vcHRpb25zLm1hdGNoQnlQb3NpdGlvblxuICB9O1xuICB2YXIgY29tbW9uSGVhZCA9IDA7XG4gIHZhciBjb21tb25UYWlsID0gMDtcbiAgdmFyIGluZGV4O1xuICB2YXIgaW5kZXgxO1xuICB2YXIgaW5kZXgyO1xuICB2YXIgYXJyYXkxID0gY29udGV4dC5sZWZ0O1xuICB2YXIgYXJyYXkyID0gY29udGV4dC5yaWdodDtcbiAgdmFyIGxlbjEgPSBhcnJheTEubGVuZ3RoO1xuICB2YXIgbGVuMiA9IGFycmF5Mi5sZW5ndGg7XG5cbiAgdmFyIGNoaWxkO1xuXG4gIGlmIChsZW4xID4gMCAmJiBsZW4yID4gMCAmJiAhbWF0Y2hDb250ZXh0Lm9iamVjdEhhc2ggJiZcbiAgICB0eXBlb2YgbWF0Y2hDb250ZXh0Lm1hdGNoQnlQb3NpdGlvbiAhPT0gJ2Jvb2xlYW4nKSB7XG4gICAgbWF0Y2hDb250ZXh0Lm1hdGNoQnlQb3NpdGlvbiA9ICFhcnJheXNIYXZlTWF0Y2hCeVJlZihhcnJheTEsIGFycmF5MiwgbGVuMSwgbGVuMik7XG4gIH1cblxuICAvLyBzZXBhcmF0ZSBjb21tb24gaGVhZFxuICB3aGlsZSAoY29tbW9uSGVhZCA8IGxlbjEgJiYgY29tbW9uSGVhZCA8IGxlbjIgJiZcbiAgICBtYXRjaEl0ZW1zKGFycmF5MSwgYXJyYXkyLCBjb21tb25IZWFkLCBjb21tb25IZWFkLCBtYXRjaENvbnRleHQpKSB7XG4gICAgaW5kZXggPSBjb21tb25IZWFkO1xuICAgIGNoaWxkID0gbmV3IERpZmZDb250ZXh0KGNvbnRleHQubGVmdFtpbmRleF0sIGNvbnRleHQucmlnaHRbaW5kZXhdKTtcbiAgICBjb250ZXh0LnB1c2goY2hpbGQsIGluZGV4KTtcbiAgICBjb21tb25IZWFkKys7XG4gIH1cbiAgLy8gc2VwYXJhdGUgY29tbW9uIHRhaWxcbiAgd2hpbGUgKGNvbW1vblRhaWwgKyBjb21tb25IZWFkIDwgbGVuMSAmJiBjb21tb25UYWlsICsgY29tbW9uSGVhZCA8IGxlbjIgJiZcbiAgICBtYXRjaEl0ZW1zKGFycmF5MSwgYXJyYXkyLCBsZW4xIC0gMSAtIGNvbW1vblRhaWwsIGxlbjIgLSAxIC0gY29tbW9uVGFpbCwgbWF0Y2hDb250ZXh0KSkge1xuICAgIGluZGV4MSA9IGxlbjEgLSAxIC0gY29tbW9uVGFpbDtcbiAgICBpbmRleDIgPSBsZW4yIC0gMSAtIGNvbW1vblRhaWw7XG4gICAgY2hpbGQgPSBuZXcgRGlmZkNvbnRleHQoY29udGV4dC5sZWZ0W2luZGV4MV0sIGNvbnRleHQucmlnaHRbaW5kZXgyXSk7XG4gICAgY29udGV4dC5wdXNoKGNoaWxkLCBpbmRleDIpO1xuICAgIGNvbW1vblRhaWwrKztcbiAgfVxuICB2YXIgcmVzdWx0O1xuICBpZiAoY29tbW9uSGVhZCArIGNvbW1vblRhaWwgPT09IGxlbjEpIHtcbiAgICBpZiAobGVuMSA9PT0gbGVuMikge1xuICAgICAgLy8gYXJyYXlzIGFyZSBpZGVudGljYWxcbiAgICAgIGNvbnRleHQuc2V0UmVzdWx0KHVuZGVmaW5lZCkuZXhpdCgpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICAvLyB0cml2aWFsIGNhc2UsIGEgYmxvY2sgKDEgb3IgbW9yZSBjb25zZWN1dGl2ZSBpdGVtcykgd2FzIGFkZGVkXG4gICAgcmVzdWx0ID0gcmVzdWx0IHx8IHtcbiAgICAgIF90OiAnYSdcbiAgICB9O1xuICAgIGZvciAoaW5kZXggPSBjb21tb25IZWFkOyBpbmRleCA8IGxlbjIgLSBjb21tb25UYWlsOyBpbmRleCsrKSB7XG4gICAgICByZXN1bHRbaW5kZXhdID0gW2FycmF5MltpbmRleF1dO1xuICAgIH1cbiAgICBjb250ZXh0LnNldFJlc3VsdChyZXN1bHQpLmV4aXQoKTtcbiAgICByZXR1cm47XG4gIH1cbiAgaWYgKGNvbW1vbkhlYWQgKyBjb21tb25UYWlsID09PSBsZW4yKSB7XG4gICAgLy8gdHJpdmlhbCBjYXNlLCBhIGJsb2NrICgxIG9yIG1vcmUgY29uc2VjdXRpdmUgaXRlbXMpIHdhcyByZW1vdmVkXG4gICAgcmVzdWx0ID0gcmVzdWx0IHx8IHtcbiAgICAgIF90OiAnYSdcbiAgICB9O1xuICAgIGZvciAoaW5kZXggPSBjb21tb25IZWFkOyBpbmRleCA8IGxlbjEgLSBjb21tb25UYWlsOyBpbmRleCsrKSB7XG4gICAgICByZXN1bHRbJ18nICsgaW5kZXhdID0gW2FycmF5MVtpbmRleF0sIDAsIDBdO1xuICAgIH1cbiAgICBjb250ZXh0LnNldFJlc3VsdChyZXN1bHQpLmV4aXQoKTtcbiAgICByZXR1cm47XG4gIH1cbiAgLy8gcmVzZXQgaGFzaCBjYWNoZVxuICBkZWxldGUgbWF0Y2hDb250ZXh0Lmhhc2hDYWNoZTE7XG4gIGRlbGV0ZSBtYXRjaENvbnRleHQuaGFzaENhY2hlMjtcblxuICAvLyBkaWZmIGlzIG5vdCB0cml2aWFsLCBmaW5kIHRoZSBMQ1MgKExvbmdlc3QgQ29tbW9uIFN1YnNlcXVlbmNlKVxuICB2YXIgdHJpbW1lZDEgPSBhcnJheTEuc2xpY2UoY29tbW9uSGVhZCwgbGVuMSAtIGNvbW1vblRhaWwpO1xuICB2YXIgdHJpbW1lZDIgPSBhcnJheTIuc2xpY2UoY29tbW9uSGVhZCwgbGVuMiAtIGNvbW1vblRhaWwpO1xuICB2YXIgc2VxID0gbGNzLmdldChcbiAgICB0cmltbWVkMSwgdHJpbW1lZDIsXG4gICAgbWF0Y2hJdGVtcyxcbiAgICBtYXRjaENvbnRleHRcbiAgKTtcbiAgdmFyIHJlbW92ZWRJdGVtcyA9IFtdO1xuICByZXN1bHQgPSByZXN1bHQgfHwge1xuICAgIF90OiAnYSdcbiAgfTtcbiAgZm9yIChpbmRleCA9IGNvbW1vbkhlYWQ7IGluZGV4IDwgbGVuMSAtIGNvbW1vblRhaWw7IGluZGV4KyspIHtcbiAgICBpZiAoYXJyYXlJbmRleE9mKHNlcS5pbmRpY2VzMSwgaW5kZXggLSBjb21tb25IZWFkKSA8IDApIHtcbiAgICAgIC8vIHJlbW92ZWRcbiAgICAgIHJlc3VsdFsnXycgKyBpbmRleF0gPSBbYXJyYXkxW2luZGV4XSwgMCwgMF07XG4gICAgICByZW1vdmVkSXRlbXMucHVzaChpbmRleCk7XG4gICAgfVxuICB9XG5cbiAgdmFyIGRldGVjdE1vdmUgPSB0cnVlO1xuICBpZiAoY29udGV4dC5vcHRpb25zICYmIGNvbnRleHQub3B0aW9ucy5hcnJheXMgJiYgY29udGV4dC5vcHRpb25zLmFycmF5cy5kZXRlY3RNb3ZlID09PSBmYWxzZSkge1xuICAgIGRldGVjdE1vdmUgPSBmYWxzZTtcbiAgfVxuICB2YXIgaW5jbHVkZVZhbHVlT25Nb3ZlID0gZmFsc2U7XG4gIGlmIChjb250ZXh0Lm9wdGlvbnMgJiYgY29udGV4dC5vcHRpb25zLmFycmF5cyAmJiBjb250ZXh0Lm9wdGlvbnMuYXJyYXlzLmluY2x1ZGVWYWx1ZU9uTW92ZSkge1xuICAgIGluY2x1ZGVWYWx1ZU9uTW92ZSA9IHRydWU7XG4gIH1cblxuICB2YXIgcmVtb3ZlZEl0ZW1zTGVuZ3RoID0gcmVtb3ZlZEl0ZW1zLmxlbmd0aDtcbiAgZm9yIChpbmRleCA9IGNvbW1vbkhlYWQ7IGluZGV4IDwgbGVuMiAtIGNvbW1vblRhaWw7IGluZGV4KyspIHtcbiAgICB2YXIgaW5kZXhPbkFycmF5MiA9IGFycmF5SW5kZXhPZihzZXEuaW5kaWNlczIsIGluZGV4IC0gY29tbW9uSGVhZCk7XG4gICAgaWYgKGluZGV4T25BcnJheTIgPCAwKSB7XG4gICAgICAvLyBhZGRlZCwgdHJ5IHRvIG1hdGNoIHdpdGggYSByZW1vdmVkIGl0ZW0gYW5kIHJlZ2lzdGVyIGFzIHBvc2l0aW9uIG1vdmVcbiAgICAgIHZhciBpc01vdmUgPSBmYWxzZTtcbiAgICAgIGlmIChkZXRlY3RNb3ZlICYmIHJlbW92ZWRJdGVtc0xlbmd0aCA+IDApIHtcbiAgICAgICAgZm9yICh2YXIgcmVtb3ZlSXRlbUluZGV4MSA9IDA7IHJlbW92ZUl0ZW1JbmRleDEgPCByZW1vdmVkSXRlbXNMZW5ndGg7IHJlbW92ZUl0ZW1JbmRleDErKykge1xuICAgICAgICAgIGluZGV4MSA9IHJlbW92ZWRJdGVtc1tyZW1vdmVJdGVtSW5kZXgxXTtcbiAgICAgICAgICBpZiAobWF0Y2hJdGVtcyh0cmltbWVkMSwgdHJpbW1lZDIsIGluZGV4MSAtIGNvbW1vbkhlYWQsXG4gICAgICAgICAgICBpbmRleCAtIGNvbW1vbkhlYWQsIG1hdGNoQ29udGV4dCkpIHtcbiAgICAgICAgICAgIC8vIHN0b3JlIHBvc2l0aW9uIG1vdmUgYXM6IFtvcmlnaW5hbFZhbHVlLCBuZXdQb3NpdGlvbiwgQVJSQVlfTU9WRV1cbiAgICAgICAgICAgIHJlc3VsdFsnXycgKyBpbmRleDFdLnNwbGljZSgxLCAyLCBpbmRleCwgQVJSQVlfTU9WRSk7XG4gICAgICAgICAgICBpZiAoIWluY2x1ZGVWYWx1ZU9uTW92ZSkge1xuICAgICAgICAgICAgICAvLyBkb24ndCBpbmNsdWRlIG1vdmVkIHZhbHVlIG9uIGRpZmYsIHRvIHNhdmUgYnl0ZXNcbiAgICAgICAgICAgICAgcmVzdWx0WydfJyArIGluZGV4MV1bMF0gPSAnJztcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaW5kZXgyID0gaW5kZXg7XG4gICAgICAgICAgICBjaGlsZCA9IG5ldyBEaWZmQ29udGV4dChjb250ZXh0LmxlZnRbaW5kZXgxXSwgY29udGV4dC5yaWdodFtpbmRleDJdKTtcbiAgICAgICAgICAgIGNvbnRleHQucHVzaChjaGlsZCwgaW5kZXgyKTtcbiAgICAgICAgICAgIHJlbW92ZWRJdGVtcy5zcGxpY2UocmVtb3ZlSXRlbUluZGV4MSwgMSk7XG4gICAgICAgICAgICBpc01vdmUgPSB0cnVlO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICBpZiAoIWlzTW92ZSkge1xuICAgICAgICAvLyBhZGRlZFxuICAgICAgICByZXN1bHRbaW5kZXhdID0gW2FycmF5MltpbmRleF1dO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICAvLyBtYXRjaCwgZG8gaW5uZXIgZGlmZlxuICAgICAgaW5kZXgxID0gc2VxLmluZGljZXMxW2luZGV4T25BcnJheTJdICsgY29tbW9uSGVhZDtcbiAgICAgIGluZGV4MiA9IHNlcS5pbmRpY2VzMltpbmRleE9uQXJyYXkyXSArIGNvbW1vbkhlYWQ7XG4gICAgICBjaGlsZCA9IG5ldyBEaWZmQ29udGV4dChjb250ZXh0LmxlZnRbaW5kZXgxXSwgY29udGV4dC5yaWdodFtpbmRleDJdKTtcbiAgICAgIGNvbnRleHQucHVzaChjaGlsZCwgaW5kZXgyKTtcbiAgICB9XG4gIH1cblxuICBjb250ZXh0LnNldFJlc3VsdChyZXN1bHQpLmV4aXQoKTtcblxufTtcbmRpZmZGaWx0ZXIuZmlsdGVyTmFtZSA9ICdhcnJheXMnO1xuXG52YXIgY29tcGFyZSA9IHtcbiAgbnVtZXJpY2FsbHk6IGZ1bmN0aW9uKGEsIGIpIHtcbiAgICByZXR1cm4gYSAtIGI7XG4gIH0sXG4gIG51bWVyaWNhbGx5Qnk6IGZ1bmN0aW9uKG5hbWUpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24oYSwgYikge1xuICAgICAgcmV0dXJuIGFbbmFtZV0gLSBiW25hbWVdO1xuICAgIH07XG4gIH1cbn07XG5cbnZhciBwYXRjaEZpbHRlciA9IGZ1bmN0aW9uIG5lc3RlZFBhdGNoRmlsdGVyKGNvbnRleHQpIHtcbiAgaWYgKCFjb250ZXh0Lm5lc3RlZCkge1xuICAgIHJldHVybjtcbiAgfVxuICBpZiAoY29udGV4dC5kZWx0YS5fdCAhPT0gJ2EnKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIHZhciBpbmRleCwgaW5kZXgxO1xuXG4gIHZhciBkZWx0YSA9IGNvbnRleHQuZGVsdGE7XG4gIHZhciBhcnJheSA9IGNvbnRleHQubGVmdDtcblxuICAvLyBmaXJzdCwgc2VwYXJhdGUgcmVtb3ZhbHMsIGluc2VydGlvbnMgYW5kIG1vZGlmaWNhdGlvbnNcbiAgdmFyIHRvUmVtb3ZlID0gW107XG4gIHZhciB0b0luc2VydCA9IFtdO1xuICB2YXIgdG9Nb2RpZnkgPSBbXTtcbiAgZm9yIChpbmRleCBpbiBkZWx0YSkge1xuICAgIGlmIChpbmRleCAhPT0gJ190Jykge1xuICAgICAgaWYgKGluZGV4WzBdID09PSAnXycpIHtcbiAgICAgICAgLy8gcmVtb3ZlZCBpdGVtIGZyb20gb3JpZ2luYWwgYXJyYXlcbiAgICAgICAgaWYgKGRlbHRhW2luZGV4XVsyXSA9PT0gMCB8fCBkZWx0YVtpbmRleF1bMl0gPT09IEFSUkFZX01PVkUpIHtcbiAgICAgICAgICB0b1JlbW92ZS5wdXNoKHBhcnNlSW50KGluZGV4LnNsaWNlKDEpLCAxMCkpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcignb25seSByZW1vdmFsIG9yIG1vdmUgY2FuIGJlIGFwcGxpZWQgYXQgb3JpZ2luYWwgYXJyYXkgaW5kaWNlcycgK1xuICAgICAgICAgICAgJywgaW52YWxpZCBkaWZmIHR5cGU6ICcgKyBkZWx0YVtpbmRleF1bMl0pO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBpZiAoZGVsdGFbaW5kZXhdLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICAgIC8vIGFkZGVkIGl0ZW0gYXQgbmV3IGFycmF5XG4gICAgICAgICAgdG9JbnNlcnQucHVzaCh7XG4gICAgICAgICAgICBpbmRleDogcGFyc2VJbnQoaW5kZXgsIDEwKSxcbiAgICAgICAgICAgIHZhbHVlOiBkZWx0YVtpbmRleF1bMF1cbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBtb2RpZmllZCBpdGVtIGF0IG5ldyBhcnJheVxuICAgICAgICAgIHRvTW9kaWZ5LnB1c2goe1xuICAgICAgICAgICAgaW5kZXg6IHBhcnNlSW50KGluZGV4LCAxMCksXG4gICAgICAgICAgICBkZWx0YTogZGVsdGFbaW5kZXhdXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvLyByZW1vdmUgaXRlbXMsIGluIHJldmVyc2Ugb3JkZXIgdG8gYXZvaWQgc2F3aW5nIG91ciBvd24gZmxvb3JcbiAgdG9SZW1vdmUgPSB0b1JlbW92ZS5zb3J0KGNvbXBhcmUubnVtZXJpY2FsbHkpO1xuICBmb3IgKGluZGV4ID0gdG9SZW1vdmUubGVuZ3RoIC0gMTsgaW5kZXggPj0gMDsgaW5kZXgtLSkge1xuICAgIGluZGV4MSA9IHRvUmVtb3ZlW2luZGV4XTtcbiAgICB2YXIgaW5kZXhEaWZmID0gZGVsdGFbJ18nICsgaW5kZXgxXTtcbiAgICB2YXIgcmVtb3ZlZFZhbHVlID0gYXJyYXkuc3BsaWNlKGluZGV4MSwgMSlbMF07XG4gICAgaWYgKGluZGV4RGlmZlsyXSA9PT0gQVJSQVlfTU9WRSkge1xuICAgICAgLy8gcmVpbnNlcnQgbGF0ZXJcbiAgICAgIHRvSW5zZXJ0LnB1c2goe1xuICAgICAgICBpbmRleDogaW5kZXhEaWZmWzFdLFxuICAgICAgICB2YWx1ZTogcmVtb3ZlZFZhbHVlXG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICAvLyBpbnNlcnQgaXRlbXMsIGluIHJldmVyc2Ugb3JkZXIgdG8gYXZvaWQgbW92aW5nIG91ciBvd24gZmxvb3JcbiAgdG9JbnNlcnQgPSB0b0luc2VydC5zb3J0KGNvbXBhcmUubnVtZXJpY2FsbHlCeSgnaW5kZXgnKSk7XG4gIHZhciB0b0luc2VydExlbmd0aCA9IHRvSW5zZXJ0Lmxlbmd0aDtcbiAgZm9yIChpbmRleCA9IDA7IGluZGV4IDwgdG9JbnNlcnRMZW5ndGg7IGluZGV4KyspIHtcbiAgICB2YXIgaW5zZXJ0aW9uID0gdG9JbnNlcnRbaW5kZXhdO1xuICAgIGFycmF5LnNwbGljZShpbnNlcnRpb24uaW5kZXgsIDAsIGluc2VydGlvbi52YWx1ZSk7XG4gIH1cblxuICAvLyBhcHBseSBtb2RpZmljYXRpb25zXG4gIHZhciB0b01vZGlmeUxlbmd0aCA9IHRvTW9kaWZ5Lmxlbmd0aDtcbiAgdmFyIGNoaWxkO1xuICBpZiAodG9Nb2RpZnlMZW5ndGggPiAwKSB7XG4gICAgZm9yIChpbmRleCA9IDA7IGluZGV4IDwgdG9Nb2RpZnlMZW5ndGg7IGluZGV4KyspIHtcbiAgICAgIHZhciBtb2RpZmljYXRpb24gPSB0b01vZGlmeVtpbmRleF07XG4gICAgICBjaGlsZCA9IG5ldyBQYXRjaENvbnRleHQoY29udGV4dC5sZWZ0W21vZGlmaWNhdGlvbi5pbmRleF0sIG1vZGlmaWNhdGlvbi5kZWx0YSk7XG4gICAgICBjb250ZXh0LnB1c2goY2hpbGQsIG1vZGlmaWNhdGlvbi5pbmRleCk7XG4gICAgfVxuICB9XG5cbiAgaWYgKCFjb250ZXh0LmNoaWxkcmVuKSB7XG4gICAgY29udGV4dC5zZXRSZXN1bHQoY29udGV4dC5sZWZ0KS5leGl0KCk7XG4gICAgcmV0dXJuO1xuICB9XG4gIGNvbnRleHQuZXhpdCgpO1xufTtcbnBhdGNoRmlsdGVyLmZpbHRlck5hbWUgPSAnYXJyYXlzJztcblxudmFyIGNvbGxlY3RDaGlsZHJlblBhdGNoRmlsdGVyID0gZnVuY3Rpb24gY29sbGVjdENoaWxkcmVuUGF0Y2hGaWx0ZXIoY29udGV4dCkge1xuICBpZiAoIWNvbnRleHQgfHwgIWNvbnRleHQuY2hpbGRyZW4pIHtcbiAgICByZXR1cm47XG4gIH1cbiAgaWYgKGNvbnRleHQuZGVsdGEuX3QgIT09ICdhJykge1xuICAgIHJldHVybjtcbiAgfVxuICB2YXIgbGVuZ3RoID0gY29udGV4dC5jaGlsZHJlbi5sZW5ndGg7XG4gIHZhciBjaGlsZDtcbiAgZm9yICh2YXIgaW5kZXggPSAwOyBpbmRleCA8IGxlbmd0aDsgaW5kZXgrKykge1xuICAgIGNoaWxkID0gY29udGV4dC5jaGlsZHJlbltpbmRleF07XG4gICAgY29udGV4dC5sZWZ0W2NoaWxkLmNoaWxkTmFtZV0gPSBjaGlsZC5yZXN1bHQ7XG4gIH1cbiAgY29udGV4dC5zZXRSZXN1bHQoY29udGV4dC5sZWZ0KS5leGl0KCk7XG59O1xuY29sbGVjdENoaWxkcmVuUGF0Y2hGaWx0ZXIuZmlsdGVyTmFtZSA9ICdhcnJheXNDb2xsZWN0Q2hpbGRyZW4nO1xuXG52YXIgcmV2ZXJzZUZpbHRlciA9IGZ1bmN0aW9uIGFycmF5c1JldmVyc2VGaWx0ZXIoY29udGV4dCkge1xuICBpZiAoIWNvbnRleHQubmVzdGVkKSB7XG4gICAgaWYgKGNvbnRleHQuZGVsdGFbMl0gPT09IEFSUkFZX01PVkUpIHtcbiAgICAgIGNvbnRleHQubmV3TmFtZSA9ICdfJyArIGNvbnRleHQuZGVsdGFbMV07XG4gICAgICBjb250ZXh0LnNldFJlc3VsdChbY29udGV4dC5kZWx0YVswXSwgcGFyc2VJbnQoY29udGV4dC5jaGlsZE5hbWUuc3Vic3RyKDEpLCAxMCksIEFSUkFZX01PVkVdKS5leGl0KCk7XG4gICAgfVxuICAgIHJldHVybjtcbiAgfVxuICBpZiAoY29udGV4dC5kZWx0YS5fdCAhPT0gJ2EnKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIHZhciBuYW1lLCBjaGlsZDtcbiAgZm9yIChuYW1lIGluIGNvbnRleHQuZGVsdGEpIHtcbiAgICBpZiAobmFtZSA9PT0gJ190Jykge1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIGNoaWxkID0gbmV3IFJldmVyc2VDb250ZXh0KGNvbnRleHQuZGVsdGFbbmFtZV0pO1xuICAgIGNvbnRleHQucHVzaChjaGlsZCwgbmFtZSk7XG4gIH1cbiAgY29udGV4dC5leGl0KCk7XG59O1xucmV2ZXJzZUZpbHRlci5maWx0ZXJOYW1lID0gJ2FycmF5cyc7XG5cbnZhciByZXZlcnNlQXJyYXlEZWx0YUluZGV4ID0gZnVuY3Rpb24oZGVsdGEsIGluZGV4LCBpdGVtRGVsdGEpIHtcbiAgaWYgKHR5cGVvZiBpbmRleCA9PT0gJ3N0cmluZycgJiYgaW5kZXhbMF0gPT09ICdfJykge1xuICAgIHJldHVybiBwYXJzZUludChpbmRleC5zdWJzdHIoMSksIDEwKTtcbiAgfSBlbHNlIGlmIChpc0FycmF5KGl0ZW1EZWx0YSkgJiYgaXRlbURlbHRhWzJdID09PSAwKSB7XG4gICAgcmV0dXJuICdfJyArIGluZGV4O1xuICB9XG5cbiAgdmFyIHJldmVyc2VJbmRleCA9ICtpbmRleDtcbiAgZm9yICh2YXIgZGVsdGFJbmRleCBpbiBkZWx0YSkge1xuICAgIHZhciBkZWx0YUl0ZW0gPSBkZWx0YVtkZWx0YUluZGV4XTtcbiAgICBpZiAoaXNBcnJheShkZWx0YUl0ZW0pKSB7XG4gICAgICBpZiAoZGVsdGFJdGVtWzJdID09PSBBUlJBWV9NT1ZFKSB7XG4gICAgICAgIHZhciBtb3ZlRnJvbUluZGV4ID0gcGFyc2VJbnQoZGVsdGFJbmRleC5zdWJzdHIoMSksIDEwKTtcbiAgICAgICAgdmFyIG1vdmVUb0luZGV4ID0gZGVsdGFJdGVtWzFdO1xuICAgICAgICBpZiAobW92ZVRvSW5kZXggPT09ICtpbmRleCkge1xuICAgICAgICAgIHJldHVybiBtb3ZlRnJvbUluZGV4O1xuICAgICAgICB9XG4gICAgICAgIGlmIChtb3ZlRnJvbUluZGV4IDw9IHJldmVyc2VJbmRleCAmJiBtb3ZlVG9JbmRleCA+IHJldmVyc2VJbmRleCkge1xuICAgICAgICAgIHJldmVyc2VJbmRleCsrO1xuICAgICAgICB9IGVsc2UgaWYgKG1vdmVGcm9tSW5kZXggPj0gcmV2ZXJzZUluZGV4ICYmIG1vdmVUb0luZGV4IDwgcmV2ZXJzZUluZGV4KSB7XG4gICAgICAgICAgcmV2ZXJzZUluZGV4LS07XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoZGVsdGFJdGVtWzJdID09PSAwKSB7XG4gICAgICAgIHZhciBkZWxldGVJbmRleCA9IHBhcnNlSW50KGRlbHRhSW5kZXguc3Vic3RyKDEpLCAxMCk7XG4gICAgICAgIGlmIChkZWxldGVJbmRleCA8PSByZXZlcnNlSW5kZXgpIHtcbiAgICAgICAgICByZXZlcnNlSW5kZXgrKztcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmIChkZWx0YUl0ZW0ubGVuZ3RoID09PSAxICYmIGRlbHRhSW5kZXggPD0gcmV2ZXJzZUluZGV4KSB7XG4gICAgICAgIHJldmVyc2VJbmRleC0tO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiByZXZlcnNlSW5kZXg7XG59O1xuXG52YXIgY29sbGVjdENoaWxkcmVuUmV2ZXJzZUZpbHRlciA9IGZ1bmN0aW9uIGNvbGxlY3RDaGlsZHJlblJldmVyc2VGaWx0ZXIoY29udGV4dCkge1xuICBpZiAoIWNvbnRleHQgfHwgIWNvbnRleHQuY2hpbGRyZW4pIHtcbiAgICByZXR1cm47XG4gIH1cbiAgaWYgKGNvbnRleHQuZGVsdGEuX3QgIT09ICdhJykge1xuICAgIHJldHVybjtcbiAgfVxuICB2YXIgbGVuZ3RoID0gY29udGV4dC5jaGlsZHJlbi5sZW5ndGg7XG4gIHZhciBjaGlsZDtcbiAgdmFyIGRlbHRhID0ge1xuICAgIF90OiAnYSdcbiAgfTtcblxuICBmb3IgKHZhciBpbmRleCA9IDA7IGluZGV4IDwgbGVuZ3RoOyBpbmRleCsrKSB7XG4gICAgY2hpbGQgPSBjb250ZXh0LmNoaWxkcmVuW2luZGV4XTtcbiAgICB2YXIgbmFtZSA9IGNoaWxkLm5ld05hbWU7XG4gICAgaWYgKHR5cGVvZiBuYW1lID09PSAndW5kZWZpbmVkJykge1xuICAgICAgbmFtZSA9IHJldmVyc2VBcnJheURlbHRhSW5kZXgoY29udGV4dC5kZWx0YSwgY2hpbGQuY2hpbGROYW1lLCBjaGlsZC5yZXN1bHQpO1xuICAgIH1cbiAgICBpZiAoZGVsdGFbbmFtZV0gIT09IGNoaWxkLnJlc3VsdCkge1xuICAgICAgZGVsdGFbbmFtZV0gPSBjaGlsZC5yZXN1bHQ7XG4gICAgfVxuICB9XG4gIGNvbnRleHQuc2V0UmVzdWx0KGRlbHRhKS5leGl0KCk7XG59O1xuY29sbGVjdENoaWxkcmVuUmV2ZXJzZUZpbHRlci5maWx0ZXJOYW1lID0gJ2FycmF5c0NvbGxlY3RDaGlsZHJlbic7XG5cbmV4cG9ydHMuZGlmZkZpbHRlciA9IGRpZmZGaWx0ZXI7XG5leHBvcnRzLnBhdGNoRmlsdGVyID0gcGF0Y2hGaWx0ZXI7XG5leHBvcnRzLmNvbGxlY3RDaGlsZHJlblBhdGNoRmlsdGVyID0gY29sbGVjdENoaWxkcmVuUGF0Y2hGaWx0ZXI7XG5leHBvcnRzLnJldmVyc2VGaWx0ZXIgPSByZXZlcnNlRmlsdGVyO1xuZXhwb3J0cy5jb2xsZWN0Q2hpbGRyZW5SZXZlcnNlRmlsdGVyID0gY29sbGVjdENoaWxkcmVuUmV2ZXJzZUZpbHRlcjtcbiIsInZhciBkaWZmRmlsdGVyID0gZnVuY3Rpb24gZGF0ZXNEaWZmRmlsdGVyKGNvbnRleHQpIHtcbiAgaWYgKGNvbnRleHQubGVmdCBpbnN0YW5jZW9mIERhdGUpIHtcbiAgICBpZiAoY29udGV4dC5yaWdodCBpbnN0YW5jZW9mIERhdGUpIHtcbiAgICAgIGlmIChjb250ZXh0LmxlZnQuZ2V0VGltZSgpICE9PSBjb250ZXh0LnJpZ2h0LmdldFRpbWUoKSkge1xuICAgICAgICBjb250ZXh0LnNldFJlc3VsdChbY29udGV4dC5sZWZ0LCBjb250ZXh0LnJpZ2h0XSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb250ZXh0LnNldFJlc3VsdCh1bmRlZmluZWQpO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBjb250ZXh0LnNldFJlc3VsdChbY29udGV4dC5sZWZ0LCBjb250ZXh0LnJpZ2h0XSk7XG4gICAgfVxuICAgIGNvbnRleHQuZXhpdCgpO1xuICB9IGVsc2UgaWYgKGNvbnRleHQucmlnaHQgaW5zdGFuY2VvZiBEYXRlKSB7XG4gICAgY29udGV4dC5zZXRSZXN1bHQoW2NvbnRleHQubGVmdCwgY29udGV4dC5yaWdodF0pLmV4aXQoKTtcbiAgfVxufTtcbmRpZmZGaWx0ZXIuZmlsdGVyTmFtZSA9ICdkYXRlcyc7XG5cbmV4cG9ydHMuZGlmZkZpbHRlciA9IGRpZmZGaWx0ZXI7XG4iLCIvKiBnbG9iYWwgZGlmZl9tYXRjaF9wYXRjaCAqL1xudmFyIFRFWFRfRElGRiA9IDI7XG52YXIgREVGQVVMVF9NSU5fTEVOR1RIID0gNjA7XG52YXIgY2FjaGVkRGlmZlBhdGNoID0gbnVsbDtcblxudmFyIGdldERpZmZNYXRjaFBhdGNoID0gZnVuY3Rpb24ocmVxdWlyZWQpIHtcbiAgLypqc2hpbnQgY2FtZWxjYXNlOiBmYWxzZSAqL1xuXG4gIGlmICghY2FjaGVkRGlmZlBhdGNoKSB7XG4gICAgdmFyIGluc3RhbmNlO1xuICAgIGlmICh0eXBlb2YgZGlmZl9tYXRjaF9wYXRjaCAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgIC8vIGFscmVhZHkgbG9hZGVkLCBwcm9iYWJseSBhIGJyb3dzZXJcbiAgICAgIGluc3RhbmNlID0gdHlwZW9mIGRpZmZfbWF0Y2hfcGF0Y2ggPT09ICdmdW5jdGlvbicgP1xuICAgICAgICBuZXcgZGlmZl9tYXRjaF9wYXRjaCgpIDogbmV3IGRpZmZfbWF0Y2hfcGF0Y2guZGlmZl9tYXRjaF9wYXRjaCgpO1xuICAgIH0gZWxzZSBpZiAodHlwZW9mIHJlcXVpcmUgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHZhciBkbXBNb2R1bGVOYW1lID0gJ2RpZmZfbWF0Y2hfcGF0Y2hfdW5jb21wcmVzc2VkJztcbiAgICAgICAgdmFyIGRtcCA9IHJlcXVpcmUoJy4uLy4uL3B1YmxpYy9leHRlcm5hbC8nICsgZG1wTW9kdWxlTmFtZSk7XG4gICAgICAgIGluc3RhbmNlID0gbmV3IGRtcC5kaWZmX21hdGNoX3BhdGNoKCk7XG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgaW5zdGFuY2UgPSBudWxsO1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAoIWluc3RhbmNlKSB7XG4gICAgICBpZiAoIXJlcXVpcmVkKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuICAgICAgdmFyIGVycm9yID0gbmV3IEVycm9yKCd0ZXh0IGRpZmZfbWF0Y2hfcGF0Y2ggbGlicmFyeSBub3QgZm91bmQnKTtcbiAgICAgIGVycm9yLmRpZmZfbWF0Y2hfcGF0Y2hfbm90X2ZvdW5kID0gdHJ1ZTtcbiAgICAgIHRocm93IGVycm9yO1xuICAgIH1cbiAgICBjYWNoZWREaWZmUGF0Y2ggPSB7XG4gICAgICBkaWZmOiBmdW5jdGlvbih0eHQxLCB0eHQyKSB7XG4gICAgICAgIHJldHVybiBpbnN0YW5jZS5wYXRjaF90b1RleHQoaW5zdGFuY2UucGF0Y2hfbWFrZSh0eHQxLCB0eHQyKSk7XG4gICAgICB9LFxuICAgICAgcGF0Y2g6IGZ1bmN0aW9uKHR4dDEsIHBhdGNoKSB7XG4gICAgICAgIHZhciByZXN1bHRzID0gaW5zdGFuY2UucGF0Y2hfYXBwbHkoaW5zdGFuY2UucGF0Y2hfZnJvbVRleHQocGF0Y2gpLCB0eHQxKTtcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCByZXN1bHRzWzFdLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgaWYgKCFyZXN1bHRzWzFdW2ldKSB7XG4gICAgICAgICAgICB2YXIgZXJyb3IgPSBuZXcgRXJyb3IoJ3RleHQgcGF0Y2ggZmFpbGVkJyk7XG4gICAgICAgICAgICBlcnJvci50ZXh0UGF0Y2hGYWlsZWQgPSB0cnVlO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcmVzdWx0c1swXTtcbiAgICAgIH1cbiAgICB9O1xuICB9XG4gIHJldHVybiBjYWNoZWREaWZmUGF0Y2g7XG59O1xuXG52YXIgZGlmZkZpbHRlciA9IGZ1bmN0aW9uIHRleHRzRGlmZkZpbHRlcihjb250ZXh0KSB7XG4gIGlmIChjb250ZXh0LmxlZnRUeXBlICE9PSAnc3RyaW5nJykge1xuICAgIHJldHVybjtcbiAgfVxuICB2YXIgbWluTGVuZ3RoID0gKGNvbnRleHQub3B0aW9ucyAmJiBjb250ZXh0Lm9wdGlvbnMudGV4dERpZmYgJiZcbiAgICBjb250ZXh0Lm9wdGlvbnMudGV4dERpZmYubWluTGVuZ3RoKSB8fCBERUZBVUxUX01JTl9MRU5HVEg7XG4gIGlmIChjb250ZXh0LmxlZnQubGVuZ3RoIDwgbWluTGVuZ3RoIHx8XG4gICAgY29udGV4dC5yaWdodC5sZW5ndGggPCBtaW5MZW5ndGgpIHtcbiAgICBjb250ZXh0LnNldFJlc3VsdChbY29udGV4dC5sZWZ0LCBjb250ZXh0LnJpZ2h0XSkuZXhpdCgpO1xuICAgIHJldHVybjtcbiAgfVxuICAvLyBsYXJnZSB0ZXh0LCB0cnkgdG8gdXNlIGEgdGV4dC1kaWZmIGFsZ29yaXRobVxuICB2YXIgZGlmZk1hdGNoUGF0Y2ggPSBnZXREaWZmTWF0Y2hQYXRjaCgpO1xuICBpZiAoIWRpZmZNYXRjaFBhdGNoKSB7XG4gICAgLy8gZGlmZi1tYXRjaC1wYXRjaCBsaWJyYXJ5IG5vdCBhdmFpbGFibGUsIGZhbGxiYWNrIHRvIHJlZ3VsYXIgc3RyaW5nIHJlcGxhY2VcbiAgICBjb250ZXh0LnNldFJlc3VsdChbY29udGV4dC5sZWZ0LCBjb250ZXh0LnJpZ2h0XSkuZXhpdCgpO1xuICAgIHJldHVybjtcbiAgfVxuICB2YXIgZGlmZiA9IGRpZmZNYXRjaFBhdGNoLmRpZmY7XG4gIGNvbnRleHQuc2V0UmVzdWx0KFtkaWZmKGNvbnRleHQubGVmdCwgY29udGV4dC5yaWdodCksIDAsIFRFWFRfRElGRl0pLmV4aXQoKTtcbn07XG5kaWZmRmlsdGVyLmZpbHRlck5hbWUgPSAndGV4dHMnO1xuXG52YXIgcGF0Y2hGaWx0ZXIgPSBmdW5jdGlvbiB0ZXh0c1BhdGNoRmlsdGVyKGNvbnRleHQpIHtcbiAgaWYgKGNvbnRleHQubmVzdGVkKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIGlmIChjb250ZXh0LmRlbHRhWzJdICE9PSBURVhUX0RJRkYpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICAvLyB0ZXh0LWRpZmYsIHVzZSBhIHRleHQtcGF0Y2ggYWxnb3JpdGhtXG4gIHZhciBwYXRjaCA9IGdldERpZmZNYXRjaFBhdGNoKHRydWUpLnBhdGNoO1xuICBjb250ZXh0LnNldFJlc3VsdChwYXRjaChjb250ZXh0LmxlZnQsIGNvbnRleHQuZGVsdGFbMF0pKS5leGl0KCk7XG59O1xucGF0Y2hGaWx0ZXIuZmlsdGVyTmFtZSA9ICd0ZXh0cyc7XG5cbnZhciB0ZXh0RGVsdGFSZXZlcnNlID0gZnVuY3Rpb24oZGVsdGEpIHtcbiAgdmFyIGksIGwsIGxpbmVzLCBsaW5lLCBsaW5lVG1wLCBoZWFkZXIgPSBudWxsLFxuICAgIGhlYWRlclJlZ2V4ID0gL15AQCArXFwtKFxcZCspLChcXGQrKSArXFwrKFxcZCspLChcXGQrKSArQEAkLyxcbiAgICBsaW5lSGVhZGVyLCBsaW5lQWRkLCBsaW5lUmVtb3ZlO1xuICBsaW5lcyA9IGRlbHRhLnNwbGl0KCdcXG4nKTtcbiAgZm9yIChpID0gMCwgbCA9IGxpbmVzLmxlbmd0aDsgaSA8IGw7IGkrKykge1xuICAgIGxpbmUgPSBsaW5lc1tpXTtcbiAgICB2YXIgbGluZVN0YXJ0ID0gbGluZS5zbGljZSgwLCAxKTtcbiAgICBpZiAobGluZVN0YXJ0ID09PSAnQCcpIHtcbiAgICAgIGhlYWRlciA9IGhlYWRlclJlZ2V4LmV4ZWMobGluZSk7XG4gICAgICBsaW5lSGVhZGVyID0gaTtcbiAgICAgIGxpbmVBZGQgPSBudWxsO1xuICAgICAgbGluZVJlbW92ZSA9IG51bGw7XG5cbiAgICAgIC8vIGZpeCBoZWFkZXJcbiAgICAgIGxpbmVzW2xpbmVIZWFkZXJdID0gJ0BAIC0nICsgaGVhZGVyWzNdICsgJywnICsgaGVhZGVyWzRdICsgJyArJyArIGhlYWRlclsxXSArICcsJyArIGhlYWRlclsyXSArICcgQEAnO1xuICAgIH0gZWxzZSBpZiAobGluZVN0YXJ0ID09PSAnKycpIHtcbiAgICAgIGxpbmVBZGQgPSBpO1xuICAgICAgbGluZXNbaV0gPSAnLScgKyBsaW5lc1tpXS5zbGljZSgxKTtcbiAgICAgIGlmIChsaW5lc1tpIC0gMV0uc2xpY2UoMCwgMSkgPT09ICcrJykge1xuICAgICAgICAvLyBzd2FwIGxpbmVzIHRvIGtlZXAgZGVmYXVsdCBvcmRlciAoLSspXG4gICAgICAgIGxpbmVUbXAgPSBsaW5lc1tpXTtcbiAgICAgICAgbGluZXNbaV0gPSBsaW5lc1tpIC0gMV07XG4gICAgICAgIGxpbmVzW2kgLSAxXSA9IGxpbmVUbXA7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChsaW5lU3RhcnQgPT09ICctJykge1xuICAgICAgbGluZVJlbW92ZSA9IGk7XG4gICAgICBsaW5lc1tpXSA9ICcrJyArIGxpbmVzW2ldLnNsaWNlKDEpO1xuICAgIH1cbiAgfVxuICByZXR1cm4gbGluZXMuam9pbignXFxuJyk7XG59O1xuXG52YXIgcmV2ZXJzZUZpbHRlciA9IGZ1bmN0aW9uIHRleHRzUmV2ZXJzZUZpbHRlcihjb250ZXh0KSB7XG4gIGlmIChjb250ZXh0Lm5lc3RlZCkge1xuICAgIHJldHVybjtcbiAgfVxuICBpZiAoY29udGV4dC5kZWx0YVsyXSAhPT0gVEVYVF9ESUZGKSB7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgLy8gdGV4dC1kaWZmLCB1c2UgYSB0ZXh0LWRpZmYgYWxnb3JpdGhtXG4gIGNvbnRleHQuc2V0UmVzdWx0KFt0ZXh0RGVsdGFSZXZlcnNlKGNvbnRleHQuZGVsdGFbMF0pLCAwLCBURVhUX0RJRkZdKS5leGl0KCk7XG59O1xucmV2ZXJzZUZpbHRlci5maWx0ZXJOYW1lID0gJ3RleHRzJztcblxuZXhwb3J0cy5kaWZmRmlsdGVyID0gZGlmZkZpbHRlcjtcbmV4cG9ydHMucGF0Y2hGaWx0ZXIgPSBwYXRjaEZpbHRlcjtcbmV4cG9ydHMucmV2ZXJzZUZpbHRlciA9IHJldmVyc2VGaWx0ZXI7XG4iLCJ2YXIgUHJvY2Vzc29yID0gcmVxdWlyZSgnLi9wcm9jZXNzb3InKS5Qcm9jZXNzb3I7XG52YXIgUGlwZSA9IHJlcXVpcmUoJy4vcGlwZScpLlBpcGU7XG52YXIgRGlmZkNvbnRleHQgPSByZXF1aXJlKCcuL2NvbnRleHRzL2RpZmYnKS5EaWZmQ29udGV4dDtcbnZhciBQYXRjaENvbnRleHQgPSByZXF1aXJlKCcuL2NvbnRleHRzL3BhdGNoJykuUGF0Y2hDb250ZXh0O1xudmFyIFJldmVyc2VDb250ZXh0ID0gcmVxdWlyZSgnLi9jb250ZXh0cy9yZXZlcnNlJykuUmV2ZXJzZUNvbnRleHQ7XG5cbnZhciBjbG9uZSA9IHJlcXVpcmUoJy4vY2xvbmUnKTtcblxudmFyIHRyaXZpYWwgPSByZXF1aXJlKCcuL2ZpbHRlcnMvdHJpdmlhbCcpO1xudmFyIG5lc3RlZCA9IHJlcXVpcmUoJy4vZmlsdGVycy9uZXN0ZWQnKTtcbnZhciBhcnJheXMgPSByZXF1aXJlKCcuL2ZpbHRlcnMvYXJyYXlzJyk7XG52YXIgZGF0ZXMgPSByZXF1aXJlKCcuL2ZpbHRlcnMvZGF0ZXMnKTtcbnZhciB0ZXh0cyA9IHJlcXVpcmUoJy4vZmlsdGVycy90ZXh0cycpO1xuXG52YXIgRGlmZlBhdGNoZXIgPSBmdW5jdGlvbiBEaWZmUGF0Y2hlcihvcHRpb25zKSB7XG4gIHRoaXMucHJvY2Vzc29yID0gbmV3IFByb2Nlc3NvcihvcHRpb25zKTtcbiAgdGhpcy5wcm9jZXNzb3IucGlwZShuZXcgUGlwZSgnZGlmZicpLmFwcGVuZChcbiAgICBuZXN0ZWQuY29sbGVjdENoaWxkcmVuRGlmZkZpbHRlcixcbiAgICB0cml2aWFsLmRpZmZGaWx0ZXIsXG4gICAgZGF0ZXMuZGlmZkZpbHRlcixcbiAgICB0ZXh0cy5kaWZmRmlsdGVyLFxuICAgIG5lc3RlZC5vYmplY3RzRGlmZkZpbHRlcixcbiAgICBhcnJheXMuZGlmZkZpbHRlclxuICApLnNob3VsZEhhdmVSZXN1bHQoKSk7XG4gIHRoaXMucHJvY2Vzc29yLnBpcGUobmV3IFBpcGUoJ3BhdGNoJykuYXBwZW5kKFxuICAgIG5lc3RlZC5jb2xsZWN0Q2hpbGRyZW5QYXRjaEZpbHRlcixcbiAgICBhcnJheXMuY29sbGVjdENoaWxkcmVuUGF0Y2hGaWx0ZXIsXG4gICAgdHJpdmlhbC5wYXRjaEZpbHRlcixcbiAgICB0ZXh0cy5wYXRjaEZpbHRlcixcbiAgICBuZXN0ZWQucGF0Y2hGaWx0ZXIsXG4gICAgYXJyYXlzLnBhdGNoRmlsdGVyXG4gICkuc2hvdWxkSGF2ZVJlc3VsdCgpKTtcbiAgdGhpcy5wcm9jZXNzb3IucGlwZShuZXcgUGlwZSgncmV2ZXJzZScpLmFwcGVuZChcbiAgICBuZXN0ZWQuY29sbGVjdENoaWxkcmVuUmV2ZXJzZUZpbHRlcixcbiAgICBhcnJheXMuY29sbGVjdENoaWxkcmVuUmV2ZXJzZUZpbHRlcixcbiAgICB0cml2aWFsLnJldmVyc2VGaWx0ZXIsXG4gICAgdGV4dHMucmV2ZXJzZUZpbHRlcixcbiAgICBuZXN0ZWQucmV2ZXJzZUZpbHRlcixcbiAgICBhcnJheXMucmV2ZXJzZUZpbHRlclxuICApLnNob3VsZEhhdmVSZXN1bHQoKSk7XG59O1xuXG5EaWZmUGF0Y2hlci5wcm90b3R5cGUub3B0aW9ucyA9IGZ1bmN0aW9uKCkge1xuICByZXR1cm4gdGhpcy5wcm9jZXNzb3Iub3B0aW9ucy5hcHBseSh0aGlzLnByb2Nlc3NvciwgYXJndW1lbnRzKTtcbn07XG5cbkRpZmZQYXRjaGVyLnByb3RvdHlwZS5kaWZmID0gZnVuY3Rpb24obGVmdCwgcmlnaHQpIHtcbiAgcmV0dXJuIHRoaXMucHJvY2Vzc29yLnByb2Nlc3MobmV3IERpZmZDb250ZXh0KGxlZnQsIHJpZ2h0KSk7XG59O1xuXG5EaWZmUGF0Y2hlci5wcm90b3R5cGUucGF0Y2ggPSBmdW5jdGlvbihsZWZ0LCBkZWx0YSkge1xuICByZXR1cm4gdGhpcy5wcm9jZXNzb3IucHJvY2VzcyhuZXcgUGF0Y2hDb250ZXh0KGxlZnQsIGRlbHRhKSk7XG59O1xuXG5EaWZmUGF0Y2hlci5wcm90b3R5cGUucmV2ZXJzZSA9IGZ1bmN0aW9uKGRlbHRhKSB7XG4gIHJldHVybiB0aGlzLnByb2Nlc3Nvci5wcm9jZXNzKG5ldyBSZXZlcnNlQ29udGV4dChkZWx0YSkpO1xufTtcblxuRGlmZlBhdGNoZXIucHJvdG90eXBlLnVucGF0Y2ggPSBmdW5jdGlvbihyaWdodCwgZGVsdGEpIHtcbiAgcmV0dXJuIHRoaXMucGF0Y2gocmlnaHQsIHRoaXMucmV2ZXJzZShkZWx0YSkpO1xufTtcblxuRGlmZlBhdGNoZXIucHJvdG90eXBlLmNsb25lID0gZnVuY3Rpb24odmFsdWUpIHtcbiAgcmV0dXJuIGNsb25lKHZhbHVlKTtcbn07XG5cbmV4cG9ydHMuRGlmZlBhdGNoZXIgPSBEaWZmUGF0Y2hlcjtcbiIsIi8vIHVzZSBhcyAybmQgcGFyYW1ldGVyIGZvciBKU09OLnBhcnNlIHRvIHJldml2ZSBEYXRlIGluc3RhbmNlc1xubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBkYXRlUmV2aXZlcihrZXksIHZhbHVlKSB7XG4gIHZhciBwYXJ0cztcbiAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycpIHtcbiAgICBwYXJ0cyA9IC9eKFxcZHs0fSktKFxcZHsyfSktKFxcZHsyfSlUKFxcZHsyfSk6KFxcZHsyfSk6KFxcZHsyfSkoPzpcXC4oXFxkKikpPyhafChbK1xcLV0pKFxcZHsyfSk6KFxcZHsyfSkpJC8uZXhlYyh2YWx1ZSk7XG4gICAgaWYgKHBhcnRzKSB7XG4gICAgICByZXR1cm4gbmV3IERhdGUoRGF0ZS5VVEMoK3BhcnRzWzFdLCArcGFydHNbMl0gLSAxLCArcGFydHNbM10sICtwYXJ0c1s0XSwgK3BhcnRzWzVdLCArcGFydHNbNl0sICsocGFydHNbN10gfHwgMCkpKTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHZhbHVlO1xufTtcbiIsIlxudmFyIGVudmlyb25tZW50ID0gcmVxdWlyZSgnLi9lbnZpcm9ubWVudCcpO1xuXG52YXIgRGlmZlBhdGNoZXIgPSByZXF1aXJlKCcuL2RpZmZwYXRjaGVyJykuRGlmZlBhdGNoZXI7XG5leHBvcnRzLkRpZmZQYXRjaGVyID0gRGlmZlBhdGNoZXI7XG5cbmV4cG9ydHMuY3JlYXRlID0gZnVuY3Rpb24ob3B0aW9ucyl7XG4gIHJldHVybiBuZXcgRGlmZlBhdGNoZXIob3B0aW9ucyk7XG59O1xuXG5leHBvcnRzLmRhdGVSZXZpdmVyID0gcmVxdWlyZSgnLi9kYXRlLXJldml2ZXInKTtcblxudmFyIGRlZmF1bHRJbnN0YW5jZTtcblxuZXhwb3J0cy5kaWZmID0gZnVuY3Rpb24oKSB7XG4gIGlmICghZGVmYXVsdEluc3RhbmNlKSB7XG4gICAgZGVmYXVsdEluc3RhbmNlID0gbmV3IERpZmZQYXRjaGVyKCk7XG4gIH1cbiAgcmV0dXJuIGRlZmF1bHRJbnN0YW5jZS5kaWZmLmFwcGx5KGRlZmF1bHRJbnN0YW5jZSwgYXJndW1lbnRzKTtcbn07XG5cbmV4cG9ydHMucGF0Y2ggPSBmdW5jdGlvbigpIHtcbiAgaWYgKCFkZWZhdWx0SW5zdGFuY2UpIHtcbiAgICBkZWZhdWx0SW5zdGFuY2UgPSBuZXcgRGlmZlBhdGNoZXIoKTtcbiAgfVxuICByZXR1cm4gZGVmYXVsdEluc3RhbmNlLnBhdGNoLmFwcGx5KGRlZmF1bHRJbnN0YW5jZSwgYXJndW1lbnRzKTtcbn07XG5cbmV4cG9ydHMudW5wYXRjaCA9IGZ1bmN0aW9uKCkge1xuICBpZiAoIWRlZmF1bHRJbnN0YW5jZSkge1xuICAgIGRlZmF1bHRJbnN0YW5jZSA9IG5ldyBEaWZmUGF0Y2hlcigpO1xuICB9XG4gIHJldHVybiBkZWZhdWx0SW5zdGFuY2UudW5wYXRjaC5hcHBseShkZWZhdWx0SW5zdGFuY2UsIGFyZ3VtZW50cyk7XG59O1xuXG5leHBvcnRzLnJldmVyc2UgPSBmdW5jdGlvbigpIHtcbiAgaWYgKCFkZWZhdWx0SW5zdGFuY2UpIHtcbiAgICBkZWZhdWx0SW5zdGFuY2UgPSBuZXcgRGlmZlBhdGNoZXIoKTtcbiAgfVxuICByZXR1cm4gZGVmYXVsdEluc3RhbmNlLnJldmVyc2UuYXBwbHkoZGVmYXVsdEluc3RhbmNlLCBhcmd1bWVudHMpO1xufTtcblxuZXhwb3J0cy5jbG9uZSA9IGZ1bmN0aW9uKCkge1xuICBpZiAoIWRlZmF1bHRJbnN0YW5jZSkge1xuICAgIGRlZmF1bHRJbnN0YW5jZSA9IG5ldyBEaWZmUGF0Y2hlcigpO1xuICB9XG4gIHJldHVybiBkZWZhdWx0SW5zdGFuY2UuY2xvbmUuYXBwbHkoZGVmYXVsdEluc3RhbmNlLCBhcmd1bWVudHMpO1xufTtcblxuXG5pZiAoZW52aXJvbm1lbnQuaXNCcm93c2VyKSB7XG4gIGV4cG9ydHMuaG9tZXBhZ2UgPSAne3twYWNrYWdlLWhvbWVwYWdlfX0nO1xuICBleHBvcnRzLnZlcnNpb24gPSAne3twYWNrYWdlLXZlcnNpb259fSc7XG59IGVsc2Uge1xuICB2YXIgcGFja2FnZUluZm9Nb2R1bGVOYW1lID0gJy4uL3BhY2thZ2UuanNvbic7XG4gIHZhciBwYWNrYWdlSW5mbyA9IHJlcXVpcmUocGFja2FnZUluZm9Nb2R1bGVOYW1lKTtcbiAgZXhwb3J0cy5ob21lcGFnZSA9IHBhY2thZ2VJbmZvLmhvbWVwYWdlO1xuICBleHBvcnRzLnZlcnNpb24gPSBwYWNrYWdlSW5mby52ZXJzaW9uO1xuXG4gIHZhciBmb3JtYXR0ZXJNb2R1bGVOYW1lID0gJy4vZm9ybWF0dGVycyc7XG4gIHZhciBmb3JtYXR0ZXJzID0gcmVxdWlyZShmb3JtYXR0ZXJNb2R1bGVOYW1lKTtcbiAgZXhwb3J0cy5mb3JtYXR0ZXJzID0gZm9ybWF0dGVycztcbiAgLy8gc2hvcnRjdXQgZm9yIGNvbnNvbGVcbiAgZXhwb3J0cy5jb25zb2xlID0gZm9ybWF0dGVycy5jb25zb2xlO1xufVxuIiwiZXhwb3J0IGZ1bmN0aW9uIHBhY2sgeFxuICAgIEpTT04uc3RyaW5naWZ5IHgsIChrZXksIHZhbCkgLT5cbiAgICAgICAgaWYgdHlwZW9mISB2YWwgaXMgXFxGdW5jdGlvblxuICAgICAgICAgICAgcmV0dXJuIHZhbCArICcnICAjIGltcGxpY2l0bHkgY29udmVydCB0byBzdHJpbmdcbiAgICAgICAgI2Vsc2UgaWYgdmFsIGlzIHVuZGVmaW5lZCAgPT4gcmV0dXJuIG51bGwgIyBETyBOT1QgRE8gVEhBVCFcbiAgICAgICAgdmFsXG5cbmV4cG9ydCBmdW5jdGlvbiB1bnBhY2sgeFxuICAgIEpTT04ucGFyc2UgeFxuXG5leHBvcnQgY2xhc3MgQ2xvbmVFcnJvciBleHRlbmRzIEVycm9yXG4gICAgKEBtZXNzYWdlLCBAYXJndW1lbnQpIC0+XG4gICAgICAgIHN1cGVyIC4uLlxuICAgICAgICBFcnJvci5jYXB0dXJlU3RhY2tUcmFjZSh0aGlzLCBDbG9uZUVycm9yKVxuXG5cbmV4cG9ydCBjbG9uZSA9ICh4KSAtPlxuICAgIGlmIHR5cGVvZiEgeCBpbiA8WyBPYmplY3QgQXJyYXkgXT5cbiAgICAgICAgdW5wYWNrIHBhY2sgeFxuICAgIGVsc2VcbiAgICAgICAgdGhyb3cgbmV3IENsb25lRXJyb3IgXCJhcmd1bWVudCBtdXN0IGJlIG9iamVjdCBvciBhcnJheSwgc3VwcGxpZWQ6ICN7cGFjayB4fVwiLCB4XG5cblxucmVxdWlyZSEgXFxqc29uZGlmZnBhdGNoXG5cbmV4cG9ydCBkaWZmID0gKGEsIGIpIC0+XG4gICAganNvbmRpZmZwYXRjaC5kaWZmIGEsIGJcbiIsInJlcXVpcmUhICcuL3BhY2tpbmcnOiB7cGFja31cblxuLyoqIC9cbmV4cG9ydCBtZXJnZSA9IChvYmoxLCBvYmoyKSAtPlxuICAgIGlmICh0eXBlb2YhIG9iajEgaXMgXFxBcnJheSkgYW5kICh0eXBlb2YhIG9iajIgaXMgXFxBcnJheSlcbiAgICAgICAgZm9yIGkgaW4gb2JqMlxuICAgICAgICAgICAgdHJ5XG4gICAgICAgICAgICAgICAgZm9yIGogaW4gb2JqMVxuICAgICAgICAgICAgICAgICAgICB0aHJvdyBpZiBwYWNrKGkpIGlzIHBhY2soailcbiAgICAgICAgICAgICAgICAjIGFwcGVuZCBpZiBpdGVtIGlzIG5vdCBmb3VuZCBpbiBmaXJzdCBvbmVcbiAgICAgICAgICAgICAgICBvYmoxLnB1c2ggaVxuICAgICAgICByZXR1cm4gb2JqMVxuICAgIGVsc2VcbiAgICAgICAgZm9yIHAgb2Ygb2JqMlxuICAgICAgICAgICAgdHJ5XG4gICAgICAgICAgICAgICAgdGhyb3cgaWYgdHlwZW9mISBvYmoyW3BdIGlzbnQgXFxPYmplY3RcbiAgICAgICAgICAgICAgICB0aHJvdyBpZiB0eXBlb2YhIG9iajFbcF0gaXNudCBcXE9iamVjdFxuICAgICAgICAgICAgICAgICMgZ28gb24gaWYgYW5kIG9ubHkgaWYgcmlnaHQgaGFuZCBpcyBvYmplY3RcbiAgICAgICAgICAgICAgICBvYmoxW3BdIGBtZXJnZWAgb2JqMltwXVxuICAgICAgICAgICAgY2F0Y2hcbiAgICAgICAgICAgICAgICBpZiBBcnJheS5pc0FycmF5IG9iajFbcF1cbiAgICAgICAgICAgICAgICAgICAgIyBhcnJheSwgbWVyZ2Ugd2l0aCBjdXJyZW50IG9uZVxuICAgICAgICAgICAgICAgICAgICBmb3IgaSwgaiBvZiBvYmoyW3BdXG4gICAgICAgICAgICAgICAgICAgICAgICB0cnlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3IgYSBpbiBvYmoxW3BdXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IGlmIHBhY2soYSkgaXMgcGFjayhqKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9iajFbcF0ucHVzaCBqXG4gICAgICAgICAgICAgICAgZWxzZSBpZiBvYmoyW3BdIGlzbnQgdm9pZFxuICAgICAgICAgICAgICAgICAgICBvYmoxW3BdID0gb2JqMltwXVxuICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAgZGVsZXRlIG9iajFbcF1cbiAgICAgICAgb2JqMVxuXG4vKiovXG5cbmV4cG9ydCBmdW5jdGlvbiBtZXJnZSBvYmoxLCBvYmoyXG4gICAgaWYgKHR5cGVvZiEgb2JqMSBpcyBcXEFycmF5KSBhbmQgKHR5cGVvZiEgb2JqMiBpcyBcXEFycmF5KVxuICAgICAgICBmb3IgaSBpbiBvYmoyXG4gICAgICAgICAgICB0cnlcbiAgICAgICAgICAgICAgICBmb3IgaiBpbiBvYmoxXG4gICAgICAgICAgICAgICAgICAgIHRocm93IGlmIHBhY2soaSkgaXMgcGFjayhqKVxuICAgICAgICAgICAgICAgICMgYXBwZW5kIGlmIGl0ZW0gaXMgbm90IGZvdW5kIGluIGZpcnN0IG9uZVxuICAgICAgICAgICAgICAgIG9iajEucHVzaCBpXG4gICAgICAgIHJldHVybiBvYmoxXG4gICAgZWxzZVxuICAgICAgICBmb3IgcCBvZiBvYmoyXG4gICAgICAgICAgICB0LW9iajEgPSB0eXBlb2YhIG9iajFbcF1cbiAgICAgICAgICAgIGlmIHR5cGVvZiEgb2JqMltwXSBpbiA8WyBPYmplY3QgQXJyYXkgXT5cbiAgICAgICAgICAgICAgICBpZiB0LW9iajEgaW4gPFsgT2JqZWN0IEFycmF5IF0+XG4gICAgICAgICAgICAgICAgICAgIG9iajFbcF0gYG1lcmdlYCBvYmoyW3BdXG4gICAgICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgICAgICBvYmoxW3BdID0gb2JqMltwXVxuICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgIGlmIG9iajJbcF0gaXNudCB2b2lkXG4gICAgICAgICAgICAgICAgICAgIG9iajFbcF0gPSBvYmoyW3BdXG4gICAgICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgICAgICBkZWxldGUgb2JqMVtwXVxuICAgICAgICBvYmoxXG4vKiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1lcmdlLWFsbCAob2JqMSwgLi4uc291cmNlcylcbiAgICBmb3Igb2JqMiBpbiBzb3VyY2VzXG4gICAgICAgICMgbWVyZ2UgcmVzdCBvbmUgYnkgb25lXG4gICAgICAgIG9iajEgYG1lcmdlYCBvYmoyXG4gICAgb2JqMVxuXG5cblxuZXhwb3J0IGJhc2VkLW9uID0gKGEsIGIpIC0+XG4gICAgIyBpbnZlcnNlIGFyZ3VtZW50IG9yZGVyIG9mIG1lcmdlXG4gICAgKGIgb3Ige30pIGBtZXJnZWAgKGEgb3Ige30pXG5cblxudGVzdHMgPVxuICAgICdzaW1wbGUgbWVyZ2UnOiAtPlxuICAgICAgICBhPVxuICAgICAgICAgIGE6IDFcbiAgICAgICAgICBiOiAyXG5cbiAgICAgICAgYj1cbiAgICAgICAgICBjOiA1XG5cbiAgICAgICAgcmVzdWx0ID0gYSBgbWVyZ2VgIGJcblxuICAgICAgICBleHBlY3RlZCA9XG4gICAgICAgICAgICBhOiAxXG4gICAgICAgICAgICBiOiAyXG4gICAgICAgICAgICBjOiA1XG5cbiAgICAgICAge3Jlc3VsdCwgZXhwZWN0ZWR9XG5cbiAgICAnc2ltcGxlIG1lcmdlMic6IC0+XG4gICAgICAgIGE9XG4gICAgICAgICAgYTogMVxuICAgICAgICAgIGI6IDJcbiAgICAgICAgICBjOlxuICAgICAgICAgICAgY2E6IDFcbiAgICAgICAgICAgIGNiOiAyXG4gICAgICAgIGI9XG4gICAgICAgICAgYzpcbiAgICAgICAgICAgIGNiOiA1XG5cbiAgICAgICAgcmVzdWx0ID0gYSBgbWVyZ2VgIGJcblxuICAgICAgICBleHBlY3RlZCA9XG4gICAgICAgICAgICBhOiAxXG4gICAgICAgICAgICBiOiAyXG4gICAgICAgICAgICBjOlxuICAgICAgICAgICAgICAgIGNhOiAxXG4gICAgICAgICAgICAgICAgY2I6IDVcblxuICAgICAgICB7cmVzdWx0LCBleHBlY3RlZH1cblxuICAgICdtZXJnZSBsaXN0cyc6IC0+XG4gICAgICAgIGE9XG4gICAgICAgICAgYTogMVxuICAgICAgICAgIGI6IDJcbiAgICAgICAgICBjOiBbMSwgMl1cbiAgICAgICAgYj1cbiAgICAgICAgICBiOiA4XG4gICAgICAgICAgYzogWzEsIDRdXG5cbiAgICAgICAgcmVzdWx0ID0gYSBgbWVyZ2VgIGJcblxuICAgICAgICBleHBlY3RlZCA9XG4gICAgICAgICAgICBhOiAxXG4gICAgICAgICAgICBiOiA4XG4gICAgICAgICAgICBjOiBbMSwgMiwgNF1cblxuICAgICAgICB7cmVzdWx0LCBleHBlY3RlZH1cblxuXG4gICAgJ21lcmdlIGxpc3RzMic6IC0+XG4gICAgICAgIGE9XG4gICAgICAgICAgYTogMVxuICAgICAgICAgIGI6IDJcbiAgICAgICAgICBjOiBbJ2hlbGxvJywgJ3dvcmxkJ11cbiAgICAgICAgYj1cbiAgICAgICAgICBiOiA4XG4gICAgICAgICAgYzogWydoaScsICd3b3JsZCddXG5cbiAgICAgICAgcmVzdWx0ID0gYSBgbWVyZ2VgIGJcblxuICAgICAgICBleHBlY3RlZCA9XG4gICAgICAgICAgICBhOiAxXG4gICAgICAgICAgICBiOiA4XG4gICAgICAgICAgICBjOiBbJ2hlbGxvJywgJ3dvcmxkJywgJ2hpJ11cblxuICAgICAgICB7cmVzdWx0LCBleHBlY3RlZH1cblxuICAgICdtZXJnZSBsaXN0cyBvZiBvYmplY3RzJzogLT5cbiAgICAgICAgYT1cbiAgICAgICAgICBhOiAxXG4gICAgICAgICAgYjogMlxuICAgICAgICAgIGM6IFt7YTogMSwgYjogMn0sIHthOiAzLCBiOiA0fV1cbiAgICAgICAgYj1cbiAgICAgICAgICBiOiA4XG4gICAgICAgICAgYzogW3thOiAxLCBiOiAyfSwge2E6IDUsIGI6IDZ9XVxuXG4gICAgICAgIHJlc3VsdCA9IGEgYG1lcmdlYCBiXG5cbiAgICAgICAgZXhwZWN0ZWQgPVxuICAgICAgICAgICAgYTogMVxuICAgICAgICAgICAgYjogOFxuICAgICAgICAgICAgYzogW3thOiAxLCBiOiAyfSwge2E6IDMsIGI6IDR9LCB7YTogNSwgYjogNn1dXG5cbiAgICAgICAge3Jlc3VsdCwgZXhwZWN0ZWR9XG5cbiAgICAnbWVyZ2UgbGlzdHMgb2Ygb2JqZWN0czInOiAtPlxuICAgICAgICB4ID1cbiAgICAgICAgICAgICogYTogMVxuICAgICAgICAgICAgICBiOiAyXG4gICAgICAgICAgICAqIGE6IDNcbiAgICAgICAgICAgICAgYjogNFxuXG4gICAgICAgIHkgPVxuICAgICAgICAgICAgKiBhOiA1XG4gICAgICAgICAgICAgIGI6IDZcbiAgICAgICAgICAgICogYTogN1xuICAgICAgICAgICAgICBiOiA4XG4gICAgICAgICAgICAqIGE6IDlcbiAgICAgICAgICAgICAgYjogMTBcbiAgICAgICAgICAgICogYTogMTFcbiAgICAgICAgICAgICAgYjogMTJcblxuICAgICAgICByZXN1bHQgPSB4IGBtZXJnZWAgeVxuXG4gICAgICAgIGV4cGVjdGVkID1cbiAgICAgICAgICAgICogYTogMVxuICAgICAgICAgICAgICBiOiAyXG4gICAgICAgICAgICAqIGE6IDNcbiAgICAgICAgICAgICAgYjogNFxuICAgICAgICAgICAgKiBhOiA1XG4gICAgICAgICAgICAgIGI6IDZcbiAgICAgICAgICAgICogYTogN1xuICAgICAgICAgICAgICBiOiA4XG4gICAgICAgICAgICAqIGE6IDlcbiAgICAgICAgICAgICAgYjogMTBcbiAgICAgICAgICAgICogYTogMTFcbiAgICAgICAgICAgICAgYjogMTJcblxuICAgICAgICB7cmVzdWx0LCBleHBlY3RlZH1cblxuICAgICdkZWxldGluZyBzb21ldGhpbmcnOiAtPlxuICAgICAgICBhPVxuICAgICAgICAgIGE6IDFcbiAgICAgICAgICBiOiAyXG4gICAgICAgICAgYzpcbiAgICAgICAgICAgIGNhOiAxMVxuICAgICAgICAgICAgY2I6IDJcblxuICAgICAgICByZXN1bHQgPSBtZXJnZSBhLCB7Yzogdm9pZH1cblxuICAgICAgICBleHBlY3RlZCA9XG4gICAgICAgICAgICBhOiAxXG4gICAgICAgICAgICBiOiAyXG5cbiAgICAgICAge3Jlc3VsdCwgZXhwZWN0ZWR9XG4gICAgJ2ZvcmNlIG92ZXJ3cml0ZSc6IC0+XG4gICAgICAgIGE9XG4gICAgICAgICAgYTogMVxuICAgICAgICAgIGI6IDJcbiAgICAgICAgICBjOlxuICAgICAgICAgICAgY2E6IDExXG4gICAgICAgICAgICBjYjogMlxuICAgICAgICBiPVxuICAgICAgICAgIGM6ICAjIGRvIG5vdCBtZXJnZSwgZm9yY2Ugb3ZlcndyaXRlXG4gICAgICAgICAgICBjYjogNVxuXG4gICAgICAgIHJlc3VsdCA9IG1lcmdlLWFsbCBhLCB7Yzogdm9pZH0sIGJcblxuICAgICAgICBleHBlY3RlZCA9XG4gICAgICAgICAgICBhOiAxXG4gICAgICAgICAgICBiOiAyXG4gICAgICAgICAgICBjOlxuICAgICAgICAgICAgICAgIGNiOiA1XG5cbiAgICAgICAge3Jlc3VsdCwgZXhwZWN0ZWR9XG5cbiAgICAnbWVyZ2luZyBvYmplY3Qgd2l0aCBmdW5jdGlvbnMnOiAtPlxuICAgICAgICBhPVxuICAgICAgICAgIGE6IDFcbiAgICAgICAgICBiOiAyXG4gICAgICAgICAgYzpcbiAgICAgICAgICAgIGNhOiAxMVxuICAgICAgICAgICAgY2I6IDJcbiAgICAgICAgYj1cbiAgICAgICAgICBjOlxuICAgICAgICAgICAgY2I6ICh4KSAtPiB4XG5cbiAgICAgICAgcmVzdWx0ID0gbWVyZ2UgYSwgYlxuXG4gICAgICAgIGV4cGVjdGVkID1cbiAgICAgICAgICAgIGE6IDFcbiAgICAgICAgICAgIGI6IDJcbiAgICAgICAgICAgIGM6XG4gICAgICAgICAgICAgICAgY2E6IDExXG4gICAgICAgICAgICAgICAgY2I6ICh4KSAtPiB4XG5cbiAgICAgICAge3Jlc3VsdCwgZXhwZWN0ZWR9XG5cbiAgICAnRmllbGQgb3IgbWV0aG9kIGRvZXMgbm90IGFscmVhZHkgZXhpc3QsIGFuZCBjYW50IGNyZWF0ZSBpdCBvbiBTdHJpbmcnOiAtPlxuICAgICAgICBhPVxuICAgICAgICAgIGE6IDFcbiAgICAgICAgICBiOiAyXG4gICAgICAgICAgYzogXCJoZXlcIlxuICAgICAgICBiPVxuICAgICAgICAgIGM6XG4gICAgICAgICAgICBjYjogXCJhYVwiXG5cbiAgICAgICAgcmVzdWx0ID0gbWVyZ2UgYSwgYlxuXG4gICAgICAgIGV4cGVjdGVkID1cbiAgICAgICAgICAgIGE6IDFcbiAgICAgICAgICAgIGI6IDJcbiAgICAgICAgICAgIGM6XG4gICAgICAgICAgICAgICAgY2I6IFwiYWFcIlxuXG4gICAgICAgIHtyZXN1bHQsIGV4cGVjdGVkfVxuXG5zdGFydCA9IERhdGUubm93IVxudGVzdC1jb3VudCA9IDEgICMgdXNlIDVfMDAwIGZvciBhIHNpZ25pZmljaWFudCBhbW91bnQgb2YgdGltZVxuZm9yIGkgZnJvbSAwIHRvIHRlc3QtY291bnRcbiAgICBmb3IgbmFtZSwgdGVzdCBvZiB0ZXN0c1xuICAgICAgICB7cmVzdWx0LCBleHBlY3RlZH0gPSB0ZXN0IVxuICAgICAgICBpZiBwYWNrKGV4cGVjdGVkKSBpc250IHBhY2socmVzdWx0KVxuICAgICAgICAgICAgY29uc29sZS5sb2cgXCJtZXJnZSB0ZXN0IGZhaWxlZCB0ZXN0OiBcIiwgbmFtZVxuICAgICAgICAgICAgY29uc29sZS5sb2cgXCJFWFBFQ1RFRDogXCIsIGV4cGVjdGVkXG4gICAgICAgICAgICBjb25zb2xlLmxvZyBcIlJFU1VMVCAgOiBcIiwgcmVzdWx0XG4gICAgICAgICAgICB0aHJvdyBcIlRlc3QgZmFpbGVkIGluIG1lcmdlLmxzISwgdGVzdDogI3tuYW1lfVwiXG5cbmlmIHRlc3QtY291bnQgPiAxXG4gICAgY29uc29sZS5sb2cgXCJNZXJnZSB0ZXN0cyB0b29rOiAje0RhdGUubm93ISAtIHN0YXJ0fSBtaWxsaXNlY29uZHMuLi5cIlxuIiwicmVxdWlyZSEgJ3ByZWx1ZGUtbHMnOiB7cmV2ZXJzZX1cblxuZXhwb3J0IGhleCA9IChuKSAtPiBuLnRvLXN0cmluZyAxNiAudG8tdXBwZXItY2FzZSFcblxuZXhwb3J0IGlwLXRvLWhleCA9IChpcCkgLT5cbiAgICBpID0gMFxuICAgIHJlc3VsdCA9IDBcbiAgICBmb3IgcGFydCBpbiByZXZlcnNlIGlwLnNwbGl0ICcuJ1xuICAgICAgICByZXN1bHQgKz0gcGFydCAqICgyNTYqKmkrKylcblxuICAgIGhleCByZXN1bHRcbiIsInJlcXVpcmUhICcuL2xvZ2dlcic6IHtMb2dnZXJ9XG5yZXF1aXJlISAnLi9ldmVudC1lbWl0dGVyJzoge0V2ZW50RW1pdHRlcn1cbnJlcXVpcmUhICcuL3NsZWVwJzoge3NsZWVwfVxucmVxdWlyZSEgJy4vcGFja2luZyc6IHtwYWNrLCB1bnBhY2ssIGNsb25lLCBkaWZmfVxucmVxdWlyZSEgJy4vbWVyZ2UnOiB7bWVyZ2UsIGJhc2VkLW9ufVxucmVxdWlyZSEgJy4vaXAtdG8taGV4Jzoge2lwLXRvLWhleCwgaGV4fVxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBMb2dnZXJcbiAgICBFdmVudEVtaXR0ZXJcbiAgICBzbGVlcFxuICAgIHBhY2ssIHVucGFjaywgY2xvbmUsIGRpZmZcbiAgICBtZXJnZSwgYmFzZWQtb25cbiAgICBpcC10by1oZXgsIGhleFxufVxuIiwiZXhwb3J0IGJyaWVmID0gKG1zZykgLT5cbiAgICBzID0ge31cbiAgICBmb3IgaywgdiBvZiBtc2dcbiAgICAgICAgY29udGludWUgaWYgayBpcyBcXGRhdGFcbiAgICAgICAgc1trXSA9IHZcbiAgICBpZiBtc2cuZGF0YVxuICAgICAgICBkYXRhLXN0ciA9IEpTT04uc3RyaW5naWZ5IG1zZy5kYXRhXG4gICAgICAgIHMuZGF0YSA9IGlmIGRhdGEtc3RyLmxlbmd0aCA+IDcwXG4gICAgICAgICAgICBcIi4uLiN7ZGF0YS1zdHIubGVuZ3RofS4uLlwiXG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIG1zZy5kYXRhXG4gICAgaWYgbXNnLnBlcm1pc3Npb25zXG4gICAgICAgIHMucGVybWlzc2lvbnMgPSBcIi4uLiN7bXNnLnBlcm1pc3Npb25zLmxlbmd0aH0uLi5cIlxuICAgIHJldHVybiBzXG4iLCJyZXF1aXJlISAncHJlbHVkZS1scyc6IHttYXgsIHNwbGl0fVxuXG5zcGxpdC1kb3QgPSBzcGxpdCAnLidcblxuZXhwb3J0IHRvcGljLW1hdGNoID0gKHRvcGljcywga2V5cGF0aHMsIG9wdHM9e30pIC0+XG4gICAgIyByZXR1cm5zIHRydWUgaWYga2V5cGF0aCBmaXRzIGludG8gdG9waWNcbiAgICAjIGVsc2UsIHJldHVybiBmYWxzZVxuICAgIHVubGVzcyB0b3BpY3M/IGFuZCBrZXlwYXRocz9cbiAgICAgICAgIyBib3RoIHNob3VsZCBiZSBkaWZmZXJlbnQgZnJvbSB1bmRlZmluZWRcbiAgICAgICAgcmV0dXJuIG5vXG5cbiAgICBhcy1hcnJheSA9ICh4KSAtPlxuICAgICAgICBpZiB0eXBlb2YhIHggaXMgXFxTdHJpbmcgdGhlbiB4LnRyaW0hLnNwbGl0ICcgJyBlbHNlIHhcblxuICAgIGZvciB0b3BpYyBpbiB0b3BpY3MgfD4gYXMtYXJyYXlcbiAgICAgICAgZm9yIGtleXBhdGggaW4ga2V5cGF0aHMgfD4gYXMtYXJyYXlcbiAgICAgICAgICAgIHRyeVxuICAgICAgICAgICAgICAgIGlmICcqKicgaW4gW3RvcGljLCBrZXlwYXRoXVxuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyBcInRvcGljIGlzICoqLCBpbW1lZGlhdGVseSBtYXRjaGVzIHdpdGggYW55dGhpbmdcIiBpZiBvcHRzLmRlYnVnXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB5ZXNcbiAgICAgICAgICAgICAgICB0cnlcbiAgICAgICAgICAgICAgICAgICAgdG9waWMtYXJyID0gc3BsaXQtZG90IHRvcGljXG4gICAgICAgICAgICAgICAgICAgIGtleXBhdGgtYXJyID0gc3BsaXQtZG90IGtleXBhdGhcbiAgICAgICAgICAgICAgICBjYXRjaFxuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yIFwiYm90aCB0b3BpYyBhbmQga2V5cGF0aCBzaG91bGQgYmUgc3RyaW5nLlwiXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBub1xuXG4gICAgICAgICAgICAgICAgZm9yIGluZGV4IGluIFt0aWwgbWF4KHRvcGljLWFyci5sZW5ndGgsIGtleXBhdGgtYXJyLmxlbmd0aCldXG4gICAgICAgICAgICAgICAgICAgIHRvcGljLXBhcnQgPSB0cnkgdG9waWMtYXJyW2luZGV4XVxuICAgICAgICAgICAgICAgICAgICBrZXlwYXRoLXBhcnQgPSB0cnkga2V5cGF0aC1hcnJbaW5kZXhdXG5cbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2cgXCJ0b3BpYy1wYXJ0OiAje3RvcGljLXBhcnR9LCBrZXlwYXRoLXBhcnQ6ICN7a2V5cGF0aC1wYXJ0fVwiIGlmIG9wdHMuZGVidWdcblxuICAgICAgICAgICAgICAgICAgICBpZiAnKicgaW4gW2tleXBhdGgtcGFydCwgdG9waWMtcGFydF1cbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIHVuZGVmaW5lZCBpbiBba2V5cGF0aC1wYXJ0LCB0b3BpYy1wYXJ0XVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nIFwicmV0dXJuaW5nIGZhbHNlIGJlY2F1c2UgdGhlcmUgaXMgbm8gY29tbWFuZCB0byBsb29rIGZvciBtYXRjaFwiIGlmIG9wdHMuZGVidWdcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aHJvd1xuICAgICAgICAgICAgICAgICAgICAgICAgY29udGludWVcblxuICAgICAgICAgICAgICAgICAgICB1bmxlc3MgJyoqJyBpbiBba2V5cGF0aC1wYXJ0LCB0b3BpYy1wYXJ0XVxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgdW5kZWZpbmVkIGluIFtrZXlwYXRoLXBhcnQsIHRvcGljLXBhcnRdXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2cgXCJyZXR1cm5pbmcgZmFsc2UgYmVjYXVzZSB0aGVyZSBpcyBubyBjb21tYW5kIHRvIGxvb2sgZm9yIG1hdGNoXCIgaWYgb3B0cy5kZWJ1Z1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRocm93XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgJyoqJyBpbiBba2V5cGF0aC1wYXJ0LCB0b3BpYy1wYXJ0XVxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2cgXCJyZXR1cm5pbmcgdHJ1ZSBiZWNhdXNlICcqKicgd2lsbCBtYXRjaCB3aXRoIGFueXRoaW5nLlwiIGlmIG9wdHMuZGVidWdcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlXG5cbiAgICAgICAgICAgICAgICAgICAgaWYgdG9waWMtcGFydCBpc250IGtleXBhdGgtcGFydFxuICAgICAgICAgICAgICAgICAgICAgICAgI2NvbnNvbGUubG9nIFwidG9waWMtcGFydDogI3t0b3BpYy1wYXJ0fSwga2V5cGF0aC1wYXJ0OiAje2tleXBhdGgtcGFydH1cIlxuICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3cgXCJub3QgbWF0Y2hpbmdcIlxuXG5cbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyBcIm5vIGNvbmRpdGlvbiBicm9rZSB0aGUgbWF0Y2guXCIgaWYgb3B0cy5kZWJ1Z1xuICAgICAgICAgICAgICAgIHJldHVybiB0cnVlXG4gICAgcmV0dXJuIGZhbHNlXG5cblxuZG8gdGVzdC10b3BpYy1tYXRjaCA9IC0+XG5cbiAgICAjIGZvcm1hdDpcbiAgICAjIG1lc3NhZ2UuY29tbWFuZC5jb21tYW5kLmNvbW1hbmQuLi4uXG4gICAgLypcblxuICAgICoqIHdpbGwgbWF0Y2ggd2l0aCBhbnl0aGluZywgaW5jbHVkaW5nIG51bGxcblxuICAgICovXG5cbiAgICBleGFtcGxlcyA9XG4gICAgICAgICMgc2ltcGxlIG1hdGNoZXNcbiAgICAgICAgKiB0b3BpYzogXCJmb28uYmFyXCIsIGtleXBhdGg6IFwiZm9vLipcIiwgZXhwZWN0ZWQ6IHRydWVcbiAgICAgICAgKiB0b3BpYzogXCIqLmJhclwiLCBrZXlwYXRoOiBcImZvby4qXCIsIGV4cGVjdGVkOiB0cnVlXG4gICAgICAgICogdG9waWM6IFwiZm9vLmJhclwiLCBrZXlwYXRoOiBcImJhei5iYXJcIiwgZXhwZWN0ZWQ6IGZhbHNlXG5cbiAgICAgICAgIyBtdWx0aSBtYXRjaFxuICAgICAgICAqIHRvcGljOiBcImZvby5iYXJcIiwga2V5cGF0aDogXCJiYXouYmFyIGZvby4qXCIsIGV4cGVjdGVkOiB0cnVlXG5cbiAgICAgICAgIyBhbnkgZm9vIG1lc3NhZ2VzIHRoYXQgY29udGFpbnMgZXhhY3RseSB0d28gbGV2ZWwgZGVlcCBjb21tYW5kc1xuICAgICAgICAqIHRvcGljOiBcImZvby5iYXJcIiwga2V5cGF0aDogXCJmb28uKi4qXCIsIGV4cGVjdGVkOiBmYWxzZVxuXG4gICAgICAgICMgcHVibGlzaCBleGFjdGx5IDMgbGV2ZWwgZGVlcCB0b3BpY3MsIHN1YnNjcmliZSB0byBmb28gbWVzc2FnZXNcbiAgICAgICAgIyB0aGF0IGFyZSBvbmx5IG9uZSBsZXZlbCBkZWVwLlxuICAgICAgICAqIHRvcGljOiBcImZvby4qLmJhclwiLCBrZXlwYXRoOiBcImZvby4qXCIsIGV4cGVjdGVkOiBmYWxzZVxuXG4gICAgICAgICogdG9waWM6IFwiZm9vLioqXCIsIGtleXBhdGg6IFwiZm9vXCIsIGV4cGVjdGVkOiB0cnVlXG4gICAgICAgICogdG9waWM6IFwiQGZvb1wiLCBrZXlwYXRoOiA8WyBAZm9vLioqIEBiYXIuKiogXT4sIGV4cGVjdGVkOiB0cnVlXG4gICAgICAgICogdG9waWM6IDxbIEBiYXIuKiogQGZvby1iYXIuKiogXT4sIGtleXBhdGg6IFwiQGZvby1iYXJcIiBleHBlY3RlZDogdHJ1ZVxuXG4gICAgICAgICMgZmlyc3Q6IGFueSBmb28gbWVzc2FnZXMgdGhhdCBjb250YWlucyB0d28gb3IgbW9yZSBjb21tYW5kc1xuICAgICAgICAqIHRvcGljOiBcImZvby4qLioqXCIsIGtleXBhdGg6IFwiZm9vLmJhci5iYXpcIiwgZXhwZWN0ZWQ6IHRydWVcbiAgICAgICAgKiB0b3BpYzogXCJmb28uKi4qKlwiLCBrZXlwYXRoOiBcImZvby5iYXJcIiwgZXhwZWN0ZWQ6IHRydWVcbiAgICAgICAgKiB0b3BpYzogXCJmb28uKi4qKlwiLCBrZXlwYXRoOiBcImZvby5iYXIuYmF6LnF1eFwiLCBleHBlY3RlZDogdHJ1ZVxuXG4gICAgICAgICogdG9waWM6IFwiZm9vLioqXCIsIGtleXBhdGg6IFwiZm9vLmJhci5iYXoucXV4XCIsIGV4cGVjdGVkOiB0cnVlXG4gICAgICAgICogdG9waWM6IFwiZm9vLioqXCIsIGtleXBhdGg6IFwiKi5iYXIuYmF6LnF1eFwiLCBleHBlY3RlZDogdHJ1ZVxuXG4gICAgICAgICogdG9waWM6IFwiZm9vLmJhclwiLCBrZXlwYXRoOiBcIiouKlwiLCBleHBlY3RlZDogdHJ1ZVxuICAgICAgICAqIHRvcGljOiBcImZvby5iYXJcIiwga2V5cGF0aDogXCIqXCIsIGV4cGVjdGVkOiBmYWxzZVxuICAgICAgICAqIHRvcGljOiBcIipcIiwga2V5cGF0aDogXCJmb28uYmFyXCIsIGV4cGVjdGVkOiBmYWxzZVxuICAgICAgICAqIHRvcGljOiBcImZvby5iYXJcIiwga2V5cGF0aDogXCIqKlwiLCBleHBlY3RlZDogdHJ1ZVxuXG4gICAgICAgICogdG9waWM6IFwiKlwiLCBrZXlwYXRoOiBcIipcIiwgZXhwZWN0ZWQ6IHRydWVcbiAgICAgICAgKiB0b3BpYzogXCIqKlwiLCBrZXlwYXRoOiBcIipcIiwgZXhwZWN0ZWQ6IHRydWVcbiAgICAgICAgKiB0b3BpYzogXCIqXCIsIGtleXBhdGg6IFwiKipcIiwgZXhwZWN0ZWQ6IHRydWVcbiAgICAgICAgKiB0b3BpYzogXCIqKlwiLCBrZXlwYXRoOiBcIioqXCIsIGV4cGVjdGVkOiB0cnVlXG4gICAgICAgICogdG9waWM6IFwiKi4qXCIsIGtleXBhdGg6IFwiKipcIiwgZXhwZWN0ZWQ6IHRydWVcbiAgICAgICAgKiB0b3BpYzogXCIqKlwiLCBrZXlwYXRoOiBcIiouKlwiLCBleHBlY3RlZDogdHJ1ZVxuXG4gICAgZm9yIG51bSBvZiBleGFtcGxlc1xuICAgICAgICBleGFtcGxlID0gZXhhbXBsZXNbbnVtXVxuICAgICAgICByZXN1bHQgPSBleGFtcGxlLnRvcGljIGB0b3BpYy1tYXRjaGAgZXhhbXBsZS5rZXlwYXRoXG4gICAgICAgIGlmIHJlc3VsdCBpc250IGV4YW1wbGUuZXhwZWN0ZWRcbiAgICAgICAgICAgIGNvbnNvbGUubG9nIFwiVGVzdCBmYWlsZWQgaW4gXFwjI3tudW19LCByZS1ydW5uaW5nIGluIGRlYnVnIG1vZGU6IFwiXG4gICAgICAgICAgICBjb25zb2xlLmxvZyBcImNvbXBhcmluZyBpZiAnI3tleGFtcGxlLnRvcGljfScgbWF0Y2hlcyB3aXRoICcje2V4YW1wbGUua2V5cGF0aH0nIGV4cGVjdGluZzogI3tleGFtcGxlLmV4cGVjdGVkfVwiXG4gICAgICAgICAgICBjb25zb2xlLmxvZyBcIi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVwiXG4gICAgICAgICAgICB0b3BpYy1tYXRjaCBleGFtcGxlLnRvcGljLCBleGFtcGxlLmtleXBhdGgsIHsrZGVidWd9XG4gICAgICAgICAgICBjb25zb2xlLmxvZyBcIi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVwiXG4gICAgICAgICAgICBwcm9jZXNzLmV4aXQgMVxuIiwicmVxdWlyZSEgJ3ByZWx1ZGUtbHMnOiB7cmVqZWN0LCBmaW5kfVxucmVxdWlyZSEgJy4uL3RvcGljLW1hdGNoJzoge3RvcGljLW1hdGNoOiByb3V0ZS1tYXRjaH1cbnJlcXVpcmUhICcuLi8uLi9saWInOiB7TG9nZ2VyLCBzbGVlcCwgaGV4fVxucmVxdWlyZSEgJy4uLy4uL2xpYi9kZWJ1Zy10b29scyc6IHticmllZn1cblxuXG5leHBvcnQgY2xhc3MgQWN0b3JNYW5hZ2VyXG4gICAgQGluc3RhbmNlID0gbnVsbFxuICAgIC0+XG4gICAgICAgICMgTWFrZSB0aGlzIGNsYXNzIFNpbmdsZXRvblxuICAgICAgICByZXR1cm4gQEBpbnN0YW5jZSBpZiBAQGluc3RhbmNlXG4gICAgICAgIEBAaW5zdGFuY2UgPSB0aGlzXG4gICAgICAgIEBhY3Rvci11aWQgPSAxICMgZmlyc3QgYWN0b3IgaWRcbiAgICAgICAgQGFjdG9ycyA9IFtdXG4gICAgICAgIEBtYW5hZ2VyLWlkID0gRGF0ZS5ub3chIHw+IGhleFxuICAgICAgICBAbG9nID0gbmV3IExvZ2dlciBcIkFjdG9yTWFuLiN7QG1hbmFnZXItaWR9XCJcblxuICAgIG5leHQtYWN0b3ItaWQ6IC0+XG4gICAgICAgIFwiYSN7QGFjdG9yLXVpZCsrfS0je0BtYW5hZ2VyLWlkfVwiXG5cbiAgICByZWdpc3Rlci1hY3RvcjogKGFjdG9yKSAtPlxuICAgICAgICB1bmxlc3MgZmluZCAoLmlkIGlzIGFjdG9yLmlkKSwgQGFjdG9yc1xuICAgICAgICAgICAgQGFjdG9ycy5wdXNoIGFjdG9yXG5cbiAgICBmaW5kLWFjdG9yOiAoaWQpIC0+XG4gICAgICAgIHRocm93ICdpZCBpcyByZXF1aXJlZCEnIHVubGVzcyBpZFxuICAgICAgICByZXR1cm4gZmluZCAoLmlkIGlzIGlkKSwgQGFjdG9yc1xuXG4gICAgZGVyZWdpc3Rlci1hY3RvcjogKGFjdG9yKSAtPlxuICAgICAgICBAYWN0b3JzID0gcmVqZWN0ICguaWQgaXMgYWN0b3IuaWQpLCBAYWN0b3JzXG5cbiAgICBkaXN0cmlidXRlOiAobXNnLCBzZW5kZXIpIC0+XG4gICAgICAgIGlmIG1zZy5kZWJ1ZyA9PiBAbG9nLmRlYnVnIFwiRGlzdHJpYnV0aW5nIG1lc3NhZ2U6IFwiLCBicmllZiBtc2dcbiAgICAgICAgZHVlLWRhdGUgPSBEYXRlLm5vdyFcbiAgICAgICAgZm9yIGFjdG9yIGluIEBhY3RvcnMgd2hlbiBhY3Rvci5pZCBpc250IHNlbmRlclxuICAgICAgICAgICAgI0Bsb2cubG9nIFwibG9va2luZyBmb3IgI3ttc2cudG99IHRvIGJlIG1hdGNoZWQgaW4gI3thY3Rvci5zdWJzY3JpcHRpb25zfVwiXG4gICAgICAgICAgICBpZiBtc2cudG8gYHJvdXRlLW1hdGNoYCBhY3Rvci5zdWJzY3JpcHRpb25zXG4gICAgICAgICAgICAgICAgaWYgbXNnLl9leGNsdWRlXG4gICAgICAgICAgICAgICAgICAgIGlmIHRoYXQgaXMgYWN0b3IuaWQgPT4gY29udGludWVcbiAgICAgICAgICAgICAgICAgICAgZGVsZXRlIG1zZy5fZXhjbHVkZVxuICAgICAgICAgICAgICAgICNAbG9nLmxvZyBcInB1dHRpbmcgbWVzc2FnZTogI3ttc2cuZnJvbX0uI3ttc2cuc2VxfSAtPiBhY3RvcjogI3thY3Rvci5pZH1cIiwgYWN0b3Iuc3Vic2NyaXB0aW9ucy5qb2luKCcsJylcbiAgICAgICAgICAgICAgICBkZWxheSA9IERhdGUubm93ISAtIGR1ZS1kYXRlXG4gICAgICAgICAgICAgICAgaWYgZGVsYXkgPiAxMG1zXG4gICAgICAgICAgICAgICAgICAgIEBsb2cud2FybiBcIlN5c3RlbSBsb2FkIGlzIGhpZ2g/IE1lc3NhZ2UgaXMgZGVsaXZlcmVkIGFmdGVyICN7ZGVsYXl9bXNcIlxuICAgICAgICAgICAgICAgIGFjdG9yLl9pbmJveCBtc2dcbiAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAjQGxvZy53YXJuIFwiZHJvcHBpbmcgYXMgcm91dGVzIGFyZSBub3QgbWF0Y2hlZDogI3ttc2cudG99IHZzLiAje3JvdXRlfVwiXG4gICAgICAgICAgICAgICAgbnVsbFxuXG4gICAga2lsbDogKC4uLmFyZ3MpIC0+XG4gICAgICAgIGZvciBhY3RvciBpbiBAYWN0b3JzXG4gICAgICAgICAgICBhY3Rvci50cmlnZ2VyIFxca2lsbCwgLi4uYXJnc1xuIiwidHJ5IFxuICAgIHJlcXVpcmUhICcuLi8uLi9saWInOiB7c2xlZXAsIExvZ2dlcn1cbmNhdGNoIFxuICAgIHNsZWVwID0gKG1zLCBmKSAtPiBzZXQtdGltZW91dCBmLCBtc1xuICAgIGdldC1mb3JtYXR0ZWQtZGF0ZSA9IC0+IFxuICAgICAgICBkID0gbmV3IERhdGUgXG4gICAgICAgIFwiI3tkLmdldEZ1bGxZZWFyIX0tI3tkLmdldE1vbnRoISArIDF9LSN7ZC5nZXREYXRlIX0gI3tkLmdldEhvdXJzIX06I3tkLmdldE1pbnV0ZXMhfToje2QuZ2V0U2Vjb25kcyF9LiN7ZC5nZXRNaWxsaXNlY29uZHMhfVwiXG5cbiAgICBjbGFzcyBMb2dnZXJcbiAgICAgICAgKEBuYW1lKSAtPiBcblxuICAgICAgICBsb2c6IC0+XG4gICAgICAgICAgICBjb25zb2xlLmxvZyAuLi5bJ1snLCBnZXRGb3JtYXR0ZWREYXRlKCksICddJywgXCIje0BuYW1lfTpcIiwgLi4uYXJndW1lbnRzXVxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBzbGVlcCwgTG9nZ2VyXG59XG4iLCJyZXF1aXJlISAnLi4vZGVwcyc6IHtzbGVlcCwgTG9nZ2VyfVxucmVxdWlyZSEgJ3ByZWx1ZGUtbHMnOiB7aXMtaXQtTmFOfVxuXG5leHBvcnQgY2xhc3MgU2lnbmFsXG4gICAgKG9wdHM9e30pIC0+XG4gICAgICAgIGlmIG9wdHMuZGVidWdcbiAgICAgICAgICAgIEBkZWJ1ZyA9IHllc1xuICAgICAgICBAbmFtZSA9IG9wdHMubmFtZSBvciBcXFNpZ25hbFxuICAgICAgICBAbG9nID0gbmV3IExvZ2dlciBAbmFtZVxuICAgICAgICBAcmVzcG9uc2UgPSBbXVxuICAgICAgICBAY2FsbGJhY2sgPSB7Y3R4OiBudWxsLCBoYW5kbGVyOiBudWxsfVxuICAgICAgICBpZiBAZGVidWcgPT4gQGxvZy5kZWJ1ZyBcIkluaXRpYWxpemVkIG5ldyBzaWduYWwuXCJcbiAgICAgICAgQHJldXNhYmxlID0gb3B0cy5yZXVzYWJsZSAjIHJldXNlIHRoZSBgd2FpdCBoYW5kbGVyYCBiZXR3ZWVuIGBmaXJlYHMgXG4gICAgICAgIEByZXNldCFcblxuICAgIGNhbmNlbDogLT5cbiAgICAgICAgQHJlc2V0IVxuXG4gICAgcmVzZXQ6IC0+XG4gICAgICAgICMgY2xlYXIgZXZlcnl0aGluZyBsaWtlIHRoZSBvYmplY3QgaXNcbiAgICAgICAgIyBpbml0aWFsaXplZCBmb3IgdGhlIGZpcnN0IHRpbWVcbiAgICAgICAgI0Bsb2cuZGVidWcgXCJSZXNldHRpbmcgc2lnbmFsLlwiXG4gICAgICAgIHVubGVzcyBAcmV1c2FibGVcbiAgICAgICAgICAgIGRlbGV0ZSBAY2FsbGJhY2suaGFuZGxlclxuICA |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment