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