Skip to content

Instantly share code, notes, and snippets.

@mikolalysenko
Created July 6, 2013 19:50
Show Gist options
  • Save mikolalysenko/5941042 to your computer and use it in GitHub Desktop.
Save mikolalysenko/5941042 to your computer and use it in GitHub Desktop.
made with requirebin.com
<style type='text/css'> html, body { margin: 0; padding: 0; border: 0; } </style>
var shell = require("game-shell")()
var context
, player_x = 250
, player_y = 250
//Bind keyboard commands
shell.bind("move-left", "left", "A")
shell.bind("move-right", "right", "D")
shell.bind("move-up", "up", "W")
shell.bind("move-down", "down", "S")
//Fired when document is loaded
shell.on("init", function() {
var canvas = document.createElement("canvas")
canvas.width = 500
canvas.height = 500
shell.element.appendChild(canvas)
context = canvas.getContext("2d")
})
//Fired once per game tick
shell.on("tick", function() {
if(shell.wasDown("move-left")) {
player_x -= 1
}
if(shell.wasDown("move-right")) {
player_x += 1
}
if(shell.wasDown("move-up")) {
player_y -= 1
}
if(shell.wasDown("move-down")) {
player_y += 1
}
})
//Render a frame
shell.on("render", function(frame_time) {
context.fillStyle = "#000"
context.fillRect(0, 0, 500, 500)
context.fillStyle = "#f00"
context.fillRect(player_x-10, player_y-10, 20, 20)
})
require=(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){
// shim for using process in browser
var process = module.exports = {};
process.nextTick = (function () {
var canSetImmediate = typeof window !== 'undefined'
&& window.setImmediate;
var canPost = typeof window !== 'undefined'
&& window.postMessage && window.addEventListener
;
if (canSetImmediate) {
return function (f) { return window.setImmediate(f) };
}
if (canPost) {
var queue = [];
window.addEventListener('message', function (ev) {
if (ev.source === window && ev.data === 'process-tick') {
ev.stopPropagation();
if (queue.length > 0) {
var fn = queue.shift();
fn();
}
}
}, true);
return function nextTick(fn) {
queue.push(fn);
window.postMessage('process-tick', '*');
};
}
return function nextTick(fn) {
setTimeout(fn, 0);
};
})();
process.title = 'browser';
process.browser = true;
process.env = {};
process.argv = [];
process.binding = function (name) {
throw new Error('process.binding is not supported');
}
// TODO(shtylman)
process.cwd = function () { return '/' };
process.chdir = function (dir) {
throw new Error('process.chdir is not supported');
};
},{}],2:[function(require,module,exports){
(function(process){if (!process.EventEmitter) process.EventEmitter = function () {};
var EventEmitter = exports.EventEmitter = process.EventEmitter;
var isArray = typeof Array.isArray === 'function'
? Array.isArray
: function (xs) {
return Object.prototype.toString.call(xs) === '[object Array]'
}
;
function indexOf (xs, x) {
if (xs.indexOf) return xs.indexOf(x);
for (var i = 0; i < xs.length; i++) {
if (x === xs[i]) return i;
}
return -1;
}
// By default EventEmitters will print a warning if more than
// 10 listeners are added to it. This is a useful default which
// helps finding memory leaks.
//
// Obviously not all Emitters should be limited to 10. This function allows
// that to be increased. Set to zero for unlimited.
var defaultMaxListeners = 10;
EventEmitter.prototype.setMaxListeners = function(n) {
if (!this._events) this._events = {};
this._events.maxListeners = n;
};
EventEmitter.prototype.emit = function(type) {
// If there is no 'error' event listener then throw.
if (type === 'error') {
if (!this._events || !this._events.error ||
(isArray(this._events.error) && !this._events.error.length))
{
if (arguments[1] instanceof Error) {
throw arguments[1]; // Unhandled 'error' event
} else {
throw new Error("Uncaught, unspecified 'error' event.");
}
return false;
}
}
if (!this._events) return false;
var handler = this._events[type];
if (!handler) return false;
if (typeof handler == 'function') {
switch (arguments.length) {
// fast cases
case 1:
handler.call(this);
break;
case 2:
handler.call(this, arguments[1]);
break;
case 3:
handler.call(this, arguments[1], arguments[2]);
break;
// slower
default:
var args = Array.prototype.slice.call(arguments, 1);
handler.apply(this, args);
}
return true;
} else if (isArray(handler)) {
var args = Array.prototype.slice.call(arguments, 1);
var listeners = handler.slice();
for (var i = 0, l = listeners.length; i < l; i++) {
listeners[i].apply(this, args);
}
return true;
} else {
return false;
}
};
// EventEmitter is defined in src/node_events.cc
// EventEmitter.prototype.emit() is also defined there.
EventEmitter.prototype.addListener = function(type, listener) {
if ('function' !== typeof listener) {
throw new Error('addListener only takes instances of Function');
}
if (!this._events) this._events = {};
// To avoid recursion in the case that type == "newListeners"! Before
// adding it to the listeners, first emit "newListeners".
this.emit('newListener', type, listener);
if (!this._events[type]) {
// Optimize the case of one listener. Don't need the extra array object.
this._events[type] = listener;
} else if (isArray(this._events[type])) {
// Check for listener leak
if (!this._events[type].warned) {
var m;
if (this._events.maxListeners !== undefined) {
m = this._events.maxListeners;
} else {
m = defaultMaxListeners;
}
if (m && m > 0 && this._events[type].length > m) {
this._events[type].warned = true;
console.error('(node) warning: possible EventEmitter memory ' +
'leak detected. %d listeners added. ' +
'Use emitter.setMaxListeners() to increase limit.',
this._events[type].length);
console.trace();
}
}
// If we've already got an array, just append.
this._events[type].push(listener);
} else {
// Adding the second element, need to change to array.
this._events[type] = [this._events[type], listener];
}
return this;
};
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
EventEmitter.prototype.once = function(type, listener) {
var self = this;
self.on(type, function g() {
self.removeListener(type, g);
listener.apply(this, arguments);
});
return this;
};
EventEmitter.prototype.removeListener = function(type, listener) {
if ('function' !== typeof listener) {
throw new Error('removeListener only takes instances of Function');
}
// does not use listeners(), so no side effect of creating _events[type]
if (!this._events || !this._events[type]) return this;
var list = this._events[type];
if (isArray(list)) {
var i = indexOf(list, listener);
if (i < 0) return this;
list.splice(i, 1);
if (list.length == 0)
delete this._events[type];
} else if (this._events[type] === listener) {
delete this._events[type];
}
return this;
};
EventEmitter.prototype.removeAllListeners = function(type) {
if (arguments.length === 0) {
this._events = {};
return this;
}
// does not use listeners(), so no side effect of creating _events[type]
if (type && this._events && this._events[type]) this._events[type] = null;
return this;
};
EventEmitter.prototype.listeners = function(type) {
if (!this._events) this._events = {};
if (!this._events[type]) this._events[type] = [];
if (!isArray(this._events[type])) {
this._events[type] = [this._events[type]];
}
return this._events[type];
};
})(require("__browserify_process"))
},{"__browserify_process":1}],3:[function(require,module,exports){
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
// requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
// MIT license
var lastTime = 0;
var vendors = ['ms', 'moz', 'webkit', 'o'];
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']
|| window[vendors[x]+'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame)
window.requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() { callback(currTime + timeToCall); },
timeToCall);
lastTime = currTime + timeToCall;
return id;
};
if (!window.cancelAnimationFrame)
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
},{}],4:[function(require,module,exports){
var events = require('events');
exports.isArray = isArray;
exports.isDate = function(obj){return Object.prototype.toString.call(obj) === '[object Date]'};
exports.isRegExp = function(obj){return Object.prototype.toString.call(obj) === '[object RegExp]'};
exports.print = function () {};
exports.puts = function () {};
exports.debug = function() {};
exports.inspect = function(obj, showHidden, depth, colors) {
var seen = [];
var stylize = function(str, styleType) {
// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
var styles =
{ 'bold' : [1, 22],
'italic' : [3, 23],
'underline' : [4, 24],
'inverse' : [7, 27],
'white' : [37, 39],
'grey' : [90, 39],
'black' : [30, 39],
'blue' : [34, 39],
'cyan' : [36, 39],
'green' : [32, 39],
'magenta' : [35, 39],
'red' : [31, 39],
'yellow' : [33, 39] };
var style =
{ 'special': 'cyan',
'number': 'blue',
'boolean': 'yellow',
'undefined': 'grey',
'null': 'bold',
'string': 'green',
'date': 'magenta',
// "name": intentionally not styling
'regexp': 'red' }[styleType];
if (style) {
return '\033[' + styles[style][0] + 'm' + str +
'\033[' + styles[style][1] + 'm';
} else {
return str;
}
};
if (! colors) {
stylize = function(str, styleType) { return str; };
}
function format(value, recurseTimes) {
// Provide a hook for user-specified inspect functions.
// Check that value is an object with an inspect function on it
if (value && typeof value.inspect === 'function' &&
// Filter out the util module, it's inspect function is special
value !== exports &&
// Also filter out any prototype objects using the circular check.
!(value.constructor && value.constructor.prototype === value)) {
return value.inspect(recurseTimes);
}
// Primitive types cannot have properties
switch (typeof value) {
case 'undefined':
return stylize('undefined', 'undefined');
case 'string':
var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
.replace(/'/g, "\\'")
.replace(/\\"/g, '"') + '\'';
return stylize(simple, 'string');
case 'number':
return stylize('' + value, 'number');
case 'boolean':
return stylize('' + value, 'boolean');
}
// For some reason typeof null is "object", so special case here.
if (value === null) {
return stylize('null', 'null');
}
// Look up the keys of the object.
var visible_keys = Object_keys(value);
var keys = showHidden ? Object_getOwnPropertyNames(value) : visible_keys;
// Functions without properties can be shortcutted.
if (typeof value === 'function' && keys.length === 0) {
if (isRegExp(value)) {
return stylize('' + value, 'regexp');
} else {
var name = value.name ? ': ' + value.name : '';
return stylize('[Function' + name + ']', 'special');
}
}
// Dates without properties can be shortcutted
if (isDate(value) && keys.length === 0) {
return stylize(value.toUTCString(), 'date');
}
var base, type, braces;
// Determine the object type
if (isArray(value)) {
type = 'Array';
braces = ['[', ']'];
} else {
type = 'Object';
braces = ['{', '}'];
}
// Make functions say that they are functions
if (typeof value === 'function') {
var n = value.name ? ': ' + value.name : '';
base = (isRegExp(value)) ? ' ' + value : ' [Function' + n + ']';
} else {
base = '';
}
// Make dates with properties first say the date
if (isDate(value)) {
base = ' ' + value.toUTCString();
}
if (keys.length === 0) {
return braces[0] + base + braces[1];
}
if (recurseTimes < 0) {
if (isRegExp(value)) {
return stylize('' + value, 'regexp');
} else {
return stylize('[Object]', 'special');
}
}
seen.push(value);
var output = keys.map(function(key) {
var name, str;
if (value.__lookupGetter__) {
if (value.__lookupGetter__(key)) {
if (value.__lookupSetter__(key)) {
str = stylize('[Getter/Setter]', 'special');
} else {
str = stylize('[Getter]', 'special');
}
} else {
if (value.__lookupSetter__(key)) {
str = stylize('[Setter]', 'special');
}
}
}
if (visible_keys.indexOf(key) < 0) {
name = '[' + key + ']';
}
if (!str) {
if (seen.indexOf(value[key]) < 0) {
if (recurseTimes === null) {
str = format(value[key]);
} else {
str = format(value[key], recurseTimes - 1);
}
if (str.indexOf('\n') > -1) {
if (isArray(value)) {
str = str.split('\n').map(function(line) {
return ' ' + line;
}).join('\n').substr(2);
} else {
str = '\n' + str.split('\n').map(function(line) {
return ' ' + line;
}).join('\n');
}
}
} else {
str = stylize('[Circular]', 'special');
}
}
if (typeof name === 'undefined') {
if (type === 'Array' && key.match(/^\d+$/)) {
return str;
}
name = JSON.stringify('' + key);
if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
name = name.substr(1, name.length - 2);
name = stylize(name, 'name');
} else {
name = name.replace(/'/g, "\\'")
.replace(/\\"/g, '"')
.replace(/(^"|"$)/g, "'");
name = stylize(name, 'string');
}
}
return name + ': ' + str;
});
seen.pop();
var numLinesEst = 0;
var length = output.reduce(function(prev, cur) {
numLinesEst++;
if (cur.indexOf('\n') >= 0) numLinesEst++;
return prev + cur.length + 1;
}, 0);
if (length > 50) {
output = braces[0] +
(base === '' ? '' : base + '\n ') +
' ' +
output.join(',\n ') +
' ' +
braces[1];
} else {
output = braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
}
return output;
}
return format(obj, (typeof depth === 'undefined' ? 2 : depth));
};
function isArray(ar) {
return ar instanceof Array ||
Array.isArray(ar) ||
(ar && ar !== Object.prototype && isArray(ar.__proto__));
}
function isRegExp(re) {
return re instanceof RegExp ||
(typeof re === 'object' && Object.prototype.toString.call(re) === '[object RegExp]');
}
function isDate(d) {
if (d instanceof Date) return true;
if (typeof d !== 'object') return false;
var properties = Date.prototype && Object_getOwnPropertyNames(Date.prototype);
var proto = d.__proto__ && Object_getOwnPropertyNames(d.__proto__);
return JSON.stringify(proto) === JSON.stringify(properties);
}
function pad(n) {
return n < 10 ? '0' + n.toString(10) : n.toString(10);
}
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
'Oct', 'Nov', 'Dec'];
// 26 Feb 16:19:34
function timestamp() {
var d = new Date();
var time = [pad(d.getHours()),
pad(d.getMinutes()),
pad(d.getSeconds())].join(':');
return [d.getDate(), months[d.getMonth()], time].join(' ');
}
exports.log = function (msg) {};
exports.pump = null;
var Object_keys = Object.keys || function (obj) {
var res = [];
for (var key in obj) res.push(key);
return res;
};
var Object_getOwnPropertyNames = Object.getOwnPropertyNames || function (obj) {
var res = [];
for (var key in obj) {
if (Object.hasOwnProperty.call(obj, key)) res.push(key);
}
return res;
};
var Object_create = Object.create || function (prototype, properties) {
// from es5-shim
var object;
if (prototype === null) {
object = { '__proto__' : null };
}
else {
if (typeof prototype !== 'object') {
throw new TypeError(
'typeof prototype[' + (typeof prototype) + '] != \'object\''
);
}
var Type = function () {};
Type.prototype = prototype;
object = new Type();
object.__proto__ = prototype;
}
if (typeof properties !== 'undefined' && Object.defineProperties) {
Object.defineProperties(object, properties);
}
return object;
};
exports.inherits = function(ctor, superCtor) {
ctor.super_ = superCtor;
ctor.prototype = Object_create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false,
writable: true,
configurable: true
}
});
};
var formatRegExp = /%[sdj%]/g;
exports.format = function(f) {
if (typeof f !== 'string') {
var objects = [];
for (var i = 0; i < arguments.length; i++) {
objects.push(exports.inspect(arguments[i]));
}
return objects.join(' ');
}
var i = 1;
var args = arguments;
var len = args.length;
var str = String(f).replace(formatRegExp, function(x) {
if (x === '%%') return '%';
if (i >= len) return x;
switch (x) {
case '%s': return String(args[i++]);
case '%d': return Number(args[i++]);
case '%j': return JSON.stringify(args[i++]);
default:
return x;
}
});
for(var x = args[i]; i < len; x = args[++i]){
if (x === null || typeof x !== 'object') {
str += ' ' + x;
} else {
str += ' ' + exports.inspect(x);
}
}
return str;
};
},{"events":2}],"game-shell":[function(require,module,exports){
module.exports=require('IZUbLl');
},{}],"IZUbLl":[function(require,module,exports){
"use strict"
var EventEmitter = require("events").EventEmitter
, util = require("util")
, domready = require("domready")
, vkey = require("vkey")
, invert = require("invert-hash")
, uniq = require("uniq")
, lowerBound = require("lower-bound")
, iota = require("iota-array")
, min = Math.min
require("./lib/raf-polyfill.js")
//Remove angle braces and other useless crap
var filtered_vkey = (function() {
var result = new Array(256)
, i, j, k
for(i=0; i<256; ++i) {
result[i] = "UNK"
}
for(i in vkey) {
k = vkey[i]
if(k.charAt(0) === '<' && k.charAt(k.length-1) === '>') {
k = k.substring(1, k.length-1)
}
k = k.replace(/\s/g, "-")
result[parseInt(i)] = k
}
return result
})()
//Compute minimal common set of keyboard functions
var keyNames = uniq(Object.keys(invert(filtered_vkey)))
//Translates a virtual keycode to a normalized keycode
function virtualKeyCode(key) {
var idx = lowerBound(keyNames, key)
if(idx < 0 || idx >= keyNames.length) {
return -1
}
return idx
}
//Maps a physical keycode to a normalized keycode
function physicalKeyCode(key) {
return virtualKeyCode(filtered_vkey[key])
}
//Game shell
function GameShell() {
EventEmitter.call(this)
this._curKeyState = new Array(keyNames.length)
this._pressCount = new Array(keyNames.length)
this._releaseCount = new Array(keyNames.length)
this._tickInterval = null
this._tickRate = 0
this._lastTick = Date.now()
this._frameTime = 0.0
this._paused = false
this._render = render.bind(undefined, this)
for(var i=0; i<keyNames.length; ++i) {
this._curKeyState[i] = false
this._pressCount[i] = this._releaseCount[i] = 0
}
//Public members
this.element = null
this.bindings = {}
this.frameSkip = 100.0
this.tickCount = 0
this.frameCount = 0
this.startTime = Date.now()
this.tickTime = this._tickRate
this.frameTime = 10.0
//Mouse state
this.mouseX = 0
this.mouseY = 0
this.prevMouseX = 0
this.prevMouseY = 0
}
util.inherits(GameShell, EventEmitter)
//Bind keynames
GameShell.prototype.keyNames = keyNames
//Binds a virtual keyboard event to a physical key
GameShell.prototype.bind = function(virtual_key) {
//Look up previous key bindings
var arr
if(virtual_key in this.bindings) {
arr = this.bindings[virtual_key]
} else {
arr = []
}
//Add keys to list
var physical_key
for(var i=1, n=arguments.length; i<n; ++i) {
physical_key = arguments[i]
if(virtualKeyCode(physical_key) >= 0) {
arr.push(physical_key)
}
}
//Remove any duplicate keys
arr = uniq(arr)
if(arr.length > 0) {
this.bindings[virtual_key] = arr
}
}
//Unbinds a virtual keyboard event
GameShell.prototype.unbind = function(virtual_key) {
if(virtual_key in this.bindings) {
delete this.bindings[virtual_key]
}
}
//Checks if a key is set in a given state
function lookupKey(state, bindings, key) {
if(key in bindings) {
var arr = bindings[key]
for(var i=0, n=arr.length; i<n; ++i) {
if(state[virtualKeyCode(arr[i])]) {
return true
}
}
return false
}
var kc = virtualKeyCode(key)
if(kc >= 0) {
return state[kc]
}
return false
}
//Checks if a key is set in a given state
function lookupCount(state, bindings, key) {
if(key in bindings) {
var arr = bindings[key], r = 0
for(var i=0, n=arr.length; i<n; ++i) {
r += state[virtualKeyCode(arr[i])]
}
return r
}
var kc = virtualKeyCode(key)
if(kc >= 0) {
return state[kc]
}
return 0
}
//Checks if a key (either physical or virtual) is currently held down
GameShell.prototype.down = function(key) {
return lookupKey(this._curKeyState, this.bindings, key)
}
//Checks if a key was ever down
GameShell.prototype.wasDown = function(key) {
return this.down(key) || this.press(key)
}
//Opposite of down
GameShell.prototype.up = function(key) {
return !this.down(key)
}
GameShell.prototype.wasUp = function(key) {
return this.up(key) || this.release(key)
}
//Returns the number of times a key was pressed since last tick
GameShell.prototype.press = function(key) {
return lookupCount(this._pressCount, this.bindings, key)
}
//Returns the number of times a key was released since last tick
GameShell.prototype.release = function(key) {
return lookupCount(this._releaseCount, this.bindings, key)
}
//Pause/unpause the game loop
Object.defineProperty(GameShell.prototype, "paused", {
get: function() {
return this._paused
},
set: function(p) {
if(p) {
if(!this._paused) {
this._paused = true
this._frameTime = min(1.0, (Date.now() - this._lastTick) / this._tickRate)
}
} else if(this._paused) {
this._paused = false
this._lastTick = Date.now() - Math.floor(this._frameTime * this._tickRate)
}
}
})
//Set key state
function setKeyState(shell, key, state) {
var ps = shell._curKeyState[key]
if(ps !== state) {
if(state) {
shell._pressCount[key]++
} else {
shell._releaseCount[key]++
}
shell._curKeyState[key] = state
}
}
//Ticks the game state one update
function tick(shell) {
var skip = Date.now() + shell.frameSkip
, pCount = shell._pressCount
, rCount = shell._releaseCount
, i, s, t
, tr = shell._tickRate
, n = keyNames.length
while(!shell._paused &&
Date.now() >= shell._lastTick + tr) {
//Skip a frame if we are over budget
if(Date.now() > skip) {
shell._lastTick = Date.now() + tr
return
}
//Update counters and time
++shell.tickCount
shell._lastTick += tr
//Tick the game
s = Date.now()
shell.emit("tick")
t = Date.now()
shell.tickTime = shell.tickTime * 0.3 + (t - s) * 0.7
//Shift input state
for(i=0; i<n; ++i) {
pCount[i] = rCount[i] = 0
}
shell.prevMouseX = shell.mouseX
shell.prevMouseY = shell.mouseY
}
}
//Render stuff
function render(shell) {
//Tick the shell
tick(shell)
//Compute frame time
var dt
if(shell._paused) {
dt = shell._frameTime
} else {
dt = min(1.0, (Date.now() - shell._lastTick) / shell._tickRate)
}
//Draw a frame
++shell.frameCount
var s = Date.now()
shell.emit("render", dt)
var t = Date.now()
shell.frameTime = shell.frameTime * 0.3 + (t - s) * 0.7
//Request next frame
requestAnimationFrame(shell._render)
}
//Set key up
function handleKeyUp(shell, ev) {
var kc = physicalKeyCode(ev.keyCode || ev.which || ev.charCode)
if(kc >= 0) {
setKeyState(shell, kc, false)
}
}
//Set key down
function handleKeyDown(shell, ev) {
var kc = physicalKeyCode(ev.keyCode || ev.char || ev.which || ev.charCode)
if(kc >= 0) {
setKeyState(shell, kc, true)
}
}
var mouseCodes = iota(5).map(function(n) {
return virtualKeyCode("mouse-" + (n+1))
})
function setMouseButtons(shell, buttons) {
for(var i=0; i<5; ++i) {
setKeyState(shell, mouseCodes[i], !!(buttons & (1<<i)))
}
}
function handleMouseMove(shell, ev) {
if(ev.which !== undefined) {
setMouseButtons(shell, ev.which)
}
if(ev.buttons !== undefined) {
setMouseButtons(shell, ev.buttons)
}
shell.mouseX = ev.clientX
shell.mouseY = ev.clientY
}
function handleMouseDown(shell, ev) {
handleMouseMove(shell, ev)
setKeyState(shell, mouseCodes[ev.button], true)
}
function handleMouseUp(shell, ev) {
handleMouseMove(shell, ev)
setKeyState(shell, mouseCodes[ev.button], false)
}
function handleMouseEnter(shell, ev) {
handleMouseMove(shell, ev)
shell.prevMouseX = shell.mouseX = ev.clientX
shell.prevMouseY = shell.mouseY = ev.clientY
}
function handleMouseLeave(shell, ev) {
for(var i=0; i<5; ++i) {
setKeyState(shell, mouseCodes[i], false)
}
}
function handleBlur(shell, ev) {
var n = keyNames.length
, c = shell._curKeyState
, i
for(i=0; i<n; ++i) {
c[i] = false
}
}
function makeDefaultContainer() {
var container = document.createElement("div")
container.style.position = "absolute"
container.style.left = "0px"
container.style.right = "0px"
container.style.top = "0px"
container.style.bottom = "0px"
document.body.appendChild(container)
return container
}
function createShell(options) {
options = options || {}
//Create initial shell
var shell = new GameShell()
shell._tickRate = options.tickRate || 30
shell.frameSkip = options.frameSkip || (shell._tickRate+5) * 5
//Set bindings
if(options.bindings) {
shell.bindings = bindings
}
//Wait for dom to intiailize
setTimeout(function() { domready(function() {
//Retrieve element
var element = options.element
if(typeof element === "string") {
var e = document.getElementById(element)
if(!e) {
e = document.querySelector(element)
}
if(!e) {
e = document.getElementByClass(element)[0]
}
if(!e) {
e = makeDefaultContainer()
}
shell.element = e
} else if(typeof element === "object" && !!element) {
shell.element = element
} else if(typeof element === "function") {
shell.element = element()
} else {
shell.element = makeDefaultContainer()
}
//Disable user-select
if(shell.element.style) {
shell.element.style["-webkit-touch-callout"] = "none"
shell.element.style["-webkit-user-select"] = "none"
shell.element.style["-khtml-user-select"] = "none"
shell.element.style["-moz-user-select"] = "none"
shell.element.style["-ms-user-select"] = "none"
shell.element.style["user-select"] = "none"
}
//Hook input listeners
window.addEventListener("keydown", handleKeyDown.bind(undefined, shell), true)
window.addEventListener("keyup", handleKeyUp.bind(undefined, shell), true)
window.addEventListener("mousedown", handleMouseDown.bind(undefined, shell), true)
window.addEventListener("mouseup", handleMouseUp.bind(undefined, shell), true)
window.addEventListener("mousemove", handleMouseMove.bind(undefined, shell), true)
window.addEventListener("mouseleave", handleMouseLeave.bind(undefined, shell), true)
window.addEventListener("mouseenter", handleMouseEnter.bind(undefined, shell), true)
window.addEventListener("blur", handleBlur.bind(undefined, shell), true)
//Initialize tick counter
shell._lastTick = Date.now()
shell._paused = false
shell.startTime = Date.now()
//Set up a tick interval
shell._tickInterval = setInterval(tick, shell._tickRate, shell)
//Create an animation frame handler
requestAnimationFrame(shell._render)
//Emit initialize event
shell.emit("init")
})}, 0)
return shell
}
module.exports = createShell
},{"events":2,"util":4,"./lib/raf-polyfill.js":3,"domready":5,"vkey":6,"invert-hash":7,"uniq":8,"lower-bound":9,"iota-array":10}],5:[function(require,module,exports){
/*!
* domready (c) Dustin Diaz 2012 - License MIT
*/
!function (name, definition) {
if (typeof module != 'undefined') module.exports = definition()
else if (typeof define == 'function' && typeof define.amd == 'object') define(definition)
else this[name] = definition()
}('domready', function (ready) {
var fns = [], fn, f = false
, doc = document
, testEl = doc.documentElement
, hack = testEl.doScroll
, domContentLoaded = 'DOMContentLoaded'
, addEventListener = 'addEventListener'
, onreadystatechange = 'onreadystatechange'
, readyState = 'readyState'
, loaded = /^loade|c/.test(doc[readyState])
function flush(f) {
loaded = 1
while (f = fns.shift()) f()
}
doc[addEventListener] && doc[addEventListener](domContentLoaded, fn = function () {
doc.removeEventListener(domContentLoaded, fn, f)
flush()
}, f)
hack && doc.attachEvent(onreadystatechange, fn = function () {
if (/^c/.test(doc[readyState])) {
doc.detachEvent(onreadystatechange, fn)
flush()
}
})
return (ready = hack ?
function (fn) {
self != top ?
loaded ? fn() : fns.push(fn) :
function () {
try {
testEl.doScroll('left')
} catch (e) {
return setTimeout(function() { ready(fn) }, 50)
}
fn()
}()
} :
function (fn) {
loaded ? fn() : fns.push(fn)
})
})
},{}],6:[function(require,module,exports){
(function(){var ua = typeof window !== 'undefined' ? window.navigator.userAgent : ''
, isOSX = /OS X/.test(ua)
, isOpera = /Opera/.test(ua)
, maybeFirefox = !/like Gecko/.test(ua) && !isOpera
var i, output = module.exports = {
0: isOSX ? '<menu>' : '<UNK>'
, 1: '<mouse 1>'
, 2: '<mouse 2>'
, 3: '<break>'
, 4: '<mouse 3>'
, 5: '<mouse 4>'
, 6: '<mouse 5>'
, 8: '<backspace>'
, 9: '<tab>'
, 12: '<clear>'
, 13: '<enter>'
, 16: '<shift>'
, 17: '<control>'
, 18: '<alt>'
, 19: '<pause>'
, 20: '<caps-lock>'
, 21: '<ime-hangul>'
, 23: '<ime-junja>'
, 24: '<ime-final>'
, 25: '<ime-kanji>'
, 27: '<escape>'
, 28: '<ime-convert>'
, 29: '<ime-nonconvert>'
, 30: '<ime-accept>'
, 31: '<ime-mode-change>'
, 27: '<escape>'
, 32: '<space>'
, 33: '<page-up>'
, 34: '<page-down>'
, 35: '<end>'
, 36: '<home>'
, 37: '<left>'
, 38: '<up>'
, 39: '<right>'
, 40: '<down>'
, 41: '<select>'
, 42: '<print>'
, 43: '<execute>'
, 44: '<snapshot>'
, 45: '<insert>'
, 46: '<delete>'
, 47: '<help>'
, 91: '<meta>' // meta-left -- no one handles left and right properly, so we coerce into one.
, 92: '<meta>' // meta-right
, 93: isOSX ? '<meta>' : '<menu>' // chrome,opera,safari all report this for meta-right (osx mbp).
, 95: '<sleep>'
, 106: '<num-*>'
, 107: '<num-+>'
, 108: '<num-enter>'
, 109: '<num-->'
, 110: '<num-.>'
, 111: '<num-/>'
, 144: '<num-lock>'
, 145: '<scroll-lock>'
, 160: '<shift-left>'
, 161: '<shift-right>'
, 162: '<control-left>'
, 163: '<control-right>'
, 164: '<alt-left>'
, 165: '<alt-right>'
, 166: '<browser-back>'
, 167: '<browser-forward>'
, 168: '<browser-refresh>'
, 169: '<browser-stop>'
, 170: '<browser-search>'
, 171: '<browser-favorites>'
, 172: '<browser-home>'
// ff/osx reports '<volume-mute>' for '-'
, 173: isOSX && maybeFirefox ? '-' : '<volume-mute>'
, 174: '<volume-down>'
, 175: '<volume-up>'
, 176: '<next-track>'
, 177: '<prev-track>'
, 178: '<stop>'
, 179: '<play-pause>'
, 180: '<launch-mail>'
, 181: '<launch-media-select>'
, 182: '<launch-app 1>'
, 183: '<launch-app 2>'
, 186: ';'
, 187: '='
, 188: ','
, 189: '-'
, 190: '.'
, 191: '/'
, 192: '`'
, 219: '['
, 220: '\\'
, 221: ']'
, 222: "'"
, 223: '<meta>'
, 224: '<meta>' // firefox reports meta here.
, 226: '<alt-gr>'
, 229: '<ime-process>'
, 231: isOpera ? '`' : '<unicode>'
, 246: '<attention>'
, 247: '<crsel>'
, 248: '<exsel>'
, 249: '<erase-eof>'
, 250: '<play>'
, 251: '<zoom>'
, 252: '<no-name>'
, 253: '<pa-1>'
, 254: '<clear>'
}
for(i = 58; i < 65; ++i) {
output[i] = String.fromCharCode(i)
}
// 0-9
for(i = 48; i < 58; ++i) {
output[i] = (i - 48)+''
}
// A-Z
for(i = 65; i < 91; ++i) {
output[i] = String.fromCharCode(i)
}
// num0-9
for(i = 96; i < 107; ++i) {
output[i] = '<num-'+(i - 96)+'>'
}
// F1-F24
for(i = 112; i < 136; ++i) {
output[i] = 'F'+(i-111)
}
})()
},{}],7:[function(require,module,exports){
"use strict"
function invert(hash) {
var result = {}
for(var i in hash) {
if(hash.hasOwnProperty(i)) {
result[hash[i]] = i
}
}
return result
}
module.exports = invert
},{}],8:[function(require,module,exports){
"use strict"
function unique_pred(list, compare) {
var ptr = 1
, len = list.length
, a=list[0], b=list[0]
for(var i=1; i<len; ++i) {
b = a
a = list[i]
if(compare(a, b)) {
if(i === ptr) {
ptr++
continue
}
list[ptr++] = a
}
}
list.length = ptr
return list
}
function unique_eq(list) {
var ptr = 1
, len = list.length
, a=list[0], b = list[0]
for(var i=1; i<len; ++i, b=a) {
b = a
a = list[i]
if(a !== b) {
if(i === ptr) {
ptr++
continue
}
list[ptr++] = a
}
}
list.length = ptr
return list
}
function unique(list, compare, sorted) {
if(list.length === 0) {
return []
}
if(compare) {
if(!sorted) {
list.sort(compare)
}
return unique_pred(list, compare)
}
if(!sorted) {
list.sort()
}
return unique_eq(list)
}
module.exports = unique
},{}],9:[function(require,module,exports){
"use strict"
function lowerBound_cmp(array, value, compare, lo, hi) {
lo = lo|0
hi = hi|0
while(lo < hi) {
var m = (lo + hi) >>> 1
, v = compare(value, array[m])
if(v < 0) {
hi = m-1
} else if(v > 0) {
lo = m+1
} else {
hi = m
}
}
if(compare(array[lo], value) <= 0) {
return lo
}
return lo - 1
}
function lowerBound_def(array, value, lo, hi) {
lo = lo|0
hi = hi|0
while(lo < hi) {
var m = (lo + hi) >>> 1
if(value < array[m]) {
hi = m-1
} else if(value > array[m]) {
lo = m+1
} else {
hi = m
}
}
if(array[lo] <= value) {
return lo
}
return lo - 1
}
function lowerBound(array, value, compare, lo, hi) {
if(!lo) {
lo = 0
}
if(typeof(hi) !== "number") {
hi = array.length-1
}
if(compare) {
return lowerBound_cmp(array, value, compare, lo, hi)
}
return lowerBound_def(array, value, lo, hi)
}
module.exports = lowerBound
},{}],10:[function(require,module,exports){
"use strict"
function iota(n) {
var result = new Array(n)
for(var i=0; i<n; ++i) {
result[i] = i
}
return result
}
module.exports = iota
},{}]},{},[])
//@ sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlcyI6WyIvdXNyL2xvY2FsL2xpYi9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvaW5zZXJ0LW1vZHVsZS1nbG9iYWxzL25vZGVfbW9kdWxlcy9wcm9jZXNzL2Jyb3dzZXIuanMiLCIvdXNyL2xvY2FsL2xpYi9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnJvd3Nlci1idWlsdGlucy9idWlsdGluL2V2ZW50cy5qcyIsIi90bXAvZ2FtZS1zaGVsbDExMzY2LTExMjgxLW40eXIwOS9ub2RlX21vZHVsZXMvZ2FtZS1zaGVsbC9saWIvcmFmLXBvbHlmaWxsLmpzIiwiL3Vzci9sb2NhbC9saWIvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItYnVpbHRpbnMvYnVpbHRpbi91dGlsLmpzIiwiL3RtcC9nYW1lLXNoZWxsMTEzNjYtMTEyODEtbjR5cjA5L25vZGVfbW9kdWxlcy9nYW1lLXNoZWxsL3NoZWxsLmpzIiwiL3RtcC9nYW1lLXNoZWxsMTEzNjYtMTEyODEtbjR5cjA5L25vZGVfbW9kdWxlcy9nYW1lLXNoZWxsL25vZGVfbW9kdWxlcy9kb21yZWFkeS9yZWFkeS5qcyIsIi90bXAvZ2FtZS1zaGVsbDExMzY2LTExMjgxLW40eXIwOS9ub2RlX21vZHVsZXMvZ2FtZS1zaGVsbC9ub2RlX21vZHVsZXMvdmtleS9pbmRleC5qcyIsIi90bXAvZ2FtZS1zaGVsbDExMzY2LTExMjgxLW40eXIwOS9ub2RlX21vZHVsZXMvZ2FtZS1zaGVsbC9ub2RlX21vZHVsZXMvaW52ZXJ0LWhhc2gvaW52ZXJ0LmpzIiwiL3RtcC9nYW1lLXNoZWxsMTEzNjYtMTEyODEtbjR5cjA5L25vZGVfbW9kdWxlcy9nYW1lLXNoZWxsL25vZGVfbW9kdWxlcy91bmlxL3VuaXEuanMiLCIvdG1wL2dhbWUtc2hlbGwxMTM2Ni0xMTI4MS1uNHlyMDkvbm9kZV9tb2R1bGVzL2dhbWUtc2hlbGwvbm9kZV9tb2R1bGVzL2xvd2VyLWJvdW5kL2xiLmpzIiwiL3RtcC9nYW1lLXNoZWxsMTEzNjYtMTEyODEtbjR5cjA5L25vZGVfbW9kdWxlcy9nYW1lLXNoZWxsL25vZGVfbW9kdWxlcy9pb3RhLWFycmF5L2lvdGEuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeExBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDL1ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOWFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNaQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3REQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwic291cmNlc0NvbnRlbnQiOlsiLy8gc2hpbSBmb3IgdXNpbmcgcHJvY2VzcyBpbiBicm93c2VyXG5cbnZhciBwcm9jZXNzID0gbW9kdWxlLmV4cG9ydHMgPSB7fTtcblxucHJvY2Vzcy5uZXh0VGljayA9IChmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGNhblNldEltbWVkaWF0ZSA9IHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnXG4gICAgJiYgd2luZG93LnNldEltbWVkaWF0ZTtcbiAgICB2YXIgY2FuUG9zdCA9IHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnXG4gICAgJiYgd2luZG93LnBvc3RNZXNzYWdlICYmIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyXG4gICAgO1xuXG4gICAgaWYgKGNhblNldEltbWVkaWF0ZSkge1xuICAgICAgICByZXR1cm4gZnVuY3Rpb24gKGYpIHsgcmV0dXJuIHdpbmRvdy5zZXRJbW1lZGlhdGUoZikgfTtcbiAgICB9XG5cbiAgICBpZiAoY2FuUG9zdCkge1xuICAgICAgICB2YXIgcXVldWUgPSBbXTtcbiAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ21lc3NhZ2UnLCBmdW5jdGlvbiAoZXYpIHtcbiAgICAgICAgICAgIGlmIChldi5zb3VyY2UgPT09IHdpbmRvdyAmJiBldi5kYXRhID09PSAncHJvY2Vzcy10aWNrJykge1xuICAgICAgICAgICAgICAgIGV2LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgICAgICAgICAgICAgIGlmIChxdWV1ZS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBmbiA9IHF1ZXVlLnNoaWZ0KCk7XG4gICAgICAgICAgICAgICAgICAgIGZuKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9LCB0cnVlKTtcblxuICAgICAgICByZXR1cm4gZnVuY3Rpb24gbmV4dFRpY2soZm4pIHtcbiAgICAgICAgICAgIHF1ZXVlLnB1c2goZm4pO1xuICAgICAgICAgICAgd2luZG93LnBvc3RNZXNzYWdlKCdwcm9jZXNzLXRpY2snLCAnKicpO1xuICAgICAgICB9O1xuICAgIH1cblxuICAgIHJldHVybiBmdW5jdGlvbiBuZXh0VGljayhmbikge1xuICAgICAgICBzZXRUaW1lb3V0KGZuLCAwKTtcbiAgICB9O1xufSkoKTtcblxucHJvY2Vzcy50aXRsZSA9ICdicm93c2VyJztcbnByb2Nlc3MuYnJvd3NlciA9IHRydWU7XG5wcm9jZXNzLmVudiA9IHt9O1xucHJvY2Vzcy5hcmd2ID0gW107XG5cbnByb2Nlc3MuYmluZGluZyA9IGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdwcm9jZXNzLmJpbmRpbmcgaXMgbm90IHN1cHBvcnRlZCcpO1xufVxuXG4vLyBUT0RPKHNodHlsbWFuKVxucHJvY2Vzcy5jd2QgPSBmdW5jdGlvbiAoKSB7IHJldHVybiAnLycgfTtcbnByb2Nlc3MuY2hkaXIgPSBmdW5jdGlvbiAoZGlyKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdwcm9jZXNzLmNoZGlyIGlzIG5vdCBzdXBwb3J0ZWQnKTtcbn07XG4iLCIoZnVuY3Rpb24ocHJvY2Vzcyl7aWYgKCFwcm9jZXNzLkV2ZW50RW1pdHRlcikgcHJvY2Vzcy5FdmVudEVtaXR0ZXIgPSBmdW5jdGlvbiAoKSB7fTtcblxudmFyIEV2ZW50RW1pdHRlciA9IGV4cG9ydHMuRXZlbnRFbWl0dGVyID0gcHJvY2Vzcy5FdmVudEVtaXR0ZXI7XG52YXIgaXNBcnJheSA9IHR5cGVvZiBBcnJheS5pc0FycmF5ID09PSAnZnVuY3Rpb24nXG4gICAgPyBBcnJheS5pc0FycmF5XG4gICAgOiBmdW5jdGlvbiAoeHMpIHtcbiAgICAgICAgcmV0dXJuIE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbCh4cykgPT09ICdbb2JqZWN0IEFycmF5XSdcbiAgICB9XG47XG5mdW5jdGlvbiBpbmRleE9mICh4cywgeCkge1xuICAgIGlmICh4cy5pbmRleE9mKSByZXR1cm4geHMuaW5kZXhPZih4KTtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHhzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGlmICh4ID09PSB4c1tpXSkgcmV0dXJuIGk7XG4gICAgfVxuICAgIHJldHVybiAtMTtcbn1cblxuLy8gQnkgZGVmYXVsdCBFdmVudEVtaXR0ZXJzIHdpbGwgcHJpbnQgYSB3YXJuaW5nIGlmIG1vcmUgdGhhblxuLy8gMTAgbGlzdGVuZXJzIGFyZSBhZGRlZCB0byBpdC4gVGhpcyBpcyBhIHVzZWZ1bCBkZWZhdWx0IHdoaWNoXG4vLyBoZWxwcyBmaW5kaW5nIG1lbW9yeSBsZWFrcy5cbi8vXG4vLyBPYnZpb3VzbHkgbm90IGFsbCBFbWl0dGVycyBzaG91bGQgYmUgbGltaXRlZCB0byAxMC4gVGhpcyBmdW5jdGlvbiBhbGxvd3Ncbi8vIHRoYXQgdG8gYmUgaW5jcmVhc2VkLiBTZXQgdG8gemVybyBmb3IgdW5saW1pdGVkLlxudmFyIGRlZmF1bHRNYXhMaXN0ZW5lcnMgPSAxMDtcbkV2ZW50RW1pdHRlci5wcm90b3R5cGUuc2V0TWF4TGlzdGVuZXJzID0gZnVuY3Rpb24obikge1xuICBpZiAoIXRoaXMuX2V2ZW50cykgdGhpcy5fZXZlbnRzID0ge307XG4gIHRoaXMuX2V2ZW50cy5tYXhMaXN0ZW5lcnMgPSBuO1xufTtcblxuXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLmVtaXQgPSBmdW5jdGlvbih0eXBlKSB7XG4gIC8vIElmIHRoZXJlIGlzIG5vICdlcnJvcicgZXZlbnQgbGlzdGVuZXIgdGhlbiB0aHJvdy5cbiAgaWYgKHR5cGUgPT09ICdlcnJvcicpIHtcbiAgICBpZiAoIXRoaXMuX2V2ZW50cyB8fCAhdGhpcy5fZXZlbnRzLmVycm9yIHx8XG4gICAgICAgIChpc0FycmF5KHRoaXMuX2V2ZW50cy5lcnJvcikgJiYgIXRoaXMuX2V2ZW50cy5lcnJvci5sZW5ndGgpKVxuICAgIHtcbiAgICAgIGlmIChhcmd1bWVudHNbMV0gaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgICB0aHJvdyBhcmd1bWVudHNbMV07IC8vIFVuaGFuZGxlZCAnZXJyb3InIGV2ZW50XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJVbmNhdWdodCwgdW5zcGVjaWZpZWQgJ2Vycm9yJyBldmVudC5cIik7XG4gICAgICB9XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgaWYgKCF0aGlzLl9ldmVudHMpIHJldHVybiBmYWxzZTtcbiAgdmFyIGhhbmRsZXIgPSB0aGlzLl9ldmVudHNbdHlwZV07XG4gIGlmICghaGFuZGxlcikgcmV0dXJuIGZhbHNlO1xuXG4gIGlmICh0eXBlb2YgaGFuZGxlciA9PSAnZnVuY3Rpb24nKSB7XG4gICAgc3dpdGNoIChhcmd1bWVudHMubGVuZ3RoKSB7XG4gICAgICAvLyBmYXN0IGNhc2VzXG4gICAgICBjYXNlIDE6XG4gICAgICAgIGhhbmRsZXIuY2FsbCh0aGlzKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDI6XG4gICAgICAgIGhhbmRsZXIuY2FsbCh0aGlzLCBhcmd1bWVudHNbMV0pO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgMzpcbiAgICAgICAgaGFuZGxlci5jYWxsKHRoaXMsIGFyZ3VtZW50c1sxXSwgYXJndW1lbnRzWzJdKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICAvLyBzbG93ZXJcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHZhciBhcmdzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICAgICAgaGFuZGxlci5hcHBseSh0aGlzLCBhcmdzKTtcbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG5cbiAgfSBlbHNlIGlmIChpc0FycmF5KGhhbmRsZXIpKSB7XG4gICAgdmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpO1xuXG4gICAgdmFyIGxpc3RlbmVycyA9IGhhbmRsZXIuc2xpY2UoKTtcbiAgICBmb3IgKHZhciBpID0gMCwgbCA9IGxpc3RlbmVycy5sZW5ndGg7IGkgPCBsOyBpKyspIHtcbiAgICAgIGxpc3RlbmVyc1tpXS5hcHBseSh0aGlzLCBhcmdzKTtcbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG5cbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbn07XG5cbi8vIEV2ZW50RW1pdHRlciBpcyBkZWZpbmVkIGluIHNyYy9ub2RlX2V2ZW50cy5jY1xuLy8gRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5lbWl0KCkgaXMgYWxzbyBkZWZpbmVkIHRoZXJlLlxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5hZGRMaXN0ZW5lciA9IGZ1bmN0aW9uKHR5cGUsIGxpc3RlbmVyKSB7XG4gIGlmICgnZnVuY3Rpb24nICE9PSB0eXBlb2YgbGlzdGVuZXIpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2FkZExpc3RlbmVyIG9ubHkgdGFrZXMgaW5zdGFuY2VzIG9mIEZ1bmN0aW9uJyk7XG4gIH1cblxuICBpZiAoIXRoaXMuX2V2ZW50cykgdGhpcy5fZXZlbnRzID0ge307XG5cbiAgLy8gVG8gYXZvaWQgcmVjdXJzaW9uIGluIHRoZSBjYXNlIHRoYXQgdHlwZSA9PSBcIm5ld0xpc3RlbmVyc1wiISBCZWZvcmVcbiAgLy8gYWRkaW5nIGl0IHRvIHRoZSBsaXN0ZW5lcnMsIGZpcnN0IGVtaXQgXCJuZXdMaXN0ZW5lcnNcIi5cbiAgdGhpcy5lbWl0KCduZXdMaXN0ZW5lcicsIHR5cGUsIGxpc3RlbmVyKTtcblxuICBpZiAoIXRoaXMuX2V2ZW50c1t0eXBlXSkge1xuICAgIC8vIE9wdGltaXplIHRoZSBjYXNlIG9mIG9uZSBsaXN0ZW5lci4gRG9uJ3QgbmVlZCB0aGUgZXh0cmEgYXJyYXkgb2JqZWN0LlxuICAgIHRoaXMuX2V2ZW50c1t0eXBlXSA9IGxpc3RlbmVyO1xuICB9IGVsc2UgaWYgKGlzQXJyYXkodGhpcy5fZXZlbnRzW3R5cGVdKSkge1xuXG4gICAgLy8gQ2hlY2sgZm9yIGxpc3RlbmVyIGxlYWtcbiAgICBpZiAoIXRoaXMuX2V2ZW50c1t0eXBlXS53YXJuZWQpIHtcbiAgICAgIHZhciBtO1xuICAgICAgaWYgKHRoaXMuX2V2ZW50cy5tYXhMaXN0ZW5lcnMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBtID0gdGhpcy5fZXZlbnRzLm1heExpc3RlbmVycztcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIG0gPSBkZWZhdWx0TWF4TGlzdGVuZXJzO1xuICAgICAgfVxuXG4gICAgICBpZiAobSAmJiBtID4gMCAmJiB0aGlzLl9ldmVudHNbdHlwZV0ubGVuZ3RoID4gbSkge1xuICAgICAgICB0aGlzLl9ldmVudHNbdHlwZV0ud2FybmVkID0gdHJ1ZTtcbiAgICAgICAgY29uc29sZS5lcnJvcignKG5vZGUpIHdhcm5pbmc6IHBvc3NpYmxlIEV2ZW50RW1pdHRlciBtZW1vcnkgJyArXG4gICAgICAgICAgICAgICAgICAgICAgJ2xlYWsgZGV0ZWN0ZWQuICVkIGxpc3RlbmVycyBhZGRlZC4gJyArXG4gICAgICAgICAgICAgICAgICAgICAgJ1VzZSBlbWl0dGVyLnNldE1heExpc3RlbmVycygpIHRvIGluY3JlYXNlIGxpbWl0LicsXG4gICAgICAgICAgICAgICAgICAgICAgdGhpcy5fZXZlbnRzW3R5cGVdLmxlbmd0aCk7XG4gICAgICAgIGNvbnNvbGUudHJhY2UoKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBJZiB3ZSd2ZSBhbHJlYWR5IGdvdCBhbiBhcnJheSwganVzdCBhcHBlbmQuXG4gICAgdGhpcy5fZXZlbnRzW3R5cGVdLnB1c2gobGlzdGVuZXIpO1xuICB9IGVsc2Uge1xuICAgIC8vIEFkZGluZyB0aGUgc2Vjb25kIGVsZW1lbnQsIG5lZWQgdG8gY2hhbmdlIHRvIGFycmF5LlxuICAgIHRoaXMuX2V2ZW50c1t0eXBlXSA9IFt0aGlzLl9ldmVudHNbdHlwZV0sIGxpc3RlbmVyXTtcbiAgfVxuXG4gIHJldHVybiB0aGlzO1xufTtcblxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5vbiA9IEV2ZW50RW1pdHRlci5wcm90b3R5cGUuYWRkTGlzdGVuZXI7XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUub25jZSA9IGZ1bmN0aW9uKHR5cGUsIGxpc3RlbmVyKSB7XG4gIHZhciBzZWxmID0gdGhpcztcbiAgc2VsZi5vbih0eXBlLCBmdW5jdGlvbiBnKCkge1xuICAgIHNlbGYucmVtb3ZlTGlzdGVuZXIodHlwZSwgZyk7XG4gICAgbGlzdGVuZXIuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgfSk7XG5cbiAgcmV0dXJuIHRoaXM7XG59O1xuXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLnJlbW92ZUxpc3RlbmVyID0gZnVuY3Rpb24odHlwZSwgbGlzdGVuZXIpIHtcbiAgaWYgKCdmdW5jdGlvbicgIT09IHR5cGVvZiBsaXN0ZW5lcikge1xuICAgIHRocm93IG5ldyBFcnJvcigncmVtb3ZlTGlzdGVuZXIgb25seSB0YWtlcyBpbnN0YW5jZXMgb2YgRnVuY3Rpb24nKTtcbiAgfVxuXG4gIC8vIGRvZXMgbm90IHVzZSBsaXN0ZW5lcnMoKSwgc28gbm8gc2lkZSBlZmZlY3Qgb2YgY3JlYXRpbmcgX2V2ZW50c1t0eXBlXVxuICBpZiAoIXRoaXMuX2V2ZW50cyB8fCAhdGhpcy5fZXZlbnRzW3R5cGVdKSByZXR1cm4gdGhpcztcblxuICB2YXIgbGlzdCA9IHRoaXMuX2V2ZW50c1t0eXBlXTtcblxuICBpZiAoaXNBcnJheShsaXN0KSkge1xuICAgIHZhciBpID0gaW5kZXhPZihsaXN0LCBsaXN0ZW5lcik7XG4gICAgaWYgKGkgPCAwKSByZXR1cm4gdGhpcztcbiAgICBsaXN0LnNwbGljZShpLCAxKTtcbiAgICBpZiAobGlzdC5sZW5ndGggPT0gMClcbiAgICAgIGRlbGV0ZSB0aGlzLl9ldmVudHNbdHlwZV07XG4gIH0gZWxzZSBpZiAodGhpcy5fZXZlbnRzW3R5cGVdID09PSBsaXN0ZW5lcikge1xuICAgIGRlbGV0ZSB0aGlzLl9ldmVudHNbdHlwZV07XG4gIH1cblxuICByZXR1cm4gdGhpcztcbn07XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUucmVtb3ZlQWxsTGlzdGVuZXJzID0gZnVuY3Rpb24odHlwZSkge1xuICBpZiAoYXJndW1lbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgIHRoaXMuX2V2ZW50cyA9IHt9O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gZG9lcyBub3QgdXNlIGxpc3RlbmVycygpLCBzbyBubyBzaWRlIGVmZmVjdCBvZiBjcmVhdGluZyBfZXZlbnRzW3R5cGVdXG4gIGlmICh0eXBlICYmIHRoaXMuX2V2ZW50cyAmJiB0aGlzLl9ldmVudHNbdHlwZV0pIHRoaXMuX2V2ZW50c1t0eXBlXSA9IG51bGw7XG4gIHJldHVybiB0aGlzO1xufTtcblxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5saXN0ZW5lcnMgPSBmdW5jdGlvbih0eXBlKSB7XG4gIGlmICghdGhpcy5fZXZlbnRzKSB0aGlzLl9ldmVudHMgPSB7fTtcbiAgaWYgKCF0aGlzLl9ldmVudHNbdHlwZV0pIHRoaXMuX2V2ZW50c1t0eXBlXSA9IFtdO1xuICBpZiAoIWlzQXJyYXkodGhpcy5fZXZlbnRzW3R5cGVdKSkge1xuICAgIHRoaXMuX2V2ZW50c1t0eXBlXSA9IFt0aGlzLl9ldmVudHNbdHlwZV1dO1xuICB9XG4gIHJldHVybiB0aGlzLl9ldmVudHNbdHlwZV07XG59O1xuXG59KShyZXF1aXJlKFwiX19icm93c2VyaWZ5X3Byb2Nlc3NcIikpIiwiLy8gaHR0cDovL3BhdWxpcmlzaC5jb20vMjAxMS9yZXF1ZXN0YW5pbWF0aW9uZnJhbWUtZm9yLXNtYXJ0LWFuaW1hdGluZy9cbi8vIGh0dHA6Ly9teS5vcGVyYS5jb20vZW1vbGxlci9ibG9nLzIwMTEvMTIvMjAvcmVxdWVzdGFuaW1hdGlvbmZyYW1lLWZvci1zbWFydC1lci1hbmltYXRpbmdcbiBcbi8vIHJlcXVlc3RBbmltYXRpb25GcmFtZSBwb2x5ZmlsbCBieSBFcmlrIE3DtmxsZXIuIGZpeGVzIGZyb20gUGF1bCBJcmlzaCBhbmQgVGlubyBaaWpkZWxcbiBcbi8vIE1JVCBsaWNlbnNlXG52YXIgbGFzdFRpbWUgPSAwO1xudmFyIHZlbmRvcnMgPSBbJ21zJywgJ21veicsICd3ZWJraXQnLCAnbyddO1xuZm9yKHZhciB4ID0gMDsgeCA8IHZlbmRvcnMubGVuZ3RoICYmICF3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lOyArK3gpIHtcbiAgICB3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lID0gd2luZG93W3ZlbmRvcnNbeF0rJ1JlcXVlc3RBbmltYXRpb25GcmFtZSddO1xuICAgIHdpbmRvdy5jYW5jZWxBbmltYXRpb25GcmFtZSA9IHdpbmRvd1t2ZW5kb3JzW3hdKydDYW5jZWxBbmltYXRpb25GcmFtZSddIFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHx8IHdpbmRvd1t2ZW5kb3JzW3hdKydDYW5jZWxSZXF1ZXN0QW5pbWF0aW9uRnJhbWUnXTtcbn1cblxuaWYgKCF3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lKVxuICAgIHdpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUgPSBmdW5jdGlvbihjYWxsYmFjaywgZWxlbWVudCkge1xuICAgICAgICB2YXIgY3VyclRpbWUgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcbiAgICAgICAgdmFyIHRpbWVUb0NhbGwgPSBNYXRoLm1heCgwLCAxNiAtIChjdXJyVGltZSAtIGxhc3RUaW1lKSk7XG4gICAgICAgIHZhciBpZCA9IHdpbmRvdy5zZXRUaW1lb3V0KGZ1bmN0aW9uKCkgeyBjYWxsYmFjayhjdXJyVGltZSArIHRpbWVUb0NhbGwpOyB9LCBcbiAgICAgICAgICB0aW1lVG9DYWxsKTtcbiAgICAgICAgbGFzdFRpbWUgPSBjdXJyVGltZSArIHRpbWVUb0NhbGw7XG4gICAgICAgIHJldHVybiBpZDtcbiAgICB9O1xuXG5pZiAoIXdpbmRvdy5jYW5jZWxBbmltYXRpb25GcmFtZSlcbiAgICB3aW5kb3cuY2FuY2VsQW5pbWF0aW9uRnJhbWUgPSBmdW5jdGlvbihpZCkge1xuICAgICAgICBjbGVhclRpbWVvdXQoaWQpO1xuICAgIH07XG4iLCJ2YXIgZXZlbnRzID0gcmVxdWlyZSgnZXZlbnRzJyk7XG5cbmV4cG9ydHMuaXNBcnJheSA9IGlzQXJyYXk7XG5leHBvcnRzLmlzRGF0ZSA9IGZ1bmN0aW9uKG9iail7cmV0dXJuIE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChvYmopID09PSAnW29iamVjdCBEYXRlXSd9O1xuZXhwb3J0cy5pc1JlZ0V4cCA9IGZ1bmN0aW9uKG9iail7cmV0dXJuIE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChvYmopID09PSAnW29iamVjdCBSZWdFeHBdJ307XG5cblxuZXhwb3J0cy5wcmludCA9IGZ1bmN0aW9uICgpIHt9O1xuZXhwb3J0cy5wdXRzID0gZnVuY3Rpb24gKCkge307XG5leHBvcnRzLmRlYnVnID0gZnVuY3Rpb24oKSB7fTtcblxuZXhwb3J0cy5pbnNwZWN0ID0gZnVuY3Rpb24ob2JqLCBzaG93SGlkZGVuLCBkZXB0aCwgY29sb3JzKSB7XG4gIHZhciBzZWVuID0gW107XG5cbiAgdmFyIHN0eWxpemUgPSBmdW5jdGlvbihzdHIsIHN0eWxlVHlwZSkge1xuICAgIC8vIGh0dHA6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvQU5TSV9lc2NhcGVfY29kZSNncmFwaGljc1xuICAgIHZhciBzdHlsZXMgPVxuICAgICAgICB7ICdib2xkJyA6IFsxLCAyMl0sXG4gICAgICAgICAgJ2l0YWxpYycgOiBbMywgMjNdLFxuICAgICAgICAgICd1bmRlcmxpbmUnIDogWzQsIDI0XSxcbiAgICAgICAgICAnaW52ZXJzZScgOiBbNywgMjddLFxuICAgICAgICAgICd3aGl0ZScgOiBbMzcsIDM5XSxcbiAgICAgICAgICAnZ3JleScgOiBbOTAsIDM5XSxcbiAgICAgICAgICAnYmxhY2snIDogWzMwLCAzOV0sXG4gICAgICAgICAgJ2JsdWUnIDogWzM0LCAzOV0sXG4gICAgICAgICAgJ2N5YW4nIDogWzM2LCAzOV0sXG4gICAgICAgICAgJ2dyZWVuJyA6IFszMiwgMzldLFxuICAgICAgICAgICdtYWdlbnRhJyA6IFszNSwgMzldLFxuICAgICAgICAgICdyZWQnIDogWzMxLCAzOV0sXG4gICAgICAgICAgJ3llbGxvdycgOiBbMzMsIDM5XSB9O1xuXG4gICAgdmFyIHN0eWxlID1cbiAgICAgICAgeyAnc3BlY2lhbCc6ICdjeWFuJyxcbiAgICAgICAgICAnbnVtYmVyJzogJ2JsdWUnLFxuICAgICAgICAgICdib29sZWFuJzogJ3llbGxvdycsXG4gICAgICAgICAgJ3VuZGVmaW5lZCc6ICdncmV5JyxcbiAgICAgICAgICAnbnVsbCc6ICdib2xkJyxcbiAgICAgICAgICAnc3RyaW5nJzogJ2dyZWVuJyxcbiAgICAgICAgICAnZGF0ZSc6ICdtYWdlbnRhJyxcbiAgICAgICAgICAvLyBcIm5hbWVcIjogaW50ZW50aW9uYWxseSBub3Qgc3R5bGluZ1xuICAgICAgICAgICdyZWdleHAnOiAncmVkJyB9W3N0eWxlVHlwZV07XG5cbiAgICBpZiAoc3R5bGUpIHtcbiAgICAgIHJldHVybiAnXFwwMzNbJyArIHN0eWxlc1tzdHlsZV1bMF0gKyAnbScgKyBzdHIgK1xuICAgICAgICAgICAgICdcXDAzM1snICsgc3R5bGVzW3N0eWxlXVsxXSArICdtJztcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHN0cjtcbiAgICB9XG4gIH07XG4gIGlmICghIGNvbG9ycykge1xuICAgIHN0eWxpemUgPSBmdW5jdGlvbihzdHIsIHN0eWxlVHlwZSkgeyByZXR1cm4gc3RyOyB9O1xuICB9XG5cbiAgZnVuY3Rpb24gZm9ybWF0KHZhbHVlLCByZWN1cnNlVGltZXMpIHtcbiAgICAvLyBQcm92aWRlIGEgaG9vayBmb3IgdXNlci1zcGVjaWZpZWQgaW5zcGVjdCBmdW5jdGlvbnMuXG4gICAgLy8gQ2hlY2sgdGhhdCB2YWx1ZSBpcyBhbiBvYmplY3Qgd2l0aCBhbiBpbnNwZWN0IGZ1bmN0aW9uIG9uIGl0XG4gICAgaWYgKHZhbHVlICYmIHR5cGVvZiB2YWx1ZS5pbnNwZWN0ID09PSAnZnVuY3Rpb24nICYmXG4gICAgICAgIC8vIEZpbHRlciBvdXQgdGhlIHV0aWwgbW9kdWxlLCBpdCdzIGluc3BlY3QgZnVuY3Rpb24gaXMgc3BlY2lhbFxuICAgICAgICB2YWx1ZSAhPT0gZXhwb3J0cyAmJlxuICAgICAgICAvLyBBbHNvIGZpbHRlciBvdXQgYW55IHByb3RvdHlwZSBvYmplY3RzIHVzaW5nIHRoZSBjaXJjdWxhciBjaGVjay5cbiAgICAgICAgISh2YWx1ZS5jb25zdHJ1Y3RvciAmJiB2YWx1ZS5jb25zdHJ1Y3Rvci5wcm90b3R5cGUgPT09IHZhbHVlKSkge1xuICAgICAgcmV0dXJuIHZhbHVlLmluc3BlY3QocmVjdXJzZVRpbWVzKTtcbiAgICB9XG5cbiAgICAvLyBQcmltaXRpdmUgdHlwZXMgY2Fubm90IGhhdmUgcHJvcGVydGllc1xuICAgIHN3aXRjaCAodHlwZW9mIHZhbHVlKSB7XG4gICAgICBjYXNlICd1bmRlZmluZWQnOlxuICAgICAgICByZXR1cm4gc3R5bGl6ZSgndW5kZWZpbmVkJywgJ3VuZGVmaW5lZCcpO1xuXG4gICAgICBjYXNlICdzdHJpbmcnOlxuICAgICAgICB2YXIgc2ltcGxlID0gJ1xcJycgKyBKU09OLnN0cmluZ2lmeSh2YWx1ZSkucmVwbGFjZSgvXlwifFwiJC9nLCAnJylcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAucmVwbGFjZSgvJy9nLCBcIlxcXFwnXCIpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLnJlcGxhY2UoL1xcXFxcIi9nLCAnXCInKSArICdcXCcnO1xuICAgICAgICByZXR1cm4gc3R5bGl6ZShzaW1wbGUsICdzdHJpbmcnKTtcblxuICAgICAgY2FzZSAnbnVtYmVyJzpcbiAgICAgICAgcmV0dXJuIHN0eWxpemUoJycgKyB2YWx1ZSwgJ251bWJlcicpO1xuXG4gICAgICBjYXNlICdib29sZWFuJzpcbiAgICAgICAgcmV0dXJuIHN0eWxpemUoJycgKyB2YWx1ZSwgJ2Jvb2xlYW4nKTtcbiAgICB9XG4gICAgLy8gRm9yIHNvbWUgcmVhc29uIHR5cGVvZiBudWxsIGlzIFwib2JqZWN0XCIsIHNvIHNwZWNpYWwgY2FzZSBoZXJlLlxuICAgIGlmICh2YWx1ZSA9PT0gbnVsbCkge1xuICAgICAgcmV0dXJuIHN0eWxpemUoJ251bGwnLCAnbnVsbCcpO1xuICAgIH1cblxuICAgIC8vIExvb2sgdXAgdGhlIGtleXMgb2YgdGhlIG9iamVjdC5cbiAgICB2YXIgdmlzaWJsZV9rZXlzID0gT2JqZWN0X2tleXModmFsdWUpO1xuICAgIHZhciBrZXlzID0gc2hvd0hpZGRlbiA/IE9iamVjdF9nZXRPd25Qcm9wZXJ0eU5hbWVzKHZhbHVlKSA6IHZpc2libGVfa2V5cztcblxuICAgIC8vIEZ1bmN0aW9ucyB3aXRob3V0IHByb3BlcnRpZXMgY2FuIGJlIHNob3J0Y3V0dGVkLlxuICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdmdW5jdGlvbicgJiYga2V5cy5sZW5ndGggPT09IDApIHtcbiAgICAgIGlmIChpc1JlZ0V4cCh2YWx1ZSkpIHtcbiAgICAgICAgcmV0dXJuIHN0eWxpemUoJycgKyB2YWx1ZSwgJ3JlZ2V4cCcpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdmFyIG5hbWUgPSB2YWx1ZS5uYW1lID8gJzogJyArIHZhbHVlLm5hbWUgOiAnJztcbiAgICAgICAgcmV0dXJuIHN0eWxpemUoJ1tGdW5jdGlvbicgKyBuYW1lICsgJ10nLCAnc3BlY2lhbCcpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIERhdGVzIHdpdGhvdXQgcHJvcGVydGllcyBjYW4gYmUgc2hvcnRjdXR0ZWRcbiAgICBpZiAoaXNEYXRlKHZhbHVlKSAmJiBrZXlzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuIHN0eWxpemUodmFsdWUudG9VVENTdHJpbmcoKSwgJ2RhdGUnKTtcbiAgICB9XG5cbiAgICB2YXIgYmFzZSwgdHlwZSwgYnJhY2VzO1xuICAgIC8vIERldGVybWluZSB0aGUgb2JqZWN0IHR5cGVcbiAgICBpZiAoaXNBcnJheSh2YWx1ZSkpIHtcbiAgICAgIHR5cGUgPSAnQXJyYXknO1xuICAgICAgYnJhY2VzID0gWydbJywgJ10nXTtcbiAgICB9IGVsc2Uge1xuICAgICAgdHlwZSA9ICdPYmplY3QnO1xuICAgICAgYnJhY2VzID0gWyd7JywgJ30nXTtcbiAgICB9XG5cbiAgICAvLyBNYWtlIGZ1bmN0aW9ucyBzYXkgdGhhdCB0aGV5IGFyZSBmdW5jdGlvbnNcbiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICB2YXIgbiA9IHZhbHVlLm5hbWUgPyAnOiAnICsgdmFsdWUubmFtZSA6ICcnO1xuICAgICAgYmFzZSA9IChpc1JlZ0V4cCh2YWx1ZSkpID8gJyAnICsgdmFsdWUgOiAnIFtGdW5jdGlvbicgKyBuICsgJ10nO1xuICAgIH0gZWxzZSB7XG4gICAgICBiYXNlID0gJyc7XG4gICAgfVxuXG4gICAgLy8gTWFrZSBkYXRlcyB3aXRoIHByb3BlcnRpZXMgZmlyc3Qgc2F5IHRoZSBkYXRlXG4gICAgaWYgKGlzRGF0ZSh2YWx1ZSkpIHtcbiAgICAgIGJhc2UgPSAnICcgKyB2YWx1ZS50b1VUQ1N0cmluZygpO1xuICAgIH1cblxuICAgIGlmIChrZXlzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuIGJyYWNlc1swXSArIGJhc2UgKyBicmFjZXNbMV07XG4gICAgfVxuXG4gICAgaWYgKHJlY3Vyc2VUaW1lcyA8IDApIHtcbiAgICAgIGlmIChpc1JlZ0V4cCh2YWx1ZSkpIHtcbiAgICAgICAgcmV0dXJuIHN0eWxpemUoJycgKyB2YWx1ZSwgJ3JlZ2V4cCcpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIHN0eWxpemUoJ1tPYmplY3RdJywgJ3NwZWNpYWwnKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBzZWVuLnB1c2godmFsdWUpO1xuXG4gICAgdmFyIG91dHB1dCA9IGtleXMubWFwKGZ1bmN0aW9uKGtleSkge1xuICAgICAgdmFyIG5hbWUsIHN0cjtcbiAgICAgIGlmICh2YWx1ZS5fX2xvb2t1cEdldHRlcl9fKSB7XG4gICAgICAgIGlmICh2YWx1ZS5fX2xvb2t1cEdldHRlcl9fKGtleSkpIHtcbiAgICAgICAgICBpZiAodmFsdWUuX19sb29rdXBTZXR0ZXJfXyhrZXkpKSB7XG4gICAgICAgICAgICBzdHIgPSBzdHlsaXplKCdbR2V0dGVyL1NldHRlcl0nLCAnc3BlY2lhbCcpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBzdHIgPSBzdHlsaXplKCdbR2V0dGVyXScsICdzcGVjaWFsJyk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGlmICh2YWx1ZS5fX2xvb2t1cFNldHRlcl9fKGtleSkpIHtcbiAgICAgICAgICAgIHN0ciA9IHN0eWxpemUoJ1tTZXR0ZXJdJywgJ3NwZWNpYWwnKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGlmICh2aXNpYmxlX2tleXMuaW5kZXhPZihrZXkpIDwgMCkge1xuICAgICAgICBuYW1lID0gJ1snICsga2V5ICsgJ10nO1xuICAgICAgfVxuICAgICAgaWYgKCFzdHIpIHtcbiAgICAgICAgaWYgKHNlZW4uaW5kZXhPZih2YWx1ZVtrZXldKSA8IDApIHtcbiAgICAgICAgICBpZiAocmVjdXJzZVRpbWVzID09PSBudWxsKSB7XG4gICAgICAgICAgICBzdHIgPSBmb3JtYXQodmFsdWVba2V5XSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHN0ciA9IGZvcm1hdCh2YWx1ZVtrZXldLCByZWN1cnNlVGltZXMgLSAxKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKHN0ci5pbmRleE9mKCdcXG4nKSA+IC0xKSB7XG4gICAgICAgICAgICBpZiAoaXNBcnJheSh2YWx1ZSkpIHtcbiAgICAgICAgICAgICAgc3RyID0gc3RyLnNwbGl0KCdcXG4nKS5tYXAoZnVuY3Rpb24obGluZSkge1xuICAgICAgICAgICAgICAgIHJldHVybiAnICAnICsgbGluZTtcbiAgICAgICAgICAgICAgfSkuam9pbignXFxuJykuc3Vic3RyKDIpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgc3RyID0gJ1xcbicgKyBzdHIuc3BsaXQoJ1xcbicpLm1hcChmdW5jdGlvbihsaW5lKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICcgICAnICsgbGluZTtcbiAgICAgICAgICAgICAgfSkuam9pbignXFxuJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHN0ciA9IHN0eWxpemUoJ1tDaXJjdWxhcl0nLCAnc3BlY2lhbCcpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBpZiAodHlwZW9mIG5hbWUgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgIGlmICh0eXBlID09PSAnQXJyYXknICYmIGtleS5tYXRjaCgvXlxcZCskLykpIHtcbiAgICAgICAgICByZXR1cm4gc3RyO1xuICAgICAgICB9XG4gICAgICAgIG5hbWUgPSBKU09OLnN0cmluZ2lmeSgnJyArIGtleSk7XG4gICAgICAgIGlmIChuYW1lLm1hdGNoKC9eXCIoW2EtekEtWl9dW2EtekEtWl8wLTldKilcIiQvKSkge1xuICAgICAgICAgIG5hbWUgPSBuYW1lLnN1YnN0cigxLCBuYW1lLmxlbmd0aCAtIDIpO1xuICAgICAgICAgIG5hbWUgPSBzdHlsaXplKG5hbWUsICduYW1lJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgbmFtZSA9IG5hbWUucmVwbGFjZSgvJy9nLCBcIlxcXFwnXCIpXG4gICAgICAgICAgICAgICAgICAgICAucmVwbGFjZSgvXFxcXFwiL2csICdcIicpXG4gICAgICAgICAgICAgICAgICAgICAucmVwbGFjZSgvKF5cInxcIiQpL2csIFwiJ1wiKTtcbiAgICAgICAgICBuYW1lID0gc3R5bGl6ZShuYW1lLCAnc3RyaW5nJyk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIG5hbWUgKyAnOiAnICsgc3RyO1xuICAgIH0pO1xuXG4gICAgc2Vlbi5wb3AoKTtcblxuICAgIHZhciBudW1MaW5lc0VzdCA9IDA7XG4gICAgdmFyIGxlbmd0aCA9IG91dHB1dC5yZWR1Y2UoZnVuY3Rpb24ocHJldiwgY3VyKSB7XG4gICAgICBudW1MaW5lc0VzdCsrO1xuICAgICAgaWYgKGN1ci5pbmRleE9mKCdcXG4nKSA+PSAwKSBudW1MaW5lc0VzdCsrO1xuICAgICAgcmV0dXJuIHByZXYgKyBjdXIubGVuZ3RoICsgMTtcbiAgICB9LCAwKTtcblxuICAgIGlmIChsZW5ndGggPiA1MCkge1xuICAgICAgb3V0cHV0ID0gYnJhY2VzWzBdICtcbiAgICAgICAgICAgICAgIChiYXNlID09PSAnJyA/ICcnIDogYmFzZSArICdcXG4gJykgK1xuICAgICAgICAgICAgICAgJyAnICtcbiAgICAgICAgICAgICAgIG91dHB1dC5qb2luKCcsXFxuICAnKSArXG4gICAgICAgICAgICAgICAnICcgK1xuICAgICAgICAgICAgICAgYnJhY2VzWzFdO1xuXG4gICAgfSBlbHNlIHtcbiAgICAgIG91dHB1dCA9IGJyYWNlc1swXSArIGJhc2UgKyAnICcgKyBvdXRwdXQuam9pbignLCAnKSArICcgJyArIGJyYWNlc1sxXTtcbiAgICB9XG5cbiAgICByZXR1cm4gb3V0cHV0O1xuICB9XG4gIHJldHVybiBmb3JtYXQob2JqLCAodHlwZW9mIGRlcHRoID09PSAndW5kZWZpbmVkJyA/IDIgOiBkZXB0aCkpO1xufTtcblxuXG5mdW5jdGlvbiBpc0FycmF5KGFyKSB7XG4gIHJldHVybiBhciBpbnN0YW5jZW9mIEFycmF5IHx8XG4gICAgICAgICBBcnJheS5pc0FycmF5KGFyKSB8fFxuICAgICAgICAgKGFyICYmIGFyICE9PSBPYmplY3QucHJvdG90eXBlICYmIGlzQXJyYXkoYXIuX19wcm90b19fKSk7XG59XG5cblxuZnVuY3Rpb24gaXNSZWdFeHAocmUpIHtcbiAgcmV0dXJuIHJlIGluc3RhbmNlb2YgUmVnRXhwIHx8XG4gICAgKHR5cGVvZiByZSA9PT0gJ29iamVjdCcgJiYgT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKHJlKSA9PT0gJ1tvYmplY3QgUmVnRXhwXScpO1xufVxuXG5cbmZ1bmN0aW9uIGlzRGF0ZShkKSB7XG4gIGlmIChkIGluc3RhbmNlb2YgRGF0ZSkgcmV0dXJuIHRydWU7XG4gIGlmICh0eXBlb2YgZCAhPT0gJ29iamVjdCcpIHJldHVybiBmYWxzZTtcbiAgdmFyIHByb3BlcnRpZXMgPSBEYXRlLnByb3RvdHlwZSAmJiBPYmplY3RfZ2V0T3duUHJvcGVydHlOYW1lcyhEYXRlLnByb3RvdHlwZSk7XG4gIHZhciBwcm90byA9IGQuX19wcm90b19fICYmIE9iamVjdF9nZXRPd25Qcm9wZXJ0eU5hbWVzKGQuX19wcm90b19fKTtcbiAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KHByb3RvKSA9PT0gSlNPTi5zdHJpbmdpZnkocHJvcGVydGllcyk7XG59XG5cbmZ1bmN0aW9uIHBhZChuKSB7XG4gIHJldHVybiBuIDwgMTAgPyAnMCcgKyBuLnRvU3RyaW5nKDEwKSA6IG4udG9TdHJpbmcoMTApO1xufVxuXG52YXIgbW9udGhzID0gWydKYW4nLCAnRmViJywgJ01hcicsICdBcHInLCAnTWF5JywgJ0p1bicsICdKdWwnLCAnQXVnJywgJ1NlcCcsXG4gICAgICAgICAgICAgICdPY3QnLCAnTm92JywgJ0RlYyddO1xuXG4vLyAyNiBGZWIgMTY6MTk6MzRcbmZ1bmN0aW9uIHRpbWVzdGFtcCgpIHtcbiAgdmFyIGQgPSBuZXcgRGF0ZSgpO1xuICB2YXIgdGltZSA9IFtwYWQoZC5nZXRIb3VycygpKSxcbiAgICAgICAgICAgICAgcGFkKGQuZ2V0TWludXRlcygpKSxcbiAgICAgICAgICAgICAgcGFkKGQuZ2V0U2Vjb25kcygpKV0uam9pbignOicpO1xuICByZXR1cm4gW2QuZ2V0RGF0ZSgpLCBtb250aHNbZC5nZXRNb250aCgpXSwgdGltZV0uam9pbignICcpO1xufVxuXG5leHBvcnRzLmxvZyA9IGZ1bmN0aW9uIChtc2cpIHt9O1xuXG5leHBvcnRzLnB1bXAgPSBudWxsO1xuXG52YXIgT2JqZWN0X2tleXMgPSBPYmplY3Qua2V5cyB8fCBmdW5jdGlvbiAob2JqKSB7XG4gICAgdmFyIHJlcyA9IFtdO1xuICAgIGZvciAodmFyIGtleSBpbiBvYmopIHJlcy5wdXNoKGtleSk7XG4gICAgcmV0dXJuIHJlcztcbn07XG5cbnZhciBPYmplY3RfZ2V0T3duUHJvcGVydHlOYW1lcyA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzIHx8IGZ1bmN0aW9uIChvYmopIHtcbiAgICB2YXIgcmVzID0gW107XG4gICAgZm9yICh2YXIga2V5IGluIG9iaikge1xuICAgICAgICBpZiAoT2JqZWN0Lmhhc093blByb3BlcnR5LmNhbGwob2JqLCBrZXkpKSByZXMucHVzaChrZXkpO1xuICAgIH1cbiAgICByZXR1cm4gcmVzO1xufTtcblxudmFyIE9iamVjdF9jcmVhdGUgPSBPYmplY3QuY3JlYXRlIHx8IGZ1bmN0aW9uIChwcm90b3R5cGUsIHByb3BlcnRpZXMpIHtcbiAgICAvLyBmcm9tIGVzNS1zaGltXG4gICAgdmFyIG9iamVjdDtcbiAgICBpZiAocHJvdG90eXBlID09PSBudWxsKSB7XG4gICAgICAgIG9iamVjdCA9IHsgJ19fcHJvdG9fXycgOiBudWxsIH07XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICBpZiAodHlwZW9mIHByb3RvdHlwZSAhPT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXG4gICAgICAgICAgICAgICAgJ3R5cGVvZiBwcm90b3R5cGVbJyArICh0eXBlb2YgcHJvdG90eXBlKSArICddICE9IFxcJ29iamVjdFxcJydcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIFR5cGUgPSBmdW5jdGlvbiAoKSB7fTtcbiAgICAgICAgVHlwZS5wcm90b3R5cGUgPSBwcm90b3R5cGU7XG4gICAgICAgIG9iamVjdCA9IG5ldyBUeXBlKCk7XG4gICAgICAgIG9iamVjdC5fX3Byb3RvX18gPSBwcm90b3R5cGU7XG4gICAgfVxuICAgIGlmICh0eXBlb2YgcHJvcGVydGllcyAhPT0gJ3VuZGVmaW5lZCcgJiYgT2JqZWN0LmRlZmluZVByb3BlcnRpZXMpIHtcbiAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnRpZXMob2JqZWN0LCBwcm9wZXJ0aWVzKTtcbiAgICB9XG4gICAgcmV0dXJuIG9iamVjdDtcbn07XG5cbmV4cG9ydHMuaW5oZXJpdHMgPSBmdW5jdGlvbihjdG9yLCBzdXBlckN0b3IpIHtcbiAgY3Rvci5zdXBlcl8gPSBzdXBlckN0b3I7XG4gIGN0b3IucHJvdG90eXBlID0gT2JqZWN0X2NyZWF0ZShzdXBlckN0b3IucHJvdG90eXBlLCB7XG4gICAgY29uc3RydWN0b3I6IHtcbiAgICAgIHZhbHVlOiBjdG9yLFxuICAgICAgZW51bWVyYWJsZTogZmFsc2UsXG4gICAgICB3cml0YWJsZTogdHJ1ZSxcbiAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZVxuICAgIH1cbiAgfSk7XG59O1xuXG52YXIgZm9ybWF0UmVnRXhwID0gLyVbc2RqJV0vZztcbmV4cG9ydHMuZm9ybWF0ID0gZnVuY3Rpb24oZikge1xuICBpZiAodHlwZW9mIGYgIT09ICdzdHJpbmcnKSB7XG4gICAgdmFyIG9iamVjdHMgPSBbXTtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkrKykge1xuICAgICAgb2JqZWN0cy5wdXNoKGV4cG9ydHMuaW5zcGVjdChhcmd1bWVudHNbaV0pKTtcbiAgICB9XG4gICAgcmV0dXJuIG9iamVjdHMuam9pbignICcpO1xuICB9XG5cbiAgdmFyIGkgPSAxO1xuICB2YXIgYXJncyA9IGFyZ3VtZW50cztcbiAgdmFyIGxlbiA9IGFyZ3MubGVuZ3RoO1xuICB2YXIgc3RyID0gU3RyaW5nKGYpLnJlcGxhY2UoZm9ybWF0UmVnRXhwLCBmdW5jdGlvbih4KSB7XG4gICAgaWYgKHggPT09ICclJScpIHJldHVybiAnJSc7XG4gICAgaWYgKGkgPj0gbGVuKSByZXR1cm4geDtcbiAgICBzd2l0Y2ggKHgpIHtcbiAgICAgIGNhc2UgJyVzJzogcmV0dXJuIFN0cmluZyhhcmdzW2krK10pO1xuICAgICAgY2FzZSAnJWQnOiByZXR1cm4gTnVtYmVyKGFyZ3NbaSsrXSk7XG4gICAgICBjYXNlICclaic6IHJldHVybiBKU09OLnN0cmluZ2lmeShhcmdzW2krK10pO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgcmV0dXJuIHg7XG4gICAgfVxuICB9KTtcbiAgZm9yKHZhciB4ID0gYXJnc1tpXTsgaSA8IGxlbjsgeCA9IGFyZ3NbKytpXSl7XG4gICAgaWYgKHggPT09IG51bGwgfHwgdHlwZW9mIHggIT09ICdvYmplY3QnKSB7XG4gICAgICBzdHIgKz0gJyAnICsgeDtcbiAgICB9IGVsc2Uge1xuICAgICAgc3RyICs9ICcgJyArIGV4cG9ydHMuaW5zcGVjdCh4KTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHN0cjtcbn07XG4iLCJcInVzZSBzdHJpY3RcIlxuXG52YXIgRXZlbnRFbWl0dGVyID0gcmVxdWlyZShcImV2ZW50c1wiKS5FdmVudEVtaXR0ZXJcbiAgLCB1dGlsICAgICAgICAgPSByZXF1aXJlKFwidXRpbFwiKVxuICAsIGRvbXJlYWR5ICAgICA9IHJlcXVpcmUoXCJkb21yZWFkeVwiKVxuICAsIHZrZXkgICAgICAgICA9IHJlcXVpcmUoXCJ2a2V5XCIpXG4gICwgaW52ZXJ0ICAgICAgID0gcmVxdWlyZShcImludmVydC1oYXNoXCIpXG4gICwgdW5pcSAgICAgICAgID0gcmVxdWlyZShcInVuaXFcIilcbiAgLCBsb3dlckJvdW5kICAgPSByZXF1aXJlKFwibG93ZXItYm91bmRcIilcbiAgLCBpb3RhICAgICAgICAgPSByZXF1aXJlKFwiaW90YS1hcnJheVwiKVxuICAsIG1pbiAgICAgICAgICA9IE1hdGgubWluXG5cbnJlcXVpcmUoXCIuL2xpYi9yYWYtcG9seWZpbGwuanNcIilcblxuLy9SZW1vdmUgYW5nbGUgYnJhY2VzIGFuZCBvdGhlciB1c2VsZXNzIGNyYXBcbnZhciBmaWx0ZXJlZF92a2V5ID0gKGZ1bmN0aW9uKCkge1xuICB2YXIgcmVzdWx0ID0gbmV3IEFycmF5KDI1NilcbiAgICAsIGksIGosIGtcbiAgZm9yKGk9MDsgaTwyNTY7ICsraSkge1xuICAgIHJlc3VsdFtpXSA9IFwiVU5LXCJcbiAgfVxuICBmb3IoaSBpbiB2a2V5KSB7XG4gICAgayA9IHZrZXlbaV1cbiAgICBpZihrLmNoYXJBdCgwKSA9PT0gJzwnICYmIGsuY2hhckF0KGsubGVuZ3RoLTEpID09PSAnPicpIHtcbiAgICAgIGsgPSBrLnN1YnN0cmluZygxLCBrLmxlbmd0aC0xKVxuICAgIH1cbiAgICBrID0gay5yZXBsYWNlKC9cXHMvZywgXCItXCIpXG4gICAgcmVzdWx0W3BhcnNlSW50KGkpXSA9IGtcbiAgfVxuICByZXR1cm4gcmVzdWx0XG59KSgpXG5cbi8vQ29tcHV0ZSBtaW5pbWFsIGNvbW1vbiBzZXQgb2Yga2V5Ym9hcmQgZnVuY3Rpb25zXG52YXIga2V5TmFtZXMgPSB1bmlxKE9iamVjdC5rZXlzKGludmVydChmaWx0ZXJlZF92a2V5KSkpXG5cbi8vVHJhbnNsYXRlcyBhIHZpcnR1YWwga2V5Y29kZSB0byBhIG5vcm1hbGl6ZWQga2V5Y29kZVxuZnVuY3Rpb24gdmlydHVhbEtleUNvZGUoa2V5KSB7XG4gIHZhciBpZHggPSBsb3dlckJvdW5kKGtleU5hbWVzLCBrZXkpXG4gIGlmKGlkeCA8IDAgfHwgaWR4ID49IGtleU5hbWVzLmxlbmd0aCkge1xuICAgIHJldHVybiAtMVxuICB9XG4gIHJldHVybiBpZHhcbn1cblxuLy9NYXBzIGEgcGh5c2ljYWwga2V5Y29kZSB0byBhIG5vcm1hbGl6ZWQga2V5Y29kZVxuZnVuY3Rpb24gcGh5c2ljYWxLZXlDb2RlKGtleSkge1xuICByZXR1cm4gdmlydHVhbEtleUNvZGUoZmlsdGVyZWRfdmtleVtrZXldKVxufVxuXG4vL0dhbWUgc2hlbGxcbmZ1bmN0aW9uIEdhbWVTaGVsbCgpIHtcbiAgRXZlbnRFbWl0dGVyLmNhbGwodGhpcylcbiAgdGhpcy5fY3VyS2V5U3RhdGUgID0gbmV3IEFycmF5KGtleU5hbWVzLmxlbmd0aClcbiAgdGhpcy5fcHJlc3NDb3VudCAgID0gbmV3IEFycmF5KGtleU5hbWVzLmxlbmd0aClcbiAgdGhpcy5fcmVsZWFzZUNvdW50ID0gbmV3IEFycmF5KGtleU5hbWVzLmxlbmd0aClcbiAgXG4gIHRoaXMuX3RpY2tJbnRlcnZhbCA9IG51bGxcbiAgdGhpcy5fdGlja1JhdGUgPSAwXG4gIHRoaXMuX2xhc3RUaWNrID0gRGF0ZS5ub3coKVxuICB0aGlzLl9mcmFtZVRpbWUgPSAwLjBcbiAgdGhpcy5fcGF1c2VkID0gZmFsc2VcbiAgXG4gIHRoaXMuX3JlbmRlciA9IHJlbmRlci5iaW5kKHVuZGVmaW5lZCwgdGhpcylcbiAgXG4gIGZvcih2YXIgaT0wOyBpPGtleU5hbWVzLmxlbmd0aDsgKytpKSB7XG4gICAgdGhpcy5fY3VyS2V5U3RhdGVbaV0gPSBmYWxzZVxuICAgIHRoaXMuX3ByZXNzQ291bnRbaV0gPSB0aGlzLl9yZWxlYXNlQ291bnRbaV0gPSAwXG4gIH1cbiAgXG4gIC8vUHVibGljIG1lbWJlcnNcbiAgdGhpcy5lbGVtZW50ID0gbnVsbFxuICB0aGlzLmJpbmRpbmdzID0ge31cbiAgdGhpcy5mcmFtZVNraXAgPSAxMDAuMFxuICB0aGlzLnRpY2tDb3VudCA9IDBcbiAgdGhpcy5mcmFtZUNvdW50ID0gMFxuICB0aGlzLnN0YXJ0VGltZSA9IERhdGUubm93KClcbiAgdGhpcy50aWNrVGltZSA9IHRoaXMuX3RpY2tSYXRlXG4gIHRoaXMuZnJhbWVUaW1lID0gMTAuMFxuICBcbiAgLy9Nb3VzZSBzdGF0ZVxuICB0aGlzLm1vdXNlWCA9IDBcbiAgdGhpcy5tb3VzZVkgPSAwXG4gIHRoaXMucHJldk1vdXNlWCA9IDBcbiAgdGhpcy5wcmV2TW91c2VZID0gMFxufVxuXG51dGlsLmluaGVyaXRzKEdhbWVTaGVsbCwgRXZlbnRFbWl0dGVyKVxuXG4vL0JpbmQga2V5bmFtZXNcbkdhbWVTaGVsbC5wcm90b3R5cGUua2V5TmFtZXMgPSBrZXlOYW1lc1xuXG4vL0JpbmRzIGEgdmlydHVhbCBrZXlib2FyZCBldmVudCB0byBhIHBoeXNpY2FsIGtleVxuR2FtZVNoZWxsLnByb3RvdHlwZS5iaW5kID0gZnVuY3Rpb24odmlydHVhbF9rZXkpIHtcbiAgLy9Mb29rIHVwIHByZXZpb3VzIGtleSBiaW5kaW5nc1xuICB2YXIgYXJyXG4gIGlmKHZpcnR1YWxfa2V5IGluIHRoaXMuYmluZGluZ3MpIHtcbiAgICBhcnIgPSB0aGlzLmJpbmRpbmdzW3ZpcnR1YWxfa2V5XVxuICB9IGVsc2Uge1xuICAgIGFyciA9IFtdXG4gIH1cbiAgLy9BZGQga2V5cyB0byBsaXN0XG4gIHZhciBwaHlzaWNhbF9rZXlcbiAgZm9yKHZhciBpPTEsIG49YXJndW1lbnRzLmxlbmd0aDsgaTxuOyArK2kpIHtcbiAgICBwaHlzaWNhbF9rZXkgPSBhcmd1bWVudHNbaV1cbiAgICBpZih2aXJ0dWFsS2V5Q29kZShwaHlzaWNhbF9rZXkpID49IDApIHtcbiAgICAgIGFyci5wdXNoKHBoeXNpY2FsX2tleSlcbiAgICB9XG4gIH1cbiAgLy9SZW1vdmUgYW55IGR1cGxpY2F0ZSBrZXlzXG4gIGFyciA9IHVuaXEoYXJyKVxuICBpZihhcnIubGVuZ3RoID4gMCkge1xuICAgIHRoaXMuYmluZGluZ3NbdmlydHVhbF9rZXldID0gYXJyXG4gIH1cbn1cblxuLy9VbmJpbmRzIGEgdmlydHVhbCBrZXlib2FyZCBldmVudFxuR2FtZVNoZWxsLnByb3RvdHlwZS51bmJpbmQgPSBmdW5jdGlvbih2aXJ0dWFsX2tleSkge1xuICBpZih2aXJ0dWFsX2tleSBpbiB0aGlzLmJpbmRpbmdzKSB7XG4gICAgZGVsZXRlIHRoaXMuYmluZGluZ3NbdmlydHVhbF9rZXldXG4gIH1cbn1cblxuLy9DaGVja3MgaWYgYSBrZXkgaXMgc2V0IGluIGEgZ2l2ZW4gc3RhdGVcbmZ1bmN0aW9uIGxvb2t1cEtleShzdGF0ZSwgYmluZGluZ3MsIGtleSkge1xuICBpZihrZXkgaW4gYmluZGluZ3MpIHtcbiAgICB2YXIgYXJyID0gYmluZGluZ3Nba2V5XVxuICAgIGZvcih2YXIgaT0wLCBuPWFyci5sZW5ndGg7IGk8bjsgKytpKSB7XG4gICAgICBpZihzdGF0ZVt2aXJ0dWFsS2V5Q29kZShhcnJbaV0pXSkge1xuICAgICAgICByZXR1cm4gdHJ1ZVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gZmFsc2VcbiAgfVxuICB2YXIga2MgPSB2aXJ0dWFsS2V5Q29kZShrZXkpXG4gIGlmKGtjID49IDApIHtcbiAgICByZXR1cm4gc3RhdGVba2NdXG4gIH1cbiAgcmV0dXJuIGZhbHNlXG59XG5cbi8vQ2hlY2tzIGlmIGEga2V5IGlzIHNldCBpbiBhIGdpdmVuIHN0YXRlXG5mdW5jdGlvbiBsb29rdXBDb3VudChzdGF0ZSwgYmluZGluZ3MsIGtleSkge1xuICBpZihrZXkgaW4gYmluZGluZ3MpIHtcbiAgICB2YXIgYXJyID0gYmluZGluZ3Nba2V5XSwgciA9IDBcbiAgICBmb3IodmFyIGk9MCwgbj1hcnIubGVuZ3RoOyBpPG47ICsraSkge1xuICAgICAgciArPSBzdGF0ZVt2aXJ0dWFsS2V5Q29kZShhcnJbaV0pXVxuICAgIH1cbiAgICByZXR1cm4gclxuICB9XG4gIHZhciBrYyA9IHZpcnR1YWxLZXlDb2RlKGtleSlcbiAgaWYoa2MgPj0gMCkge1xuICAgIHJldHVybiBzdGF0ZVtrY11cbiAgfVxuICByZXR1cm4gMFxufVxuXG4vL0NoZWNrcyBpZiBhIGtleSAoZWl0aGVyIHBoeXNpY2FsIG9yIHZpcnR1YWwpIGlzIGN1cnJlbnRseSBoZWxkIGRvd25cbkdhbWVTaGVsbC5wcm90b3R5cGUuZG93biA9IGZ1bmN0aW9uKGtleSkge1xuICByZXR1cm4gbG9va3VwS2V5KHRoaXMuX2N1cktleVN0YXRlLCB0aGlzLmJpbmRpbmdzLCBrZXkpXG59XG5cbi8vQ2hlY2tzIGlmIGEga2V5IHdhcyBldmVyIGRvd25cbkdhbWVTaGVsbC5wcm90b3R5cGUud2FzRG93biA9IGZ1bmN0aW9uKGtleSkge1xuICByZXR1cm4gdGhpcy5kb3duKGtleSkgfHwgdGhpcy5wcmVzcyhrZXkpXG59XG5cbi8vT3Bwb3NpdGUgb2YgZG93blxuR2FtZVNoZWxsLnByb3RvdHlwZS51cCA9IGZ1bmN0aW9uKGtleSkge1xuICByZXR1cm4gIXRoaXMuZG93bihrZXkpXG59XG5cbkdhbWVTaGVsbC5wcm90b3R5cGUud2FzVXAgPSBmdW5jdGlvbihrZXkpIHtcbiAgcmV0dXJuIHRoaXMudXAoa2V5KSB8fCB0aGlzLnJlbGVhc2Uoa2V5KVxufVxuXG4vL1JldHVybnMgdGhlIG51bWJlciBvZiB0aW1lcyBhIGtleSB3YXMgcHJlc3NlZCBzaW5jZSBsYXN0IHRpY2tcbkdhbWVTaGVsbC5wcm90b3R5cGUucHJlc3MgPSBmdW5jdGlvbihrZXkpIHtcbiAgcmV0dXJuIGxvb2t1cENvdW50KHRoaXMuX3ByZXNzQ291bnQsIHRoaXMuYmluZGluZ3MsIGtleSlcbn1cblxuLy9SZXR1cm5zIHRoZSBudW1iZXIgb2YgdGltZXMgYSBrZXkgd2FzIHJlbGVhc2VkIHNpbmNlIGxhc3QgdGlja1xuR2FtZVNoZWxsLnByb3RvdHlwZS5yZWxlYXNlID0gZnVuY3Rpb24oa2V5KSB7XG4gIHJldHVybiBsb29rdXBDb3VudCh0aGlzLl9yZWxlYXNlQ291bnQsIHRoaXMuYmluZGluZ3MsIGtleSlcbn1cblxuLy9QYXVzZS91bnBhdXNlIHRoZSBnYW1lIGxvb3Bcbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShHYW1lU2hlbGwucHJvdG90eXBlLCBcInBhdXNlZFwiLCB7XG4gIGdldDogZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIHRoaXMuX3BhdXNlZFxuICB9LFxuICBzZXQ6IGZ1bmN0aW9uKHApIHtcbiAgICBpZihwKSB7XG4gICAgICBpZighdGhpcy5fcGF1c2VkKSB7XG4gICAgICAgIHRoaXMuX3BhdXNlZCA9IHRydWVcbiAgICAgICAgdGhpcy5fZnJhbWVUaW1lID0gbWluKDEuMCwgKERhdGUubm93KCkgLSB0aGlzLl9sYXN0VGljaykgLyB0aGlzLl90aWNrUmF0ZSlcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYodGhpcy5fcGF1c2VkKSB7XG4gICAgICB0aGlzLl9wYXVzZWQgPSBmYWxzZVxuICAgICAgdGhpcy5fbGFzdFRpY2sgPSBEYXRlLm5vdygpIC0gTWF0aC5mbG9vcih0aGlzLl9mcmFtZVRpbWUgKiB0aGlzLl90aWNrUmF0ZSlcbiAgICB9XG4gIH1cbn0pXG5cbi8vU2V0IGtleSBzdGF0ZVxuZnVuY3Rpb24gc2V0S2V5U3RhdGUoc2hlbGwsIGtleSwgc3RhdGUpIHtcbiAgdmFyIHBzID0gc2hlbGwuX2N1cktleVN0YXRlW2tleV1cbiAgaWYocHMgIT09IHN0YXRlKSB7XG4gICAgaWYoc3RhdGUpIHtcbiAgICAgIHNoZWxsLl9wcmVzc0NvdW50W2tleV0rK1xuICAgIH0gZWxzZSB7XG4gICAgICBzaGVsbC5fcmVsZWFzZUNvdW50W2tleV0rK1xuICAgIH1cbiAgICBzaGVsbC5fY3VyS2V5U3RhdGVba2V5XSA9IHN0YXRlXG4gIH1cbn1cblxuLy9UaWNrcyB0aGUgZ2FtZSBzdGF0ZSBvbmUgdXBkYXRlXG5mdW5jdGlvbiB0aWNrKHNoZWxsKSB7XG4gIHZhciBza2lwID0gRGF0ZS5ub3coKSArIHNoZWxsLmZyYW1lU2tpcFxuICAgICwgcENvdW50ID0gc2hlbGwuX3ByZXNzQ291bnRcbiAgICAsIHJDb3VudCA9IHNoZWxsLl9yZWxlYXNlQ291bnRcbiAgICAsIGksIHMsIHRcbiAgICAsIHRyID0gc2hlbGwuX3RpY2tSYXRlXG4gICAgLCBuID0ga2V5TmFtZXMubGVuZ3RoXG4gIHdoaWxlKCFzaGVsbC5fcGF1c2VkICYmXG4gICAgICAgIERhdGUubm93KCkgPj0gc2hlbGwuX2xhc3RUaWNrICsgdHIpIHtcbiAgICAvL1NraXAgYSBmcmFtZSBpZiB3ZSBhcmUgb3ZlciBidWRnZXRcbiAgICBpZihEYXRlLm5vdygpID4gc2tpcCkge1xuICAgICAgc2hlbGwuX2xhc3RUaWNrID0gRGF0ZS5ub3coKSArIHRyXG4gICAgICByZXR1cm5cbiAgICB9XG4gICAgXG4gICAgLy9VcGRhdGUgY291bnRlcnMgYW5kIHRpbWVcbiAgICArK3NoZWxsLnRpY2tDb3VudFxuICAgIHNoZWxsLl9sYXN0VGljayArPSB0clxuICAgIFxuICAgIC8vVGljayB0aGUgZ2FtZVxuICAgIHMgPSBEYXRlLm5vdygpXG4gICAgc2hlbGwuZW1pdChcInRpY2tcIilcbiAgICB0ID0gRGF0ZS5ub3coKVxuICAgIHNoZWxsLnRpY2tUaW1lID0gc2hlbGwudGlja1RpbWUgKiAwLjMgKyAodCAtIHMpICogMC43XG4gICAgXG4gICAgLy9TaGlmdCBpbnB1dCBzdGF0ZVxuICAgIGZvcihpPTA7IGk8bjsgKytpKSB7XG4gICAgICBwQ291bnRbaV0gPSByQ291bnRbaV0gPSAwXG4gICAgfVxuICAgIHNoZWxsLnByZXZNb3VzZVggPSBzaGVsbC5tb3VzZVhcbiAgICBzaGVsbC5wcmV2TW91c2VZID0gc2hlbGwubW91c2VZXG4gIH1cbn1cblxuLy9SZW5kZXIgc3R1ZmZcbmZ1bmN0aW9uIHJlbmRlcihzaGVsbCkge1xuICAvL1RpY2sgdGhlIHNoZWxsXG4gIHRpY2soc2hlbGwpXG4gIFxuICAvL0NvbXB1dGUgZnJhbWUgdGltZVxuICB2YXIgZHRcbiAgaWYoc2hlbGwuX3BhdXNlZCkge1xuICAgIGR0ID0gc2hlbGwuX2ZyYW1lVGltZVxuICB9IGVsc2Uge1xuICAgIGR0ID0gbWluKDEuMCwgKERhdGUubm93KCkgLSBzaGVsbC5fbGFzdFRpY2spIC8gc2hlbGwuX3RpY2tSYXRlKVxuICB9XG4gIFxuICAvL0RyYXcgYSBmcmFtZVxuICArK3NoZWxsLmZyYW1lQ291bnRcbiAgdmFyIHMgPSBEYXRlLm5vdygpXG4gIHNoZWxsLmVtaXQoXCJyZW5kZXJcIiwgZHQpXG4gIHZhciB0ID0gRGF0ZS5ub3coKVxuICBzaGVsbC5mcmFtZVRpbWUgPSBzaGVsbC5mcmFtZVRpbWUgKiAwLjMgKyAodCAtIHMpICogMC43XG4gIFxuICAvL1JlcXVlc3QgbmV4dCBmcmFtZVxuICByZXF1ZXN0QW5pbWF0aW9uRnJhbWUoc2hlbGwuX3JlbmRlcilcbn1cblxuLy9TZXQga2V5IHVwXG5mdW5jdGlvbiBoYW5kbGVLZXlVcChzaGVsbCwgZXYpIHtcbiAgdmFyIGtjID0gcGh5c2ljYWxLZXlDb2RlKGV2LmtleUNvZGUgfHwgZXYud2hpY2ggfHwgZXYuY2hhckNvZGUpXG4gIGlmKGtjID49IDApIHtcbiAgICBzZXRLZXlTdGF0ZShzaGVsbCwga2MsIGZhbHNlKVxuICB9XG59XG5cbi8vU2V0IGtleSBkb3duXG5mdW5jdGlvbiBoYW5kbGVLZXlEb3duKHNoZWxsLCBldikge1xuICB2YXIga2MgPSBwaHlzaWNhbEtleUNvZGUoZXYua2V5Q29kZSB8fCBldi5jaGFyIHx8IGV2LndoaWNoIHx8IGV2LmNoYXJDb2RlKVxuICBpZihrYyA+PSAwKSB7XG4gICAgc2V0S2V5U3RhdGUoc2hlbGwsIGtjLCB0cnVlKVxuICB9XG59XG5cbnZhciBtb3VzZUNvZGVzID0gaW90YSg1KS5tYXAoZnVuY3Rpb24obikge1xuICByZXR1cm4gdmlydHVhbEtleUNvZGUoXCJtb3VzZS1cIiArIChuKzEpKVxufSlcblxuZnVuY3Rpb24gc2V0TW91c2VCdXR0b25zKHNoZWxsLCBidXR0b25zKSB7XG4gIGZvcih2YXIgaT0wOyBpPDU7ICsraSkge1xuICAgIHNldEtleVN0YXRlKHNoZWxsLCBtb3VzZUNvZGVzW2ldLCAhIShidXR0b25zICYgKDE8PGkpKSlcbiAgfVxufVxuXG5mdW5jdGlvbiBoYW5kbGVNb3VzZU1vdmUoc2hlbGwsIGV2KSB7XG4gIGlmKGV2LndoaWNoICE9PSB1bmRlZmluZWQpIHtcbiAgICBzZXRNb3VzZUJ1dHRvbnMoc2hlbGwsIGV2LndoaWNoKVxuICB9XG4gIGlmKGV2LmJ1dHRvbnMgIT09IHVuZGVmaW5lZCkge1xuICAgIHNldE1vdXNlQnV0dG9ucyhzaGVsbCwgZXYuYnV0dG9ucylcbiAgfVxuICBzaGVsbC5tb3VzZVggPSBldi5jbGllbnRYXG4gIHNoZWxsLm1vdXNlWSA9IGV2LmNsaWVudFlcbn1cblxuZnVuY3Rpb24gaGFuZGxlTW91c2VEb3duKHNoZWxsLCBldikge1xuICBoYW5kbGVNb3VzZU1vdmUoc2hlbGwsIGV2KVxuICBzZXRLZXlTdGF0ZShzaGVsbCwgbW91c2VDb2Rlc1tldi5idXR0b25dLCB0cnVlKVxufVxuXG5mdW5jdGlvbiBoYW5kbGVNb3VzZVVwKHNoZWxsLCBldikge1xuICBoYW5kbGVNb3VzZU1vdmUoc2hlbGwsIGV2KVxuICBzZXRLZXlTdGF0ZShzaGVsbCwgbW91c2VDb2Rlc1tldi5idXR0b25dLCBmYWxzZSlcbn1cblxuZnVuY3Rpb24gaGFuZGxlTW91c2VFbnRlcihzaGVsbCwgZXYpIHtcbiAgaGFuZGxlTW91c2VNb3ZlKHNoZWxsLCBldilcbiAgc2hlbGwucHJldk1vdXNlWCA9IHNoZWxsLm1vdXNlWCA9IGV2LmNsaWVudFhcbiAgc2hlbGwucHJldk1vdXNlWSA9IHNoZWxsLm1vdXNlWSA9IGV2LmNsaWVudFlcbn1cblxuZnVuY3Rpb24gaGFuZGxlTW91c2VMZWF2ZShzaGVsbCwgZXYpIHtcbiAgZm9yKHZhciBpPTA7IGk8NTsgKytpKSB7XG4gICAgc2V0S2V5U3RhdGUoc2hlbGwsIG1vdXNlQ29kZXNbaV0sIGZhbHNlKVxuICB9XG59XG5cbmZ1bmN0aW9uIGhhbmRsZUJsdXIoc2hlbGwsIGV2KSB7XG4gIHZhciBuID0ga2V5TmFtZXMubGVuZ3RoXG4gICAgLCBjID0gc2hlbGwuX2N1cktleVN0YXRlXG4gICAgLCBpXG4gIGZvcihpPTA7IGk8bjsgKytpKSB7XG4gICAgY1tpXSA9IGZhbHNlXG4gIH1cbn1cblxuZnVuY3Rpb24gbWFrZURlZmF1bHRDb250YWluZXIoKSB7XG4gIHZhciBjb250YWluZXIgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KFwiZGl2XCIpXG4gIGNvbnRhaW5lci5zdHlsZS5wb3NpdGlvbiA9IFwiYWJzb2x1dGVcIlxuICBjb250YWluZXIuc3R5bGUubGVmdCA9IFwiMHB4XCJcbiAgY29udGFpbmVyLnN0eWxlLnJpZ2h0ID0gXCIwcHhcIlxuICBjb250YWluZXIuc3R5bGUudG9wID0gXCIwcHhcIlxuICBjb250YWluZXIuc3R5bGUuYm90dG9tID0gXCIwcHhcIlxuICBkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKGNvbnRhaW5lcilcbiAgcmV0dXJuIGNvbnRhaW5lclxufVxuXG5mdW5jdGlvbiBjcmVhdGVTaGVsbChvcHRpb25zKSB7XG4gIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9XG4gIFxuICAvL0NyZWF0ZSBpbml0aWFsIHNoZWxsXG4gIHZhciBzaGVsbCA9IG5ldyBHYW1lU2hlbGwoKVxuICBzaGVsbC5fdGlja1JhdGUgPSBvcHRpb25zLnRpY2tSYXRlIHx8IDMwXG4gIHNoZWxsLmZyYW1lU2tpcCA9IG9wdGlvbnMuZnJhbWVTa2lwIHx8IChzaGVsbC5fdGlja1JhdGUrNSkgKiA1XG4gIFxuICAvL1NldCBiaW5kaW5nc1xuICBpZihvcHRpb25zLmJpbmRpbmdzKSB7XG4gICAgc2hlbGwuYmluZGluZ3MgPSBiaW5kaW5nc1xuICB9XG4gIFxuICAvL1dhaXQgZm9yIGRvbSB0byBpbnRpYWlsaXplXG4gIHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7IGRvbXJlYWR5KGZ1bmN0aW9uKCkge1xuICAgIFxuICAgIC8vUmV0cmlldmUgZWxlbWVudFxuICAgIHZhciBlbGVtZW50ID0gb3B0aW9ucy5lbGVtZW50XG4gICAgaWYodHlwZW9mIGVsZW1lbnQgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgIHZhciBlID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoZWxlbWVudClcbiAgICAgIGlmKCFlKSB7XG4gICAgICAgIGUgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKGVsZW1lbnQpXG4gICAgICB9XG4gICAgICBpZighZSkge1xuICAgICAgICBlID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5Q2xhc3MoZWxlbWVudClbMF1cbiAgICAgIH1cbiAgICAgIGlmKCFlKSB7XG4gICAgICAgIGUgPSBtYWtlRGVmYXVsdENvbnRhaW5lcigpXG4gICAgICB9XG4gICAgICBzaGVsbC5lbGVtZW50ID0gZVxuICAgIH0gZWxzZSBpZih0eXBlb2YgZWxlbWVudCA9PT0gXCJvYmplY3RcIiAmJiAhIWVsZW1lbnQpIHtcbiAgICAgIHNoZWxsLmVsZW1lbnQgPSBlbGVtZW50XG4gICAgfSBlbHNlIGlmKHR5cGVvZiBlbGVtZW50ID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgIHNoZWxsLmVsZW1lbnQgPSBlbGVtZW50KClcbiAgICB9IGVsc2Uge1xuICAgICAgc2hlbGwuZWxlbWVudCA9IG1ha2VEZWZhdWx0Q29udGFpbmVyKClcbiAgICB9XG4gICAgXG4gICAgLy9EaXNhYmxlIHVzZXItc2VsZWN0XG4gICAgaWYoc2hlbGwuZWxlbWVudC5zdHlsZSkge1xuICAgICAgc2hlbGwuZWxlbWVudC5zdHlsZVtcIi13ZWJraXQtdG91Y2gtY2FsbG91dFwiXSA9IFwibm9uZVwiXG4gICAgICBzaGVsbC5lbGVtZW50LnN0eWxlW1wiLXdlYmtpdC11c2VyLXNlbGVjdFwiXSA9IFwibm9uZVwiXG4gICAgICBzaGVsbC5lbGVtZW50LnN0eWxlW1wiLWtodG1sLXVzZXItc2VsZWN0XCJdID0gXCJub25lXCJcbiAgICAgIHNoZWxsLmVsZW1lbnQuc3R5bGVbXCItbW96LXVzZXItc2VsZWN0XCJdID0gXCJub25lXCJcbiAgICAgIHNoZWxsLmVsZW1lbnQuc3R5bGVbXCItbXMtdXNlci1zZWxlY3RcIl0gPSBcIm5vbmVcIlxuICAgICAgc2hlbGwuZWxlbWVudC5zdHlsZVtcInVzZXItc2VsZWN0XCJdID0gXCJub25lXCJcbiAgICB9XG4gICAgXG4gICAgLy9Ib29rIGlucHV0IGxpc3RlbmVyc1xuICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKFwia2V5ZG93blwiLCBoYW5kbGVLZXlEb3duLmJpbmQodW5kZWZpbmVkLCBzaGVsbCksIHRydWUpXG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoXCJrZXl1cFwiLCBoYW5kbGVLZXlVcC5iaW5kKHVuZGVmaW5lZCwgc2hlbGwpLCB0cnVlKVxuICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKFwibW91c2Vkb3duXCIsIGhhbmRsZU1vdXNlRG93bi5iaW5kKHVuZGVmaW5lZCwgc2hlbGwpLCB0cnVlKVxuICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKFwibW91c2V1cFwiLCBoYW5kbGVNb3VzZVVwLmJpbmQodW5kZWZpbmVkLCBzaGVsbCksIHRydWUpXG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoXCJtb3VzZW1vdmVcIiwgaGFuZGxlTW91c2VNb3ZlLmJpbmQodW5kZWZpbmVkLCBzaGVsbCksIHRydWUpXG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoXCJtb3VzZWxlYXZlXCIsIGhhbmRsZU1vdXNlTGVhdmUuYmluZCh1bmRlZmluZWQsIHNoZWxsKSwgdHJ1ZSlcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihcIm1vdXNlZW50ZXJcIiwgaGFuZGxlTW91c2VFbnRlci5iaW5kKHVuZGVmaW5lZCwgc2hlbGwpLCB0cnVlKVxuICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKFwiYmx1clwiLCBoYW5kbGVCbHVyLmJpbmQodW5kZWZpbmVkLCBzaGVsbCksIHRydWUpXG4gICAgXG4gICAgLy9Jbml0aWFsaXplIHRpY2sgY291bnRlclxuICAgIHNoZWxsLl9sYXN0VGljayA9IERhdGUubm93KClcbiAgICBzaGVsbC5fcGF1c2VkID0gZmFsc2VcbiAgICBzaGVsbC5zdGFydFRpbWUgPSBEYXRlLm5vdygpXG4gICAgXG4gICAgLy9TZXQgdXAgYSB0aWNrIGludGVydmFsXG4gICAgc2hlbGwuX3RpY2tJbnRlcnZhbCA9IHNldEludGVydmFsKHRpY2ssIHNoZWxsLl90aWNrUmF0ZSwgc2hlbGwpXG4gICAgXG4gICAgLy9DcmVhdGUgYW4gYW5pbWF0aW9uIGZyYW1lIGhhbmRsZXJcbiAgICByZXF1ZXN0QW5pbWF0aW9uRnJhbWUoc2hlbGwuX3JlbmRlcilcbiAgICBcbiAgICAvL0VtaXQgaW5pdGlhbGl6ZSBldmVudFxuICAgIHNoZWxsLmVtaXQoXCJpbml0XCIpXG4gIH0pfSwgMClcbiAgXG4gIHJldHVybiBzaGVsbFxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGNyZWF0ZVNoZWxsIiwiLyohXG4gICogZG9tcmVhZHkgKGMpIER1c3RpbiBEaWF6IDIwMTIgLSBMaWNlbnNlIE1JVFxuICAqL1xuIWZ1bmN0aW9uIChuYW1lLCBkZWZpbml0aW9uKSB7XG4gIGlmICh0eXBlb2YgbW9kdWxlICE9ICd1bmRlZmluZWQnKSBtb2R1bGUuZXhwb3J0cyA9IGRlZmluaXRpb24oKVxuICBlbHNlIGlmICh0eXBlb2YgZGVmaW5lID09ICdmdW5jdGlvbicgJiYgdHlwZW9mIGRlZmluZS5hbWQgPT0gJ29iamVjdCcpIGRlZmluZShkZWZpbml0aW9uKVxuICBlbHNlIHRoaXNbbmFtZV0gPSBkZWZpbml0aW9uKClcbn0oJ2RvbXJlYWR5JywgZnVuY3Rpb24gKHJlYWR5KSB7XG5cbiAgdmFyIGZucyA9IFtdLCBmbiwgZiA9IGZhbHNlXG4gICAgLCBkb2MgPSBkb2N1bWVudFxuICAgICwgdGVzdEVsID0gZG9jLmRvY3VtZW50RWxlbWVudFxuICAgICwgaGFjayA9IHRlc3RFbC5kb1Njcm9sbFxuICAgICwgZG9tQ29udGVudExvYWRlZCA9ICdET01Db250ZW50TG9hZGVkJ1xuICAgICwgYWRkRXZlbnRMaXN0ZW5lciA9ICdhZGRFdmVudExpc3RlbmVyJ1xuICAgICwgb25yZWFkeXN0YXRlY2hhbmdlID0gJ29ucmVhZHlzdGF0ZWNoYW5nZSdcbiAgICAsIHJlYWR5U3RhdGUgPSAncmVhZHlTdGF0ZSdcbiAgICAsIGxvYWRlZCA9IC9ebG9hZGV8Yy8udGVzdChkb2NbcmVhZHlTdGF0ZV0pXG5cbiAgZnVuY3Rpb24gZmx1c2goZikge1xuICAgIGxvYWRlZCA9IDFcbiAgICB3aGlsZSAoZiA9IGZucy5zaGlmdCgpKSBmKClcbiAgfVxuXG4gIGRvY1thZGRFdmVudExpc3RlbmVyXSAmJiBkb2NbYWRkRXZlbnRMaXN0ZW5lcl0oZG9tQ29udGVudExvYWRlZCwgZm4gPSBmdW5jdGlvbiAoKSB7XG4gICAgZG9jLnJlbW92ZUV2ZW50TGlzdGVuZXIoZG9tQ29udGVudExvYWRlZCwgZm4sIGYpXG4gICAgZmx1c2goKVxuICB9LCBmKVxuXG5cbiAgaGFjayAmJiBkb2MuYXR0YWNoRXZlbnQob25yZWFkeXN0YXRlY2hhbmdlLCBmbiA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAoL15jLy50ZXN0KGRvY1tyZWFkeVN0YXRlXSkpIHtcbiAgICAgIGRvYy5kZXRhY2hFdmVudChvbnJlYWR5c3RhdGVjaGFuZ2UsIGZuKVxuICAgICAgZmx1c2goKVxuICAgIH1cbiAgfSlcblxuICByZXR1cm4gKHJlYWR5ID0gaGFjayA/XG4gICAgZnVuY3Rpb24gKGZuKSB7XG4gICAgICBzZWxmICE9IHRvcCA/XG4gICAgICAgIGxvYWRlZCA/IGZuKCkgOiBmbnMucHVzaChmbikgOlxuICAgICAgICBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHRlc3RFbC5kb1Njcm9sbCgnbGVmdCcpXG4gICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgcmV0dXJuIHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7IHJlYWR5KGZuKSB9LCA1MClcbiAgICAgICAgICB9XG4gICAgICAgICAgZm4oKVxuICAgICAgICB9KClcbiAgICB9IDpcbiAgICBmdW5jdGlvbiAoZm4pIHtcbiAgICAgIGxvYWRlZCA/IGZuKCkgOiBmbnMucHVzaChmbilcbiAgICB9KVxufSkiLCIoZnVuY3Rpb24oKXt2YXIgdWEgPSB0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJyA/IHdpbmRvdy5uYXZpZ2F0b3IudXNlckFnZW50IDogJydcbiAgLCBpc09TWCA9IC9PUyBYLy50ZXN0KHVhKVxuICAsIGlzT3BlcmEgPSAvT3BlcmEvLnRlc3QodWEpXG4gICwgbWF5YmVGaXJlZm94ID0gIS9saWtlIEdlY2tvLy50ZXN0KHVhKSAmJiAhaXNPcGVyYVxuXG52YXIgaSwgb3V0cHV0ID0gbW9kdWxlLmV4cG9ydHMgPSB7XG4gIDA6ICBpc09TWCA/ICc8bWVudT4nIDogJzxVTks+J1xuLCAxOiAgJzxtb3VzZSAxPidcbiwgMjogICc8bW91c2UgMj4nXG4sIDM6ICAnPGJyZWFrPidcbiwgNDogICc8bW91c2UgMz4nXG4sIDU6ICAnPG1vdXNlIDQ+J1xuLCA2OiAgJzxtb3VzZSA1PidcbiwgODogICc8YmFja3NwYWNlPidcbiwgOTogICc8dGFiPidcbiwgMTI6ICc8Y2xlYXI+J1xuLCAxMzogJzxlbnRlcj4nXG4sIDE2OiAnPHNoaWZ0PidcbiwgMTc6ICc8Y29udHJvbD4nXG4sIDE4OiAnPGFsdD4nXG4sIDE5OiAnPHBhdXNlPidcbiwgMjA6ICc8Y2Fwcy1sb2NrPidcbiwgMjE6ICc8aW1lLWhhbmd1bD4nXG4sIDIzOiAnPGltZS1qdW5qYT4nXG4sIDI0OiAnPGltZS1maW5hbD4nXG4sIDI1OiAnPGltZS1rYW5qaT4nXG4sIDI3OiAnPGVzY2FwZT4nXG4sIDI4OiAnPGltZS1jb252ZXJ0PidcbiwgMjk6ICc8aW1lLW5vbmNvbnZlcnQ+J1xuLCAzMDogJzxpbWUtYWNjZXB0PidcbiwgMzE6ICc8aW1lLW1vZGUtY2hhbmdlPidcbiwgMjc6ICc8ZXNjYXBlPidcbiwgMzI6ICc8c3BhY2U+J1xuLCAzMzogJzxwYWdlLXVwPidcbiwgMzQ6ICc8cGFnZS1kb3duPidcbiwgMzU6ICc8ZW5kPidcbiwgMzY6ICc8aG9tZT4nXG4sIDM3OiAnPGxlZnQ+J1xuLCAzODogJzx1cD4nXG4sIDM5OiAnPHJpZ2h0PidcbiwgNDA6ICc8ZG93bj4nXG4sIDQxOiAnPHNlbGVjdD4nXG4sIDQyOiAnPHByaW50PidcbiwgNDM6ICc8ZXhlY3V0ZT4nXG4sIDQ0OiAnPHNuYXBzaG90PidcbiwgNDU6ICc8aW5zZXJ0PidcbiwgNDY6ICc8ZGVsZXRlPidcbiwgNDc6ICc8aGVscD4nXG4sIDkxOiAnPG1ldGE+JyAgLy8gbWV0YS1sZWZ0IC0tIG5vIG9uZSBoYW5kbGVzIGxlZnQgYW5kIHJpZ2h0IHByb3Blcmx5LCBzbyB3ZSBjb2VyY2UgaW50byBvbmUuXG4sIDkyOiAnPG1ldGE+JyAgLy8gbWV0YS1yaWdodFxuLCA5MzogaXNPU1ggPyAnPG1ldGE+JyA6ICc8bWVudT4nICAgICAgLy8gY2hyb21lLG9wZXJhLHNhZmFyaSBhbGwgcmVwb3J0IHRoaXMgZm9yIG1ldGEtcmlnaHQgKG9zeCBtYnApLlxuLCA5NTogJzxzbGVlcD4nXG4sIDEwNjogJzxudW0tKj4nXG4sIDEwNzogJzxudW0tKz4nXG4sIDEwODogJzxudW0tZW50ZXI+J1xuLCAxMDk6ICc8bnVtLS0+J1xuLCAxMTA6ICc8bnVtLS4+J1xuLCAxMTE6ICc8bnVtLS8+J1xuLCAxNDQ6ICc8bnVtLWxvY2s+J1xuLCAxNDU6ICc8c2Nyb2xsLWxvY2s+J1xuLCAxNjA6ICc8c2hpZnQtbGVmdD4nXG4sIDE2MTogJzxzaGlmdC1yaWdodD4nXG4sIDE2MjogJzxjb250cm9sLWxlZnQ+J1xuLCAxNjM6ICc8Y29udHJvbC1yaWdodD4nXG4sIDE2NDogJzxhbHQtbGVmdD4nXG4sIDE2NTogJzxhbHQtcmlnaHQ+J1xuLCAxNjY6ICc8YnJvd3Nlci1iYWNrPidcbiwgMTY3OiAnPGJyb3dzZXItZm9yd2FyZD4nXG4sIDE2ODogJzxicm93c2VyLXJlZnJlc2g+J1xuLCAxNjk6ICc8YnJvd3Nlci1zdG9wPidcbiwgMTcwOiAnPGJyb3dzZXItc2VhcmNoPidcbiwgMTcxOiAnPGJyb3dzZXItZmF2b3JpdGVzPidcbiwgMTcyOiAnPGJyb3dzZXItaG9tZT4nXG5cbiAgLy8gZmYvb3N4IHJlcG9ydHMgJzx2b2x1bWUtbXV0ZT4nIGZvciAnLSdcbiwgMTczOiBpc09TWCAmJiBtYXliZUZpcmVmb3ggPyAnLScgOiAnPHZvbHVtZS1tdXRlPidcbiwgMTc0OiAnPHZvbHVtZS1kb3duPidcbiwgMTc1OiAnPHZvbHVtZS11cD4nXG4sIDE3NjogJzxuZXh0LXRyYWNrPidcbiwgMTc3OiAnPHByZXYtdHJhY2s+J1xuLCAxNzg6ICc8c3RvcD4nXG4sIDE3OTogJzxwbGF5LXBhdXNlPidcbiwgMTgwOiAnPGxhdW5jaC1tYWlsPidcbiwgMTgxOiAnPGxhdW5jaC1tZWRpYS1zZWxlY3Q+J1xuLCAxODI6ICc8bGF1bmNoLWFwcCAxPidcbiwgMTgzOiAnPGxhdW5jaC1hcHAgMj4nXG4sIDE4NjogJzsnXG4sIDE4NzogJz0nXG4sIDE4ODogJywnXG4sIDE4OTogJy0nXG4sIDE5MDogJy4nXG4sIDE5MTogJy8nXG4sIDE5MjogJ2AnXG4sIDIxOTogJ1snXG4sIDIyMDogJ1xcXFwnXG4sIDIyMTogJ10nXG4sIDIyMjogXCInXCJcbiwgMjIzOiAnPG1ldGE+J1xuLCAyMjQ6ICc8bWV0YT4nICAgICAgIC8vIGZpcmVmb3ggcmVwb3J0cyBtZXRhIGhlcmUuXG4sIDIyNjogJzxhbHQtZ3I+J1xuLCAyMjk6ICc8aW1lLXByb2Nlc3M+J1xuLCAyMzE6IGlzT3BlcmEgPyAnYCcgOiAnPHVuaWNvZGU+J1xuLCAyNDY6ICc8YXR0ZW50aW9uPidcbiwgMjQ3OiAnPGNyc2VsPidcbiwgMjQ4OiAnPGV4c2VsPidcbiwgMjQ5OiAnPGVyYXNlLWVvZj4nXG4sIDI1MDogJzxwbGF5PidcbiwgMjUxOiAnPHpvb20+J1xuLCAyNTI6ICc8bm8tbmFtZT4nXG4sIDI1MzogJzxwYS0xPidcbiwgMjU0OiAnPGNsZWFyPidcbn1cblxuZm9yKGkgPSA1ODsgaSA8IDY1OyArK2kpIHtcbiAgb3V0cHV0W2ldID0gU3RyaW5nLmZyb21DaGFyQ29kZShpKVxufVxuXG4vLyAwLTlcbmZvcihpID0gNDg7IGkgPCA1ODsgKytpKSB7XG4gIG91dHB1dFtpXSA9IChpIC0gNDgpKycnXG59XG5cbi8vIEEtWlxuZm9yKGkgPSA2NTsgaSA8IDkxOyArK2kpIHtcbiAgb3V0cHV0W2ldID0gU3RyaW5nLmZyb21DaGFyQ29kZShpKVxufVxuXG4vLyBudW0wLTlcbmZvcihpID0gOTY7IGkgPCAxMDc7ICsraSkge1xuICBvdXRwdXRbaV0gPSAnPG51bS0nKyhpIC0gOTYpKyc+J1xufVxuXG4vLyBGMS1GMjRcbmZvcihpID0gMTEyOyBpIDwgMTM2OyArK2kpIHtcbiAgb3V0cHV0W2ldID0gJ0YnKyhpLTExMSlcbn1cblxufSkoKSIsIlwidXNlIHN0cmljdFwiXG5cbmZ1bmN0aW9uIGludmVydChoYXNoKSB7XG4gIHZhciByZXN1bHQgPSB7fVxuICBmb3IodmFyIGkgaW4gaGFzaCkge1xuICAgIGlmKGhhc2guaGFzT3duUHJvcGVydHkoaSkpIHtcbiAgICAgIHJlc3VsdFtoYXNoW2ldXSA9IGlcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHJlc3VsdFxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGludmVydCIsIlwidXNlIHN0cmljdFwiXG5cbmZ1bmN0aW9uIHVuaXF1ZV9wcmVkKGxpc3QsIGNvbXBhcmUpIHtcbiAgdmFyIHB0ciA9IDFcbiAgICAsIGxlbiA9IGxpc3QubGVuZ3RoXG4gICAgLCBhPWxpc3RbMF0sIGI9bGlzdFswXVxuICBmb3IodmFyIGk9MTsgaTxsZW47ICsraSkge1xuICAgIGIgPSBhXG4gICAgYSA9IGxpc3RbaV1cbiAgICBpZihjb21wYXJlKGEsIGIpKSB7XG4gICAgICBpZihpID09PSBwdHIpIHtcbiAgICAgICAgcHRyKytcbiAgICAgICAgY29udGludWVcbiAgICAgIH1cbiAgICAgIGxpc3RbcHRyKytdID0gYVxuICAgIH1cbiAgfVxuICBsaXN0Lmxlbmd0aCA9IHB0clxuICByZXR1cm4gbGlzdFxufVxuXG5mdW5jdGlvbiB1bmlxdWVfZXEobGlzdCkge1xuICB2YXIgcHRyID0gMVxuICAgICwgbGVuID0gbGlzdC5sZW5ndGhcbiAgICAsIGE9bGlzdFswXSwgYiA9IGxpc3RbMF1cbiAgZm9yKHZhciBpPTE7IGk8bGVuOyArK2ksIGI9YSkge1xuICAgIGIgPSBhXG4gICAgYSA9IGxpc3RbaV1cbiAgICBpZihhICE9PSBiKSB7XG4gICAgICBpZihpID09PSBwdHIpIHtcbiAgICAgICAgcHRyKytcbiAgICAgICAgY29udGludWVcbiAgICAgIH1cbiAgICAgIGxpc3RbcHRyKytdID0gYVxuICAgIH1cbiAgfVxuICBsaXN0Lmxlbmd0aCA9IHB0clxuICByZXR1cm4gbGlzdFxufVxuXG5mdW5jdGlvbiB1bmlxdWUobGlzdCwgY29tcGFyZSwgc29ydGVkKSB7XG4gIGlmKGxpc3QubGVuZ3RoID09PSAwKSB7XG4gICAgcmV0dXJuIFtdXG4gIH1cbiAgaWYoY29tcGFyZSkge1xuICAgIGlmKCFzb3J0ZWQpIHtcbiAgICAgIGxpc3Quc29ydChjb21wYXJlKVxuICAgIH1cbiAgICByZXR1cm4gdW5pcXVlX3ByZWQobGlzdCwgY29tcGFyZSlcbiAgfVxuICBpZighc29ydGVkKSB7XG4gICAgbGlzdC5zb3J0KClcbiAgfVxuICByZXR1cm4gdW5pcXVlX2VxKGxpc3QpXG59XG5cbm1vZHVsZS5leHBvcnRzID0gdW5pcXVlIiwiXCJ1c2Ugc3RyaWN0XCJcblxuZnVuY3Rpb24gbG93ZXJCb3VuZF9jbXAoYXJyYXksIHZhbHVlLCBjb21wYXJlLCBsbywgaGkpIHtcbiAgbG8gPSBsb3wwXG4gIGhpID0gaGl8MFxuICB3aGlsZShsbyA8IGhpKSB7XG4gICAgdmFyIG0gPSAobG8gKyBoaSkgPj4+IDFcbiAgICAgICwgdiA9IGNvbXBhcmUodmFsdWUsIGFycmF5W21dKVxuICAgIGlmKHYgPCAwKSB7XG4gICAgICBoaSA9IG0tMVxuICAgIH0gZWxzZSBpZih2ID4gMCkge1xuICAgICAgbG8gPSBtKzFcbiAgICB9IGVsc2Uge1xuICAgICAgaGkgPSBtXG4gICAgfVxuICB9XG4gIGlmKGNvbXBhcmUoYXJyYXlbbG9dLCB2YWx1ZSkgPD0gMCkge1xuICAgIHJldHVybiBsb1xuICB9XG4gIHJldHVybiBsbyAtIDFcbn1cblxuZnVuY3Rpb24gbG93ZXJCb3VuZF9kZWYoYXJyYXksIHZhbHVlLCBsbywgaGkpIHtcbiAgbG8gPSBsb3wwXG4gIGhpID0gaGl8MFxuICB3aGlsZShsbyA8IGhpKSB7XG4gICAgdmFyIG0gPSAobG8gKyBoaSkgPj4+IDFcbiAgICBpZih2YWx1ZSA8IGFycmF5W21dKSB7XG4gICAgICBoaSA9IG0tMVxuICAgIH0gZWxzZSBpZih2YWx1ZSA+IGFycmF5W21dKSB7XG4gICAgICBsbyA9IG0rMVxuICAgIH0gZWxzZSB7XG4gICAgICBoaSA9IG1cbiAgICB9XG4gIH1cbiAgaWYoYXJyYXlbbG9dIDw9IHZhbHVlKSB7XG4gICAgcmV0dXJuIGxvXG4gIH1cbiAgcmV0dXJuIGxvIC0gMVxufVxuXG5mdW5jdGlvbiBsb3dlckJvdW5kKGFycmF5LCB2YWx1ZSwgY29tcGFyZSwgbG8sIGhpKSB7XG4gIGlmKCFsbykge1xuICAgIGxvID0gMFxuICB9XG4gIGlmKHR5cGVvZihoaSkgIT09IFwibnVtYmVyXCIpIHtcbiAgICBoaSA9IGFycmF5Lmxlbmd0aC0xXG4gIH1cbiAgaWYoY29tcGFyZSkge1xuICAgIHJldHVybiBsb3dlckJvdW5kX2NtcChhcnJheSwgdmFsdWUsIGNvbXBhcmUsIGxvLCBoaSlcbiAgfVxuICByZXR1cm4gbG93ZXJCb3VuZF9kZWYoYXJyYXksIHZhbHVlLCBsbywgaGkpXG59XG5cbm1vZHVsZS5leHBvcnRzID0gbG93ZXJCb3VuZCIsIlwidXNlIHN0cmljdFwiXG5cbmZ1bmN0aW9uIGlvdGEobikge1xuICB2YXIgcmVzdWx0ID0gbmV3IEFycmF5KG4pXG4gIGZvcih2YXIgaT0wOyBpPG47ICsraSkge1xuICAgIHJlc3VsdFtpXSA9IGlcbiAgfVxuICByZXR1cm4gcmVzdWx0XG59XG5cbm1vZHVsZS5leHBvcnRzID0gaW90YSJdfQ==
;var shell = require("game-shell")()
var context
, player_x = 250
, player_y = 250
//Bind keyboard commands
shell.bind("move-left", "left", "A")
shell.bind("move-right", "right", "D")
shell.bind("move-up", "up", "W")
shell.bind("move-down", "down", "S")
//Fired when document is loaded
shell.on("init", function() {
var canvas = document.createElement("canvas")
canvas.width = 500
canvas.height = 500
shell.element.appendChild(canvas)
context = canvas.getContext("2d")
})
//Fired once per game tick
shell.on("tick", function() {
if(shell.wasDown("move-left")) {
player_x -= 1
}
if(shell.wasDown("move-right")) {
player_x += 1
}
if(shell.wasDown("move-up")) {
player_y -= 1
}
if(shell.wasDown("move-down")) {
player_y += 1
}
})
//Render a frame
shell.on("render", function(frame_time) {
context.fillStyle = "#000"
context.fillRect(0, 0, 500, 500)
context.fillStyle = "#f00"
context.fillRect(player_x-10, player_y-10, 20, 20)
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment