UNPKG

ketcher-standalone

Version:
578 lines (508 loc) 15.3 MB
/**************************************************************************** * Copyright 2021 EPAM Systems * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ***************************************************************************/ import _objectWithoutProperties from '@babel/runtime/helpers/objectWithoutProperties'; import _slicedToArray from '@babel/runtime/helpers/slicedToArray'; import _asyncToGenerator from '@babel/runtime/helpers/asyncToGenerator'; import _classCallCheck from '@babel/runtime/helpers/classCallCheck'; import _createClass from '@babel/runtime/helpers/createClass'; import _defineProperty from '@babel/runtime/helpers/defineProperty'; import _regeneratorRuntime from '@babel/runtime/regenerator'; import { pickStandardServerOptions, CoreEditor, getLabelRenderModeForIndigo, ChemicalMimeType } from 'ketcher-core'; var Command; (function (Command) { Command[Command["Info"] = 0] = "Info"; Command[Command["Convert"] = 1] = "Convert"; Command[Command["Layout"] = 2] = "Layout"; Command[Command["Clean"] = 3] = "Clean"; Command[Command["Aromatize"] = 4] = "Aromatize"; Command[Command["Dearomatize"] = 5] = "Dearomatize"; Command[Command["CalculateCip"] = 6] = "CalculateCip"; Command[Command["Automap"] = 7] = "Automap"; Command[Command["Check"] = 8] = "Check"; Command[Command["Calculate"] = 9] = "Calculate"; Command[Command["GenerateImageAsBase64"] = 10] = "GenerateImageAsBase64"; Command[Command["GetInChIKey"] = 11] = "GetInChIKey"; Command[Command["ExplicitHydrogens"] = 12] = "ExplicitHydrogens"; })(Command || (Command = {})); var WorkerEvent; (function (WorkerEvent) { WorkerEvent["Info"] = "info"; WorkerEvent["Convert"] = "convert"; WorkerEvent["Layout"] = "layout"; WorkerEvent["Clean"] = "clean"; WorkerEvent["Aromatize"] = "aromatize"; WorkerEvent["Dearomatize"] = "dearomatize"; WorkerEvent["CalculateCip"] = "calculateCip"; WorkerEvent["Automap"] = "automap"; WorkerEvent["Check"] = "check"; WorkerEvent["Calculate"] = "calculate"; WorkerEvent["GenerateImageAsBase64"] = "generateImageAsBase64"; WorkerEvent["GetInChIKey"] = "getInChIKey"; WorkerEvent["ExplicitHydrogens"] = "convert_explicit_hydrogens"; })(WorkerEvent || (WorkerEvent = {})); var SupportedFormat; (function (SupportedFormat) { SupportedFormat["Rxn"] = "rxnfile"; SupportedFormat["Mol"] = "molfile"; SupportedFormat["Smiles"] = "smiles"; SupportedFormat["Smarts"] = "smarts"; SupportedFormat["CML"] = "cml"; SupportedFormat["InChI"] = "inchi"; SupportedFormat["InChIAuxInfo"] = "inchi-aux"; SupportedFormat["InChIKey"] = "inchi-key"; SupportedFormat["Ket"] = "ket"; SupportedFormat["CDX"] = "cdx"; SupportedFormat["CDXML"] = "cdxml"; SupportedFormat["SDF"] = "sdf"; SupportedFormat["FASTA"] = "fasta"; SupportedFormat["SEQUENCE"] = "sequence"; SupportedFormat["SEQUENCE_3_LETTER"] = "peptide-sequence-3-letter"; SupportedFormat["IDT"] = "idt"; SupportedFormat["HELM"] = "helm"; SupportedFormat["RDF"] = "rdf"; })(SupportedFormat || (SupportedFormat = {})); var domain; // This constructor is used to store event handlers. Instantiating this is // faster than explicitly calling `Object.create(null)` to get a "clean" empty // object (tested with v8 v4.9). function EventHandlers() {} EventHandlers.prototype = Object.create(null); function EventEmitter() { EventEmitter.init.call(this); } // nodejs oddity // require('events') === require('events').EventEmitter EventEmitter.EventEmitter = EventEmitter; EventEmitter.usingDomains = false; EventEmitter.prototype.domain = undefined; EventEmitter.prototype._events = undefined; EventEmitter.prototype._maxListeners = undefined; // 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. EventEmitter.defaultMaxListeners = 10; EventEmitter.init = function() { this.domain = null; if (EventEmitter.usingDomains) { // if there is an active domain, then attach to it. if (domain.active ) ; } if (!this._events || this._events === Object.getPrototypeOf(this)._events) { this._events = new EventHandlers(); this._eventsCount = 0; } this._maxListeners = this._maxListeners || undefined; }; // Obviously not all Emitters should be limited to 10. This function allows // that to be increased. Set to zero for unlimited. EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) { if (typeof n !== 'number' || n < 0 || isNaN(n)) throw new TypeError('"n" argument must be a positive number'); this._maxListeners = n; return this; }; function $getMaxListeners(that) { if (that._maxListeners === undefined) return EventEmitter.defaultMaxListeners; return that._maxListeners; } EventEmitter.prototype.getMaxListeners = function getMaxListeners() { return $getMaxListeners(this); }; // These standalone emit* functions are used to optimize calling of event // handlers for fast cases because emit() itself often has a variable number of // arguments and can be deoptimized because of that. These functions always have // the same number of arguments and thus do not get deoptimized, so the code // inside them can execute faster. function emitNone(handler, isFn, self) { if (isFn) handler.call(self); else { var len = handler.length; var listeners = arrayClone(handler, len); for (var i = 0; i < len; ++i) listeners[i].call(self); } } function emitOne(handler, isFn, self, arg1) { if (isFn) handler.call(self, arg1); else { var len = handler.length; var listeners = arrayClone(handler, len); for (var i = 0; i < len; ++i) listeners[i].call(self, arg1); } } function emitTwo(handler, isFn, self, arg1, arg2) { if (isFn) handler.call(self, arg1, arg2); else { var len = handler.length; var listeners = arrayClone(handler, len); for (var i = 0; i < len; ++i) listeners[i].call(self, arg1, arg2); } } function emitThree(handler, isFn, self, arg1, arg2, arg3) { if (isFn) handler.call(self, arg1, arg2, arg3); else { var len = handler.length; var listeners = arrayClone(handler, len); for (var i = 0; i < len; ++i) listeners[i].call(self, arg1, arg2, arg3); } } function emitMany(handler, isFn, self, args) { if (isFn) handler.apply(self, args); else { var len = handler.length; var listeners = arrayClone(handler, len); for (var i = 0; i < len; ++i) listeners[i].apply(self, args); } } EventEmitter.prototype.emit = function emit(type) { var er, handler, len, args, i, events, domain; var doError = (type === 'error'); events = this._events; if (events) doError = (doError && events.error == null); else if (!doError) return false; domain = this.domain; // If there is no 'error' event listener then throw. if (doError) { er = arguments[1]; if (domain) { if (!er) er = new Error('Uncaught, unspecified "error" event'); er.domainEmitter = this; er.domain = domain; er.domainThrown = false; domain.emit('error', er); } else if (er instanceof Error) { throw er; // Unhandled 'error' event } else { // At least give some kind of context to the user var err = new Error('Uncaught, unspecified "error" event. (' + er + ')'); err.context = er; throw err; } return false; } handler = events[type]; if (!handler) return false; var isFn = typeof handler === 'function'; len = arguments.length; switch (len) { // fast cases case 1: emitNone(handler, isFn, this); break; case 2: emitOne(handler, isFn, this, arguments[1]); break; case 3: emitTwo(handler, isFn, this, arguments[1], arguments[2]); break; case 4: emitThree(handler, isFn, this, arguments[1], arguments[2], arguments[3]); break; // slower default: args = new Array(len - 1); for (i = 1; i < len; i++) args[i - 1] = arguments[i]; emitMany(handler, isFn, this, args); } return true; }; function _addListener(target, type, listener, prepend) { var m; var events; var existing; if (typeof listener !== 'function') throw new TypeError('"listener" argument must be a function'); events = target._events; if (!events) { events = target._events = new EventHandlers(); target._eventsCount = 0; } else { // To avoid recursion in the case that type === "newListener"! Before // adding it to the listeners, first emit "newListener". if (events.newListener) { target.emit('newListener', type, listener.listener ? listener.listener : listener); // Re-assign `events` because a newListener handler could have caused the // this._events to be assigned to a new object events = target._events; } existing = events[type]; } if (!existing) { // Optimize the case of one listener. Don't need the extra array object. existing = events[type] = listener; ++target._eventsCount; } else { if (typeof existing === 'function') { // Adding the second element, need to change to array. existing = events[type] = prepend ? [listener, existing] : [existing, listener]; } else { // If we've already got an array, just append. if (prepend) { existing.unshift(listener); } else { existing.push(listener); } } // Check for listener leak if (!existing.warned) { m = $getMaxListeners(target); if (m && m > 0 && existing.length > m) { existing.warned = true; var w = new Error('Possible EventEmitter memory leak detected. ' + existing.length + ' ' + type + ' listeners added. ' + 'Use emitter.setMaxListeners() to increase limit'); w.name = 'MaxListenersExceededWarning'; w.emitter = target; w.type = type; w.count = existing.length; emitWarning(w); } } } return target; } function emitWarning(e) { typeof console.warn === 'function' ? console.warn(e) : console.log(e); } EventEmitter.prototype.addListener = function addListener(type, listener) { return _addListener(this, type, listener, false); }; EventEmitter.prototype.on = EventEmitter.prototype.addListener; EventEmitter.prototype.prependListener = function prependListener(type, listener) { return _addListener(this, type, listener, true); }; function _onceWrap(target, type, listener) { var fired = false; function g() { target.removeListener(type, g); if (!fired) { fired = true; listener.apply(target, arguments); } } g.listener = listener; return g; } EventEmitter.prototype.once = function once(type, listener) { if (typeof listener !== 'function') throw new TypeError('"listener" argument must be a function'); this.on(type, _onceWrap(this, type, listener)); return this; }; EventEmitter.prototype.prependOnceListener = function prependOnceListener(type, listener) { if (typeof listener !== 'function') throw new TypeError('"listener" argument must be a function'); this.prependListener(type, _onceWrap(this, type, listener)); return this; }; // emits a 'removeListener' event iff the listener was removed EventEmitter.prototype.removeListener = function removeListener(type, listener) { var list, events, position, i, originalListener; if (typeof listener !== 'function') throw new TypeError('"listener" argument must be a function'); events = this._events; if (!events) return this; list = events[type]; if (!list) return this; if (list === listener || (list.listener && list.listener === listener)) { if (--this._eventsCount === 0) this._events = new EventHandlers(); else { delete events[type]; if (events.removeListener) this.emit('removeListener', type, list.listener || listener); } } else if (typeof list !== 'function') { position = -1; for (i = list.length; i-- > 0;) { if (list[i] === listener || (list[i].listener && list[i].listener === listener)) { originalListener = list[i].listener; position = i; break; } } if (position < 0) return this; if (list.length === 1) { list[0] = undefined; if (--this._eventsCount === 0) { this._events = new EventHandlers(); return this; } else { delete events[type]; } } else { spliceOne(list, position); } if (events.removeListener) this.emit('removeListener', type, originalListener || listener); } return this; }; EventEmitter.prototype.removeAllListeners = function removeAllListeners(type) { var listeners, events; events = this._events; if (!events) return this; // not listening for removeListener, no need to emit if (!events.removeListener) { if (arguments.length === 0) { this._events = new EventHandlers(); this._eventsCount = 0; } else if (events[type]) { if (--this._eventsCount === 0) this._events = new EventHandlers(); else delete events[type]; } return this; } // emit removeListener for all listeners on all events if (arguments.length === 0) { var keys = Object.keys(events); for (var i = 0, key; i < keys.length; ++i) { key = keys[i]; if (key === 'removeListener') continue; this.removeAllListeners(key); } this.removeAllListeners('removeListener'); this._events = new EventHandlers(); this._eventsCount = 0; return this; } listeners = events[type]; if (typeof listeners === 'function') { this.removeListener(type, listeners); } else if (listeners) { // LIFO order do { this.removeListener(type, listeners[listeners.length - 1]); } while (listeners[0]); } return this; }; EventEmitter.prototype.listeners = function listeners(type) { var evlistener; var ret; var events = this._events; if (!events) ret = []; else { evlistener = events[type]; if (!evlistener) ret = []; else if (typeof evlistener === 'function') ret = [evlistener.listener || evlistener]; else ret = unwrapListeners(evlistener); } return ret; }; EventEmitter.listenerCount = function(emitter, type) { if (typeof emitter.listenerCount === 'function') { return emitter.listenerCount(type); } else { return listenerCount.call(emitter, type); } }; EventEmitter.prototype.listenerCount = listenerCount; function listenerCount(type) { var events = this._events; if (events) { var evlistener = events[type]; if (typeof evlistener === 'function') { return 1; } else if (evlistener) { return evlistener.length; } } return 0; } EventEmitter.prototype.eventNames = function eventNames() { return this._eventsCount > 0 ? Reflect.ownKeys(this._events) : []; }; // About 1.5x faster than the two-arg version of Array#splice(). function spliceOne(list, index) { for (var i = index, k = i + 1, n = list.length; k < n; i += 1, k += 1) list[i] = list[k]; list.pop(); } function arrayClone(arr, i) { var copy = new Array(i); while (i--) copy[i] = arr[i]; return copy; } function unwrapListeners(arr) { var ret = new Array(arr.length); for (var i = 0; i < ret.length; ++i) { ret[i] = arr[i].listener || arr[i]; } return ret; } var STRUCT_SERVICE_NO_RENDER_INITIALIZED_EVENT = 'struct-service-no-render-initialized'; var STRUCT_SERVICE_INITIALIZED_EVENT = 'struct-service-initialized'; function decodeBase64(base64, enableUnicode) { var binaryString = atob(base64); if (enableUnicode) { var binaryView = new Uint8Array(binaryString.length); for (var i = 0, n = binaryString.length; i < n; ++i) { binaryView[i] = binaryString.charCodeAt(i); } return String.fromCharCode.apply(null, new Uint16Array(binaryView.buffer)); } return binaryString; } function createURL(base64, sourcemapArg, enableUnicodeArg) { var sourcemap = sourcemapArg === undefined ? null : sourcemapArg; var enableUnicode = enableUnicodeArg === undefined ? false : enableUnicodeArg; var source = decodeBase64(base64, enableUnicode); var start = source.indexOf('\n', 10) + 1; var body = source.substring(start) + (sourcemap ? '\/\/# sourceMappingURL=' + sourcemap : ''); var blob = new Blob([body], { type: 'application/javascript' }); return URL.createObjectURL(blob); } function createBase64WorkerFactory(base64, sourcemapArg, enableUnicodeArg) { var url; return function WorkerFactory(options) { url = url || createURL(base64, sourcemapArg, enableUnicodeArg); return new Worker(url, options); }; } var WorkerFactory = createBase64WorkerFactory('Lyogcm9sbHVwLXBsdWdpbi13ZWItd29ya2VyLWxvYWRlciAqLwooZnVuY3Rpb24gKCkgewoJJ3VzZSBzdHJpY3QnOwoKCWZ1bmN0aW9uIGdldERlZmF1bHRFeHBvcnRGcm9tQ2pzICh4KSB7CgkJcmV0dXJuIHggJiYgeC5fX2VzTW9kdWxlICYmIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh4LCAnZGVmYXVsdCcpID8geFsnZGVmYXVsdCddIDogeDsKCX0KCglmdW5jdGlvbiBjcmVhdGVDb21tb25qc01vZHVsZShmbiwgYmFzZWRpciwgbW9kdWxlKSB7CgkJcmV0dXJuIG1vZHVsZSA9IHsKCQkJcGF0aDogYmFzZWRpciwKCQkJZXhwb3J0czoge30sCgkJCXJlcXVpcmU6IGZ1bmN0aW9uIChwYXRoLCBiYXNlKSB7CgkJCQlyZXR1cm4gY29tbW9uanNSZXF1aXJlKHBhdGgsIChiYXNlID09PSB1bmRlZmluZWQgfHwgYmFzZSA9PT0gbnVsbCkgPyBtb2R1bGUucGF0aCA6IGJhc2UpOwoJCQl9CgkJfSwgZm4obW9kdWxlLCBtb2R1bGUuZXhwb3J0cyksIG1vZHVsZS5leHBvcnRzOwoJfQoKCWZ1bmN0aW9uIGdldEF1Z21lbnRlZE5hbWVzcGFjZShuKSB7CgkJaWYgKG4uX19lc01vZHVsZSkgcmV0dXJuIG47CgkJdmFyIGEgPSBPYmplY3QuZGVmaW5lUHJvcGVydHkoe30sICdfX2VzTW9kdWxlJywge3ZhbHVlOiB0cnVlfSk7CgkJT2JqZWN0LmtleXMobikuZm9yRWFjaChmdW5jdGlvbiAoaykgewoJCQl2YXIgZCA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3Iobiwgayk7CgkJCU9iamVjdC5kZWZpbmVQcm9wZXJ0eShhLCBrLCBkLmdldCA/IGQgOiB7CgkJCQllbnVtZXJhYmxlOiB0cnVlLAoJCQkJZ2V0OiBmdW5jdGlvbiAoKSB7CgkJCQkJcmV0dXJuIG5ba107CgkJCQl9CgkJCX0pOwoJCX0pOwoJCXJldHVybiBhOwoJfQoKCWZ1bmN0aW9uIGNvbW1vbmpzUmVxdWlyZSAoKSB7CgkJdGhyb3cgbmV3IEVycm9yKCdEeW5hbWljIHJlcXVpcmVzIGFyZSBub3QgY3VycmVudGx5IHN1cHBvcnRlZCBieSBAcm9sbHVwL3BsdWdpbi1jb21tb25qcycpOwoJfQoKCXZhciBfdHlwZW9mXzEgPSBjcmVhdGVDb21tb25qc01vZHVsZShmdW5jdGlvbiAobW9kdWxlKSB7CglmdW5jdGlvbiBfdHlwZW9mKG8pIHsKCSAgIkBiYWJlbC9oZWxwZXJzIC0gdHlwZW9mIjsKCgkgIHJldHVybiAobW9kdWxlLmV4cG9ydHMgPSBfdHlwZW9mID0gImZ1bmN0aW9uIiA9PSB0eXBlb2YgU3ltYm9sICYmICJzeW1ib2wiID09IHR5cGVvZiBTeW1ib2wuaXRlcmF0b3IgPyBmdW5jdGlvbiAobykgewoJICAgIHJldHVybiB0eXBlb2YgbzsKCSAgfSA6IGZ1bmN0aW9uIChvKSB7CgkgICAgcmV0dXJuIG8gJiYgImZ1bmN0aW9uIiA9PSB0eXBlb2YgU3ltYm9sICYmIG8uY29uc3RydWN0b3IgPT09IFN5bWJvbCAmJiBvICE9PSBTeW1ib2wucHJvdG90eXBlID8gInN5bWJvbCIgOiB0eXBlb2YgbzsKCSAgfSwgbW9kdWxlLmV4cG9ydHMuX19lc01vZHVsZSA9IHRydWUsIG1vZHVsZS5leHBvcnRzWyJkZWZhdWx0Il0gPSBtb2R1bGUuZXhwb3J0cyksIF90eXBlb2Yobyk7Cgl9Cgltb2R1bGUuZXhwb3J0cyA9IF90eXBlb2YsIG1vZHVsZS5leHBvcnRzLl9fZXNNb2R1bGUgPSB0cnVlLCBtb2R1bGUuZXhwb3J0c1siZGVmYXVsdCJdID0gbW9kdWxlLmV4cG9ydHM7Cgl9KTsKCgl2YXIgdG9QcmltaXRpdmVfMSA9IGNyZWF0ZUNvbW1vbmpzTW9kdWxlKGZ1bmN0aW9uIChtb2R1bGUpIHsKCXZhciBfdHlwZW9mID0gX3R5cGVvZl8xWyJkZWZhdWx0Il07CglmdW5jdGlvbiB0b1ByaW1pdGl2ZSh0LCByKSB7CgkgIGlmICgib2JqZWN0IiAhPSBfdHlwZW9mKHQpIHx8ICF0KSByZXR1cm4gdDsKCSAgdmFyIGUgPSB0W1N5bWJvbC50b1ByaW1pdGl2ZV07CgkgIGlmICh2b2lkIDAgIT09IGUpIHsKCSAgICB2YXIgaSA9IGUuY2FsbCh0LCByIHx8ICJkZWZhdWx0Iik7CgkgICAgaWYgKCJvYmplY3QiICE9IF90eXBlb2YoaSkpIHJldHVybiBpOwoJICAgIHRocm93IG5ldyBUeXBlRXJyb3IoIkBAdG9QcmltaXRpdmUgbXVzdCByZXR1cm4gYSBwcmltaXRpdmUgdmFsdWUuIik7CgkgIH0KCSAgcmV0dXJuICgic3RyaW5nIiA9PT0gciA/IFN0cmluZyA6IE51bWJlcikodCk7Cgl9Cgltb2R1bGUuZXhwb3J0cyA9IHRvUHJpbWl0aXZlLCBtb2R1bGUuZXhwb3J0cy5fX2VzTW9kdWxlID0gdHJ1ZSwgbW9kdWxlLmV4cG9ydHNbImRlZmF1bHQiXSA9IG1vZHVsZS5leHBvcnRzOwoJfSk7CgoJdmFyIHRvUHJvcGVydHlLZXlfMSA9IGNyZWF0ZUNvbW1vbmpzTW9kdWxlKGZ1bmN0aW9uIChtb2R1bGUpIHsKCXZhciBfdHlwZW9mID0gX3R5cGVvZl8xWyJkZWZhdWx0Il07CgoJZnVuY3Rpb24gdG9Qcm9wZXJ0eUtleSh0KSB7CgkgIHZhciBpID0gdG9QcmltaXRpdmVfMSh0LCAic3RyaW5nIik7CgkgIHJldHVybiAic3ltYm9sIiA9PSBfdHlwZW9mKGkpID8gaSA6IFN0cmluZyhpKTsKCX0KCW1vZHVsZS5leHBvcnRzID0gdG9Qcm9wZXJ0eUtleSwgbW9kdWxlLmV4cG9ydHMuX19lc01vZHVsZSA9IHRydWUsIG1vZHVsZS5leHBvcnRzWyJkZWZhdWx0Il0gPSBtb2R1bGUuZXhwb3J0czsKCX0pOwoKCXZhciBkZWZpbmVQcm9wZXJ0eSA9IGNyZWF0ZUNvbW1vbmpzTW9kdWxlKGZ1bmN0aW9uIChtb2R1bGUpIHsKCWZ1bmN0aW9uIF9kZWZpbmVQcm9wZXJ0eShvYmosIGtleSwgdmFsdWUpIHsKCSAga2V5ID0gdG9Qcm9wZXJ0eUtleV8xKGtleSk7CgkgIGlmIChrZXkgaW4gb2JqKSB7CgkgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KG9iaiwga2V5LCB7CgkgICAgICB2YWx1ZTogdmFsdWUsCgkgICAgICBlbnVtZXJhYmxlOiB0cnVlLAoJICAgICAgY29uZmlndXJhYmxlOiB0cnVlLAoJICAgICAgd3JpdGFibGU6IHRydWUKCSAgICB9KTsKCSAgfSBlbHNlIHsKCSAgICBvYmpba2V5XSA9IHZhbHVlOwoJICB9CgkgIHJldHVybiBvYmo7Cgl9Cgltb2R1bGUuZXhwb3J0cyA9IF9kZWZpbmVQcm9wZXJ0eSwgbW9kdWxlLmV4cG9ydHMuX19lc01vZHVsZSA9IHRydWUsIG1vZHVsZS5leHBvcnRzWyJkZWZhdWx0Il0gPSBtb2R1bGUuZXhwb3J0czsKCX0pOwoKCXZhciBfZGVmaW5lUHJvcGVydHkgPSAvKkBfX1BVUkVfXyovZ2V0RGVmYXVsdEV4cG9ydEZyb21DanMoZGVmaW5lUHJvcGVydHkpOwoKCXZhciBhcnJheVdpdGhIb2xlcyA9IGNyZWF0ZUNvbW1vbmpzTW9kdWxlKGZ1bmN0aW9uIChtb2R1bGUpIHsKCWZ1bmN0aW9uIF9hcnJheVdpdGhIb2xlcyhhcnIpIHsKCSAgaWYgKEFycmF5LmlzQXJyYXkoYXJyKSkgcmV0dXJuIGFycjsKCX0KCW1vZHVsZS5leHBvcnRzID0gX2FycmF5V2l0aEhvbGVzLCBtb2R1bGUuZXhwb3J0cy5fX2VzTW9kdWxlID0gdHJ1ZSwgbW9kdWxlLmV4cG9ydHNbImRlZmF1bHQiXSA9IG1vZHVsZS5leHBvcnRzOwoJfSk7CgoJdmFyIGl0ZXJhYmxlVG9BcnJheUxpbWl0ID0gY3JlYXRlQ29tbW9uanNNb2R1bGUoZnVuY3Rpb24gKG1vZHVsZSkgewoJZnVuY3Rpb24gX2l0ZXJhYmxlVG9BcnJheUxpbWl0KHIsIGwpIHsKCSAgdmFyIHQgPSBudWxsID09IHIgPyBudWxsIDogInVuZGVmaW5lZCIgIT0gdHlwZW9mIFN5bWJvbCAmJiByW1N5bWJvbC5pdGVyYXRvcl0gfHwgclsiQEBpdGVyYXRvciJdOwoJICBpZiAobnVsbCAhPSB0KSB7CgkgICAgdmFyIGUsCgkgICAgICBuLAoJICAgICAgaSwKCSAgICAgIHUsCgkgICAgICBhID0gW10sCgkgICAgICBmID0gITAsCgkgICAgICBvID0gITE7CgkgICAgdHJ5IHsKCSAgICAgIGlmIChpID0gKHQgPSB0LmNhbGwocikpLm5leHQsIDAgPT09IGwpIHsKCSAgICAgICAgaWYgKE9iamVjdCh0KSAhPT0gdCkgcmV0dXJuOwoJICAgICAgICBmID0gITE7CgkgICAgICB9IGVsc2UgZm9yICg7ICEoZiA9IChlID0gaS5jYWxsKHQpKS5kb25lKSAmJiAoYS5wdXNoKGUudmFsdWUpLCBhLmxlbmd0aCAhPT0gbCk7IGYgPSAhMCk7CgkgICAgfSBjYXRjaCAocikgewoJICAgICAgbyA9ICEwLCBuID0gcjsKCSAgICB9IGZpbmFsbHkgewoJICAgICAgdHJ5IHsKCSAgICAgICAgaWYgKCFmICYmIG51bGwgIT0gdFsicmV0dXJuIl0gJiYgKHUgPSB0WyJyZXR1cm4iXSgpLCBPYmplY3QodSkgIT09IHUpKSByZXR1cm47CgkgICAgICB9IGZpbmFsbHkgewoJICAgICAgICBpZiAobykgdGhyb3cgbjsKCSAgICAgIH0KCSAgICB9CgkgICAgcmV0dXJuIGE7CgkgIH0KCX0KCW1vZHVsZS5leHBvcnRzID0gX2l0ZXJhYmxlVG9BcnJheUxpbWl0LCBtb2R1bGUuZXhwb3J0cy5fX2VzTW9kdWxlID0gdHJ1ZSwgbW9kdWxlLmV4cG9ydHNbImRlZmF1bHQiXSA9IG1vZHVsZS5leHBvcnRzOwoJfSk7CgoJdmFyIGFycmF5TGlrZVRvQXJyYXkgPSBjcmVhdGVDb21tb25qc01vZHVsZShmdW5jdGlvbiAobW9kdWxlKSB7CglmdW5jdGlvbiBfYXJyYXlMaWtlVG9BcnJheShhcnIsIGxlbikgewoJICBpZiAobGVuID09IG51bGwgfHwgbGVuID4gYXJyLmxlbmd0aCkgbGVuID0gYXJyLmxlbmd0aDsKCSAgZm9yICh2YXIgaSA9IDAsIGFycjIgPSBuZXcgQXJyYXkobGVuKTsgaSA8IGxlbjsgaSsrKSBhcnIyW2ldID0gYXJyW2ldOwoJICByZXR1cm4gYXJyMjsKCX0KCW1vZHVsZS5leHBvcnRzID0gX2FycmF5TGlrZVRvQXJyYXksIG1vZHVsZS5leHBvcnRzLl9fZXNNb2R1bGUgPSB0cnVlLCBtb2R1bGUuZXhwb3J0c1siZGVmYXVsdCJdID0gbW9kdWxlLmV4cG9ydHM7Cgl9KTsKCgl2YXIgdW5zdXBwb3J0ZWRJdGVyYWJsZVRvQXJyYXkgPSBjcmVhdGVDb21tb25qc01vZHVsZShmdW5jdGlvbiAobW9kdWxlKSB7CglmdW5jdGlvbiBfdW5zdXBwb3J0ZWRJdGVyYWJsZVRvQXJyYXkobywgbWluTGVuKSB7CgkgIGlmICghbykgcmV0dXJuOwoJICBpZiAodHlwZW9mIG8gPT09ICJzdHJpbmciKSByZXR1cm4gYXJyYXlMaWtlVG9BcnJheShvLCBtaW5MZW4pOwoJICB2YXIgbiA9IE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChvKS5zbGljZSg4LCAtMSk7CgkgIGlmIChuID09PSAiT2JqZWN0IiAmJiBvLmNvbnN0cnVjdG9yKSBuID0gby5jb25zdHJ1Y3Rvci5uYW1lOwoJICBpZiAobiA9PT0gIk1hcCIgfHwgbiA9PT0gIlNldCIpIHJldHVybiBBcnJheS5mcm9tKG8pOwoJICBpZiAobiA9PT0gIkFyZ3VtZW50cyIgfHwgL14oPzpVaXxJKW50KD86OHwxNnwzMikoPzpDbGFtcGVkKT9BcnJheSQvLnRlc3QobikpIHJldHVybiBhcnJheUxpa2VUb0FycmF5KG8sIG1pbkxlbik7Cgl9Cgltb2R1bGUuZXhwb3J0cyA9IF91bnN1cHBvcnRlZEl0ZXJhYmxlVG9BcnJheSwgbW9kdWxlLmV4cG9ydHMuX19lc01vZHVsZSA9IHRydWUsIG1vZHVsZS5leHBvcnRzWyJkZWZhdWx0Il0gPSBtb2R1bGUuZXhwb3J0czsKCX0pOwoKCXZhciBub25JdGVyYWJsZVJlc3QgPSBjcmVhdGVDb21tb25qc01vZHVsZShmdW5jdGlvbiAobW9kdWxlKSB7CglmdW5jdGlvbiBfbm9uSXRlcmFibGVSZXN0KCkgewoJICB0aHJvdyBuZXcgVHlwZUVycm9yKCJJbnZhbGlkIGF0dGVtcHQgdG8gZGVzdHJ1Y3R1cmUgbm9uLWl0ZXJhYmxlIGluc3RhbmNlLlxuSW4gb3JkZXIgdG8gYmUgaXRlcmFibGUsIG5vbi1hcnJheSBvYmplY3RzIG11c3QgaGF2ZSBhIFtTeW1ib2wuaXRlcmF0b3JdKCkgbWV0aG9kLiIpOwoJfQoJbW9kdWxlLmV4cG9ydHMgPSBfbm9uSXRlcmFibGVSZXN0LCBtb2R1bGUuZXhwb3J0cy5fX2VzTW9kdWxlID0gdHJ1ZSwgbW9kdWxlLmV4cG9ydHNbImRlZmF1bHQiXSA9IG1vZHVsZS5leHBvcnRzOwoJfSk7CgoJdmFyIHNsaWNlZFRvQXJyYXkgPSBjcmVhdGVDb21tb25qc01vZHVsZShmdW5jdGlvbiAobW9kdWxlKSB7CglmdW5jdGlvbiBfc2xpY2VkVG9BcnJheShhcnIsIGkpIHsKCSAgcmV0dXJuIGFycmF5V2l0aEhvbGVzKGFycikgfHwgaXRlcmFibGVUb0FycmF5TGltaXQoYXJyLCBpKSB8fCB1bnN1cHBvcnRlZEl0ZXJhYmxlVG9BcnJheShhcnIsIGkpIHx8IG5vbkl0ZXJhYmxlUmVzdCgpOwoJfQoJbW9kdWxlLmV4cG9ydHMgPSBfc2xpY2VkVG9BcnJheSwgbW9kdWxlLmV4cG9ydHMuX19lc01vZHVsZSA9IHRydWUsIG1vZHVsZS5leHBvcnRzWyJkZWZhdWx0Il0gPSBtb2R1bGUuZXhwb3J0czsKCX0pOwoKCXZhciBfc2xpY2VkVG9BcnJheSA9IC8qQF9fUFVSRV9fKi9nZXREZWZhdWx0RXhwb3J0RnJvbUNqcyhzbGljZWRUb0FycmF5KTsKCgl2YXIgQ29tbWFuZDsKCShmdW5jdGlvbiAoQ29tbWFuZCkgewoJICBDb21tYW5kW0NvbW1hbmRbIkluZm8iXSA9IDBdID0gIkluZm8iOwoJICBDb21tYW5kW0NvbW1hbmRbIkNvbnZlcnQiXSA9IDFdID0gIkNvbnZlcnQiOwoJICBDb21tYW5kW0NvbW1hbmRbIkxheW91dCJdID0gMl0gPSAiTGF5b3V0IjsKCSAgQ29tbWFuZFtDb21tYW5kWyJDbGVhbiJdID0gM10gPSAiQ2xlYW4iOwoJICBDb21tYW5kW0NvbW1hbmRbIkFyb21hdGl6ZSJdID0gNF0gPSAiQXJvbWF0aXplIjsKCSAgQ29tbWFuZFtDb21tYW5kWyJEZWFyb21hdGl6ZSJdID0gNV0gPSAiRGVhcm9tYXRpemUiOwoJICBDb21tYW5kW0NvbW1hbmRbIkNhbGN1bGF0ZUNpcCJdID0gNl0gPSAiQ2FsY3VsYXRlQ2lwIjsKCSAgQ29tbWFuZFtDb21tYW5kWyJBdXRvbWFwIl0gPSA3XSA9ICJBdXRvbWFwIjsKCSAgQ29tbWFuZFtDb21tYW5kWyJDaGVjayJdID0gOF0gPSAiQ2hlY2siOwoJICBDb21tYW5kW0NvbW1hbmRbIkNhbGN1bGF0ZSJdID0gOV0gPSAiQ2FsY3VsYXRlIjsKCSAgQ29tbWFuZFtDb21tYW5kWyJHZW5lcmF0ZUltYWdlQXNCYXNlNjQiXSA9IDEwXSA9ICJHZW5lcmF0ZUltYWdlQXNCYXNlNjQiOwoJICBDb21tYW5kW0NvbW1hbmRbIkdldEluQ2hJS2V5Il0gPSAxMV0gPSAiR2V0SW5DaElLZXkiOwoJICBDb21tYW5kW0NvbW1hbmRbIkV4cGxpY2l0SHlkcm9nZW5zIl0gPSAxMl0gPSAiRXhwbGljaXRIeWRyb2dlbnMiOwoJfSkoQ29tbWFuZCB8fCAoQ29tbWFuZCA9IHt9KSk7Cgl2YXIgV29ya2VyRXZlbnQ7CgkoZnVuY3Rpb24gKFdvcmtlckV2ZW50KSB7CgkgIFdvcmtlckV2ZW50WyJJbmZvIl0gPSAiaW5mbyI7CgkgIFdvcmtlckV2ZW50WyJDb252ZXJ0Il0gPSAiY29udmVydCI7CgkgIFdvcmtlckV2ZW50WyJMYXlvdXQiXSA9ICJsYXlvdXQiOwoJICBXb3JrZXJFdmVudFsiQ2xlYW4iXSA9ICJjbGVhbiI7CgkgIFdvcmtlckV2ZW50WyJBcm9tYXRpemUiXSA9ICJhcm9tYXRpemUiOwoJICBXb3JrZXJFdmVudFsiRGVhcm9tYXRpemUiXSA9ICJkZWFyb21hdGl6ZSI7CgkgIFdvcmtlckV2ZW50WyJDYWxjdWxhdGVDaXAiXSA9ICJjYWxjdWxhdGVDaXAiOwoJICBXb3JrZXJFdmVudFsiQXV0b21hcCJdID0gImF1dG9tYXAiOwoJICBXb3JrZXJFdmVudFsiQ2hlY2siXSA9ICJjaGVjayI7CgkgIFdvcmtlckV2ZW50WyJDYWxjdWxhdGUiXSA9ICJjYWxjdWxhdGUiOwoJICBXb3JrZXJFdmVudFsiR2VuZXJhdGVJbWFnZUFzQmFzZTY0Il0gPSAiZ2VuZXJhdGVJbWFnZUFzQmFzZTY0IjsKCSAgV29ya2VyRXZlbnRbIkdldEluQ2hJS2V5Il0gPSAiZ2V0SW5DaElLZXkiOwoJICBXb3JrZXJFdmVudFsiRXhwbGljaXRIeWRyb2dlbnMiXSA9ICJjb252ZXJ0X2V4cGxpY2l0X2h5ZHJvZ2VucyI7Cgl9KShXb3JrZXJFdmVudCB8fCAoV29ya2VyRXZlbnQgPSB7fSkpOwoJdmFyIFN1cHBvcnRlZEZvcm1hdDsKCShmdW5jdGlvbiAoU3VwcG9ydGVkRm9ybWF0KSB7CgkgIFN1cHBvcnRlZEZvcm1hdFsiUnhuIl0gPSAicnhuZmlsZSI7CgkgIFN1cHBvcnRlZEZvcm1hdFsiTW9sIl0gPSAibW9sZmlsZSI7CgkgIFN1cHBvcnRlZEZvcm1hdFsiU21pbGVzIl0gPSAic21pbGVzIjsKCSAgU3VwcG9ydGVkRm9ybWF0WyJTbWFydHMiXSA9ICJzbWFydHMiOwoJICBTdXBwb3J0ZWRGb3JtYXRbIkNNTCJdID0gImNtbCI7CgkgIFN1cHBvcnRlZEZvcm1hdFsiSW5DaEkiXSA9ICJpbmNoaSI7CgkgIFN1cHBvcnRlZEZvcm1hdFsiSW5DaElBdXhJbmZvIl0gPSAiaW5jaGktYXV4IjsKCSAgU3VwcG9ydGVkRm9ybWF0WyJJbkNoSUtleSJdID0gImluY2hpLWtleSI7CgkgIFN1cHBvcnRlZEZvcm1hdFsiS2V0Il0gPSAia2V0IjsKCSAgU3VwcG9ydGVkRm9ybWF0WyJDRFgiXSA9ICJjZHgiOwoJICBTdXBwb3J0ZWRGb3JtYXRbIkNEWE1MIl0gPSAiY2R4bWwiOwoJICBTdXBwb3J0ZWRGb3JtYXRbIlNERiJdID0gInNkZiI7CgkgIFN1cHBvcnRlZEZvcm1hdFsiRkFTVEEiXSA9ICJmYXN0YSI7CgkgIFN1cHBvcnRlZEZvcm1hdFsiU0VRVUVOQ0UiXSA9ICJzZXF1ZW5jZSI7CgkgIFN1cHBvcnRlZEZvcm1hdFsiU0VRVUVOQ0VfM19MRVRURVIiXSA9ICJwZXB0aWRlLXNlcXVlbmNlLTMtbGV0dGVyIjsKCSAgU3VwcG9ydGVkRm9ybWF0WyJJRFQiXSA9ICJpZHQiOwoJICBTdXBwb3J0ZWRGb3JtYXRbIkhFTE0iXSA9ICJoZWxtIjsKCSAgU3VwcG9ydGVkRm9ybWF0WyJSREYiXSA9ICJyZGYiOwoJfSkoU3VwcG9ydGVkRm9ybWF0IHx8IChTdXBwb3J0ZWRGb3JtYXQgPSB7fSkpOwoKCXZhciBlbXB0eSA9IHt9OwoKCXZhciBlbXB0eSQxID0gLyojX19QVVJFX18qL09iamVjdC5mcmVlemUoewoJCV9fcHJvdG9fXzogbnVsbCwKCQknZGVmYXVsdCc6IGVtcHR5Cgl9KTsKCgkvLyBDb3B5cmlnaHQgSm95ZW50LCBJbmMuIGFuZCBvdGhlciBOb2RlIGNvbnRyaWJ1dG9ycy4KCS8vCgkvLyBQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvbiBvYnRhaW5pbmcgYQoJLy8gY29weSBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZQoJLy8gIlNvZnR3YXJlIiksIHRvIGRlYWwgaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZwoJLy8gd2l0aG91dCBsaW1pdGF0aW9uIHRoZSByaWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLAoJLy8gZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGwgY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdAoJLy8gcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpcyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlCgkvLyBmb2xsb3dpbmcgY29uZGl0aW9uczoKCS8vCgkvLyBUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZSBpbmNsdWRlZAoJLy8gaW4gYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuCgkvLwoJLy8gVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEICJBUyBJUyIsIFdJVEhPVVQgV0FSUkFOVFkgT0YgQU5ZIEtJTkQsIEVYUFJFU1MKCS8vIE9SIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0YKCS8vIE1FUkNIQU5UQUJJTElUWSwgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4KCS8vIE5PIEVWRU5UIFNIQUxMIFRIRSBBVVRIT1JTIE9SIENPUFlSSUdIVCBIT0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZIENMQUlNLAoJLy8gREFNQUdFUyBPUiBPVEhFUiBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SCgkvLyBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSwgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFCgkvLyBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU4gVEhFIFNPRlRXQVJFLgoKCS8vIHJlc29sdmVzIC4gYW5kIC4uIGVsZW1lbnRzIGluIGEgcGF0aCBhcnJheSB3aXRoIGRpcmVjdG9yeSBuYW1lcyB0aGVyZQoJLy8gbXVzdCBiZSBubyBzbGFzaGVzLCBlbXB0eSBlbGVtZW50cywgb3IgZGV2aWNlIG5hbWVzIChjOlwpIGluIHRoZSBhcnJheQoJLy8gKHNvIGFsc28gbm8gbGVhZGluZyBhbmQgdHJhaWxpbmcgc2xhc2hlcyAtIGl0IGRvZXMgbm90IGRpc3Rpbmd1aXNoCgkvLyByZWxhdGl2ZSBhbmQgYWJzb2x1dGUgcGF0aHMpCglmdW5jdGlvbiBub3JtYWxpemVBcnJheShwYXJ0cywgYWxsb3dBYm92ZVJvb3QpIHsKCSAgLy8gaWYgdGhlIHBhdGggdHJpZXMgdG8gZ28gYWJvdmUgdGhlIHJvb3QsIGB1cGAgZW5kcyB1cCA+IDAKCSAgdmFyIHVwID0gMDsKCSAgZm9yICh2YXIgaSA9IHBhcnRzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7CgkgICAgdmFyIGxhc3QgPSBwYXJ0c1tpXTsKCSAgICBpZiAobGFzdCA9PT0gJy4nKSB7CgkgICAgICBwYXJ0cy5zcGxpY2UoaSwgMSk7CgkgICAgfSBlbHNlIGlmIChsYXN0ID09PSAnLi4nKSB7CgkgICAgICBwYXJ0cy5zcGxpY2UoaSwgMSk7CgkgICAgICB1cCsrOwoJICAgIH0gZWxzZSBpZiAodXApIHsKCSAgICAgIHBhcnRzLnNwbGljZShpLCAxKTsKCSAgICAgIHVwLS07CgkgICAgfQoJICB9CgoJICAvLyBpZiB0aGUgcGF0aCBpcyBhbGxvd2VkIHRvIGdvIGFib3ZlIHRoZSByb290LCByZXN0b3JlIGxlYWRpbmcgLi5zCgkgIGlmIChhbGxvd0Fib3ZlUm9vdCkgewoJICAgIGZvciAoOyB1cC0tOyB1cCkgewoJICAgICAgcGFydHMudW5zaGlmdCgnLi4nKTsKCSAgICB9CgkgIH0KCgkgIHJldHVybiBwYXJ0czsKCX0KCgkvLyBTcGxpdCBhIGZpbGVuYW1lIGludG8gW3Jvb3QsIGRpciwgYmFzZW5hbWUsIGV4dF0sIHVuaXggdmVyc2lvbgoJLy8gJ3Jvb3QnIGlzIGp1c3QgYSBzbGFzaCwgb3Igbm90aGluZy4KCXZhciBzcGxpdFBhdGhSZSA9CgkgICAgL14oXC8/fCkoW1xzXFNdKj8pKCg/OlwuezEsMn18W15cL10rP3wpKFwuW14uXC9dKnwpKSg/OltcL10qKSQvOwoJdmFyIHNwbGl0UGF0aCA9IGZ1bmN0aW9uKGZpbGVuYW1lKSB7CgkgIHJldHVybiBzcGxpdFBhdGhSZS5leGVjKGZpbGVuYW1lKS5zbGljZSgxKTsKCX07CgoJLy8gcGF0aC5yZXNvbHZlKFtmcm9tIC4uLl0sIHRvKQoJLy8gcG9zaXggdmVyc2lvbgoJZnVuY3Rpb24gcmVzb2x2ZSgpIHsKCSAgdmFyIHJlc29sdmVkUGF0aCA9ICcnLAoJICAgICAgcmVzb2x2ZWRBYnNvbHV0ZSA9IGZhbHNlOwoKCSAgZm9yICh2YXIgaSA9IGFyZ3VtZW50cy5sZW5ndGggLSAxOyBpID49IC0xICYmICFyZXNvbHZlZEFic29sdXRlOyBpLS0pIHsKCSAgICB2YXIgcGF0aCA9IChpID49IDApID8gYXJndW1lbnRzW2ldIDogJy8nOwoKCSAgICAvLyBTa2lwIGVtcHR5IGFuZCBpbnZhbGlkIGVudHJpZXMKCSAgICBpZiAodHlwZW9mIHBhdGggIT09ICdzdHJpbmcnKSB7CgkgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdBcmd1bWVudHMgdG8gcGF0aC5yZXNvbHZlIG11c3QgYmUgc3RyaW5ncycpOwoJICAgIH0gZWxzZSBpZiAoIXBhdGgpIHsKCSAgICAgIGNvbnRpbnVlOwoJICAgIH0KCgkgICAgcmVzb2x2ZWRQYXRoID0gcGF0aCArICcvJyArIHJlc29sdmVkUGF0aDsKCSAgICByZXNvbHZlZEFic29sdXRlID0gcGF0aC5jaGFyQXQoMCkgPT09ICcvJzsKCSAgfQoKCSAgLy8gQXQgdGhpcyBwb2ludCB0aGUgcGF0aCBzaG91bGQgYmUgcmVzb2x2ZWQgdG8gYSBmdWxsIGFic29sdXRlIHBhdGgsIGJ1dAoJICAvLyBoYW5kbGUgcmVsYXRpdmUgcGF0aHMgdG8gYmUgc2FmZSAobWlnaHQgaGFwcGVuIHdoZW4gcHJvY2Vzcy5jd2QoKSBmYWlscykKCgkgIC8vIE5vcm1hbGl6ZSB0aGUgcGF0aAoJICByZXNvbHZlZFBhdGggPSBub3JtYWxpemVBcnJheShmaWx0ZXIocmVzb2x2ZWRQYXRoLnNwbGl0KCcvJyksIGZ1bmN0aW9uKHApIHsKCSAgICByZXR1cm4gISFwOwoJICB9KSwgIXJlc29sdmVkQWJzb2x1dGUpLmpvaW4oJy8nKTsKCgkgIHJldHVybiAoKHJlc29sdmVkQWJzb2x1dGUgPyAnLycgOiAnJykgKyByZXNvbHZlZFBhdGgpIHx8ICcuJzsKCX0KCS8vIHBhdGgubm9ybWFsaXplKHBhdGgpCgkvLyBwb3NpeCB2ZXJzaW9uCglmdW5jdGlvbiBub3JtYWxpemUocGF0aCkgewoJICB2YXIgaXNQYXRoQWJzb2x1dGUgPSBpc0Fic29sdXRlKHBhdGgpLAoJICAgICAgdHJhaWxpbmdTbGFzaCA9IHN1YnN0cihwYXRoLCAtMSkgPT09ICcvJzsKCgkgIC8vIE5vcm1hbGl6ZSB0aGUgcGF0aAoJICBwYXRoID0gbm9ybWFsaXplQXJyYXkoZmlsdGVyKHBhdGguc3BsaXQoJy8nKSwgZnVuY3Rpb24ocCkgewoJICAgIHJldHVybiAhIXA7CgkgIH0pLCAhaXNQYXRoQWJzb2x1dGUpLmpvaW4oJy8nKTsKCgkgIGlmICghcGF0aCAmJiAhaXNQYXRoQWJzb2x1dGUpIHsKCSAgICBwYXRoID0gJy4nOwoJICB9CgkgIGlmIChwYXRoICYmIHRyYWlsaW5nU2xhc2gpIHsKCSAgICBwYXRoICs9ICcvJzsKCSAgfQoKCSAgcmV0dXJuIChpc1BhdGhBYnNvbHV0ZSA/ICcvJyA6ICcnKSArIHBhdGg7Cgl9CgkvLyBwb3NpeCB2ZXJzaW9uCglmdW5jdGlvbiBpc0Fic29sdXRlKHBhdGgpIHsKCSAgcmV0dXJuIHBhdGguY2hhckF0KDApID09PSAnLyc7Cgl9CgoJLy8gcG9zaXggdmVyc2lvbgoJZnVuY3Rpb24gam9pbigpIHsKCSAgdmFyIHBhdGhzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAwKTsKCSAgcmV0dXJuIG5vcm1hbGl6ZShmaWx0ZXIocGF0aHMsIGZ1bmN0aW9uKHAsIGluZGV4KSB7CgkgICAgaWYgKHR5cGVvZiBwICE9PSAnc3RyaW5nJykgewoJICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignQXJndW1lbnRzIHRvIHBhdGguam9pbiBtdXN0IGJlIHN0cmluZ3MnKTsKCSAgICB9CgkgICAgcmV0dXJuIHA7CgkgIH0pLmpvaW4oJy8nKSk7Cgl9CgoKCS8vIHBhdGgucmVsYXRpdmUoZnJvbSwgdG8pCgkvLyBwb3NpeCB2ZXJzaW9uCglmdW5jdGlvbiByZWxhdGl2ZShmcm9tLCB0bykgewoJICBmcm9tID0gcmVzb2x2ZShmcm9tKS5zdWJzdHIoMSk7CgkgIHRvID0gcmVzb2x2ZSh0bykuc3Vic3RyKDEpOwoKCSAgZnVuY3Rpb24gdHJpbShhcnIpIHsKCSAgICB2YXIgc3RhcnQgPSAwOwoJICAgIGZvciAoOyBzdGFydCA8IGFyci5sZW5ndGg7IHN0YXJ0KyspIHsKCSAgICAgIGlmIChhcnJbc3RhcnRdICE9PSAnJykgYnJlYWs7CgkgICAgfQoKCSAgICB2YXIgZW5kID0gYXJyLmxlbmd0aCAtIDE7CgkgICAgZm9yICg7IGVuZCA+PSAwOyBlbmQtLSkgewoJICAgICAgaWYgKGFycltlbmRdICE9PSAnJykgYnJlYWs7CgkgICAgfQoKCSAgICBpZiAoc3RhcnQgPiBlbmQpIHJldHVybiBbXTsKCSAgICByZXR1cm4gYXJyLnNsaWNlKHN0YXJ0LCBlbmQgLSBzdGFydCArIDEpOwoJICB9CgoJICB2YXIgZnJvbVBhcnRzID0gdHJpbShmcm9tLnNwbGl0KCcvJykpOwoJICB2YXIgdG9QYXJ0cyA9IHRyaW0odG8uc3BsaXQoJy8nKSk7CgoJICB2YXIgbGVuZ3RoID0gTWF0aC5taW4oZnJvbVBhcnRzLmxlbmd0aCwgdG9QYXJ0cy5sZW5ndGgpOwoJICB2YXIgc2FtZVBhcnRzTGVuZ3RoID0gbGVuZ3RoOwoJICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7CgkgICAgaWYgKGZyb21QYXJ0c1tpXSAhPT0gdG9QYXJ0c1tpXSkgewoJICAgICAgc2FtZVBhcnRzTGVuZ3RoID0gaTsKCSAgICAgIGJyZWFrOwoJICAgIH0KCSAgfQoKCSAgdmFyIG91dHB1dFBhcnRzID0gW107CgkgIGZvciAodmFyIGkgPSBzYW1lUGFydHNMZW5ndGg7IGkgPCBmcm9tUGFydHMubGVuZ3RoOyBpKyspIHsKCSAgICBvdXRwdXRQYXJ0cy5wdXNoKCcuLicpOwoJICB9CgoJICBvdXRwdXRQYXJ0cyA9IG91dHB1dFBhcnRzLmNvbmNhdCh0b1BhcnRzLnNsaWNlKHNhbWVQYXJ0c0xlbmd0aCkpOwoKCSAgcmV0dXJuIG91dHB1dFBhcnRzLmpvaW4oJy8nKTsKCX0KCgl2YXIgc2VwID0gJy8nOwoJdmFyIGRlbGltaXRlciA9ICc6JzsKCglmdW5jdGlvbiBkaXJuYW1lKHBhdGgpIHsKCSAgdmFyIHJlc3VsdCA9IHNwbGl0UGF0aChwYXRoKSwKCSAgICAgIHJvb3QgPSByZXN1bHRbMF0sCgkgICAgICBkaXIgPSByZXN1bHRbMV07CgoJICBpZiAoIXJvb3QgJiYgIWRpcikgewoJICAgIC8vIE5vIGRpcm5hbWUgd2hhdHNvZXZlcgoJICAgIHJldHVybiAnLic7CgkgIH0KCgkgIGlmIChkaXIpIHsKCSAgICAvLyBJdCBoYXMgYSBkaXJuYW1lLCBzdHJpcCB0cmFpbGluZyBzbGFzaAoJICAgIGRpciA9IGRpci5zdWJzdHIoMCwgZGlyLmxlbmd0aCAtIDEpOwoJICB9CgoJICByZXR1cm4gcm9vdCArIGRpcjsKCX0KCglmdW5jdGlvbiBiYXNlbmFtZShwYXRoLCBleHQpIHsKCSAgdmFyIGYgPSBzcGxpdFBhdGgocGF0aClbMl07CgkgIC8vIFRPRE86IG1ha2UgdGhpcyBjb21wYXJpc29uIGNhc2UtaW5zZW5zaXRpdmUgb24gd2luZG93cz8KCSAgaWYgKGV4dCAmJiBmLnN1YnN0cigtMSAqIGV4dC5sZW5ndGgpID09PSBleHQpIHsKCSAgICBmID0gZi5zdWJzdHIoMCwgZi5sZW5ndGggLSBleHQubGVuZ3RoKTsKCSAgfQoJICByZXR1cm4gZjsKCX0KCgoJZnVuY3Rpb24gZXh0bmFtZShwYXRoKSB7CgkgIHJldHVybiBzcGxpdFBhdGgocGF0aClbM107Cgl9Cgl2YXIgcGF0aCA9IHsKCSAgZXh0bmFtZTogZXh0bmFtZSwKCSAgYmFzZW5hbWU6IGJhc2VuYW1lLAoJICBkaXJuYW1lOiBkaXJuYW1lLAoJICBzZXA6IHNlcCwKCSAgZGVsaW1pdGVyOiBkZWxpbWl0ZXIsCgkgIHJlbGF0aXZlOiByZWxhdGl2ZSwKCSAgam9pbjogam9pbiwKCSAgaXNBYnNvbHV0ZTogaXNBYnNvbHV0ZSwKCSAgbm9ybWFsaXplOiBub3JtYWxpemUsCgkgIHJlc29sdmU6IHJlc29sdmUKCX07CglmdW5jdGlvbiBmaWx0ZXIgKHhzLCBmKSB7CgkgICAgaWYgKHhzLmZpbHRlcikgcmV0dXJuIHhzLmZpbHRlcihmKTsKCSAgICB2YXIgcmVzID0gW107CgkgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB4cy5sZW5ndGg7IGkrKykgewoJICAgICAgICBpZiAoZih4c1tpXSwgaSwgeHMpKSByZXMucHVzaCh4c1tpXSk7CgkgICAgfQoJICAgIHJldHVybiByZXM7Cgl9CgoJLy8gU3RyaW5nLnByb3RvdHlwZS5zdWJzdHIgLSBuZWdhdGl2ZSBpbmRleCBkb24ndCB3b3JrIGluIElFOAoJdmFyIHN1YnN0ciA9ICdhYicuc3Vic3RyKC0xKSA9PT0gJ2InID8KCSAgICBmdW5jdGlvbiAoc3RyLCBzdGFydCwgbGVuKSB7IHJldHVybiBzdHIuc3Vic3RyKHN0YXJ0LCBsZW4pIH0gOgoJICAgIGZ1bmN0aW9uIChzdHIsIHN0YXJ0LCBsZW4pIHsKCSAgICAgICAgaWYgKHN0YXJ0IDwgMCkgc3RhcnQgPSBzdHIubGVuZ3RoICsgc3RhcnQ7CgkgICAgICAgIHJldHVybiBzdHIuc3Vic3RyKHN0YXJ0LCBsZW4pOwoJICAgIH0KCTsKCgl2YXIgcGF0aCQxID0gLyojX19QVVJFX18qL09iamVjdC5mcmVlemUoewoJCV9fcHJvdG9fXzogbnVsbCwKCQlyZXNvbHZlOiByZXNvbHZlLAoJCW5vcm1hbGl6ZTogbm9ybWFsaXplLAoJCWlzQWJzb2x1dGU6IGlzQWJzb2x1dGUsCgkJam9pbjogam9pbiwKCQlyZWxhdGl2ZTogcmVsYXRpdmUsCgkJc2VwOiBzZXAsCgkJZGVsaW1pdGVyOiBkZWxpbWl0ZXIsCgkJZGlybmFtZTogZGlybmFtZSwKCQliYXNlbmFtZTogYmFzZW5hbWUsCgkJZXh0bmFtZTogZXh0bmFtZSwKCQknZGVmYXVsdCc6IHBhdGgKCX0pOwoKCXZhciByZXF1aXJlJCQyID0gLypAX19QVVJFX18qL2dldEF1Z21lbnRlZE5hbWVzcGFjZShlbXB0eSQxKTsKCgl2YXIgcmVxdWlyZSQkMSA9IC8qQF9fUFVSRV9fKi9nZXRBdWdtZW50ZWROYW1lc3BhY2UocGF0aCQxKTsKCgl2YXIgaW5kaWdvS2V0Y2hlciA9IGNyZWF0ZUNvbW1vbmpzTW9kdWxlKGZ1bmN0aW9uIChtb2R1bGUsIGV4cG9ydHMpIHsKCXZhciBNb2R1bGUgPSAoKCkgPT4gewoJICB2YXIgX3NjcmlwdE5hbWUgPSB0eXBlb2YgZG9jdW1lbnQgIT0gJ3VuZGVmaW5lZCcgPyBkb2N1bWVudC5jdXJyZW50U2NyaXB0Py5zcmMgOiB1bmRlZmluZWQ7CgkgIGlmICh0eXBlb2YgX19maWxlbmFtZSAhPSAndW5kZWZpbmVkJykgX3NjcmlwdE5hbWUgfHw9IF9fZmlsZW5hbWU7CgkgIHJldHVybiAoCglmdW5jdGlvbihtb2R1bGVBcmcgPSB7fSkgewoJICB2YXIgbW9kdWxlUnRuOwoKCXZhciBNb2R1bGU9T2JqZWN0LmFzc2lnbih7fSxtb2R1bGVBcmcpO3ZhciByZWFkeVByb21pc2VSZXNvbHZlLHJlYWR5UHJvbWlzZVJlamVjdDt2YXIgcmVhZHlQcm9taXNlPW5ldyBQcm9taXNlKChyZXNvbHZlLHJlamVjdCk9PntyZWFkeVByb21pc2VSZXNvbHZlPXJlc29sdmU7cmVhZHlQcm9taXNlUmVqZWN0PXJlamVjdDt9KTtbImdldEV4Y2VwdGlvbk1lc3NhZ2UiLCJpbmNyZW1lbnRFeGNlcHRpb25SZWZjb3VudCIsImRlY3JlbWVudEV4Y2VwdGlvblJlZmNvdW50IiwiX21lbW9yeSIsIl9fX2luZGlyZWN0X2Z1bmN0aW9uX3RhYmxlIiwiX2pzVGhyb3ciLCJfcHJpbnRfanNuIiwiX21haW4iLCJvblJ1bnRpbWVJbml0aWFsaXplZCJdLmZvckVhY2gocHJvcD0+e2lmKCFPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKHJlYWR5UHJvbWlzZSxwcm9wKSl7T2JqZWN0LmRlZmluZVByb3BlcnR5KHJlYWR5UHJvbWlzZSxwcm9wLHtnZXQ6KCk9PmFib3J0KCJZb3UgYXJlIGdldHRpbmcgIitwcm9wKyIgb24gdGhlIFByb21pc2Ugb2JqZWN0LCBpbnN0ZWFkIG9mIHRoZSBpbnN0YW5jZS4gVXNlIC50aGVuKCkgdG8gZ2V0IGNhbGxlZCBiYWNrIHdpdGggdGhlIGluc3RhbmNlLCBzZWUgdGhlIE1PRFVMQVJJWkUgZG9jcyBpbiBzcmMvc2V0dGluZ3MuanMiKSxzZXQ6KCk9PmFib3J0KCJZb3UgYXJlIHNldHRpbmcgIitwcm9wKyIgb24gdGhlIFByb21pc2Ugb2JqZWN0LCBpbnN0ZWFkIG9mIHRoZSBpbnN0YW5jZS4gVXNlIC50aGVuKCkgdG8gZ2V0IGNhbGxlZCBiYWNrIHdpdGggdGhlIGluc3RhbmNlLCBzZWUgdGhlIE1PRFVMQVJJWkUgZG9jcyBpbiBzcmMvc2V0dGluZ3MuanMiKX0pO319KTt2YXIgRU5WSVJPTk1FTlRfSVNfV0VCPXR5cGVvZiB3aW5kb3c9PSJvYmplY3QiO3ZhciBFTlZJUk9OTUVOVF9JU19XT1JLRVI9dHlwZW9mIGltcG9ydFNjcmlwdHM9PSJmdW5jdGlvbiI7dmFyIEVOVklST05NRU5UX0lTX05PREU9dHlwZW9mIHByb2Nlc3M9PSJvYmplY3QiJiZ0eXBlb2YgcHJvY2Vzcy52ZXJzaW9ucz09Im9iamVjdCImJnR5cGVvZiBwcm9jZXNzLnZlcnNpb25zLm5vZGU9PSJzdHJpbmciO3ZhciBFTlZJUk9OTUVOVF9JU19TSEVMTD0hRU5WSVJPTk1FTlRfSVNfV0VCJiYhRU5WSVJPTk1FTlRfSVNfTk9ERSYmIUVOVklST05NRU5UX0lTX1dPUktFUjtpZihNb2R1bGVbIkVOVklST05NRU5UIl0pe3Rocm93IG5ldyBFcnJvcigiTW9kdWxlLkVOVklST05NRU5UIGhhcyBiZWVuIGRlcHJlY2F0ZWQuIFRvIGZvcmNlIHRoZSBlbnZpcm9ubWVudCwgdXNlIHRoZSBFTlZJUk9OTUVOVCBjb21waWxlLXRpbWUgb3B0aW9uIChmb3IgZXhhbXBsZSwgLXNFTlZJUk9OTUVOVD13ZWIgb3IgLXNFTlZJUk9OTUVOVD1ub2RlKSIpfXZhciBtb2R1bGVPdmVycmlkZXM9T2JqZWN0LmFzc2lnbih7fSxNb2R1bGUpO3ZhciB0aGlzUHJvZ3JhbT0iLi90aGlzLnByb2dyYW0iO3ZhciBxdWl0Xz0oc3RhdHVzLHRvVGhyb3cpPT57dGhyb3cgdG9UaHJvd307dmFyIHNjcmlwdERpcmVjdG9yeT0iIjt2YXIgcmVhZF8scmVhZEFzeW5jLHJlYWRCaW5hcnk7aWYoRU5WSVJPTk1FTlRfSVNfTk9ERSl7aWYodHlwZW9mIHByb2Nlc3M9PSJ1bmRlZmluZWQifHwhcHJvY2Vzcy5yZWxlYXNlfHxwcm9jZXNzLnJlbGVhc2UubmFtZSE9PSJub2RlIil0aHJvdyBuZXcgRXJyb3IoIm5vdCBjb21waWxlZCBmb3IgdGhpcyBlbnZpcm9ubWVudCAoZGlkIHlvdSBidWlsZCB0byBIVE1MIGFuZCB0cnkgdG8gcnVuIGl0IG5vdCBvbiB0aGUgd2ViLCBvciBzZXQgRU5WSVJPTk1FTlQgdG8gc29tZXRoaW5nIC0gbGlrZSBub2RlIC0gYW5kIHJ1biBpdCBzb21lcGxhY2UgZWxzZSAtIGxpa2Ugb24gdGhlIHdlYj8pIik7dmFyIG5vZGVWZXJzaW9uPXByb2Nlc3MudmVyc2lvbnMubm9kZTt2YXIgbnVtZXJpY1ZlcnNpb249bm9kZVZlcnNpb24uc3BsaXQoIi4iKS5zbGljZSgwLDMpO251bWVyaWNWZXJzaW9uPW51bWVyaWNWZXJzaW9uWzBdKjFlNCtudW1lcmljVmVyc2lvblsxXSoxMDArbnVtZXJpY1ZlcnNpb25bMl0uc3BsaXQoIi0iKVswXSoxO2lmKG51bWVyaWNWZXJzaW9uPDE2ZTQpe3Rocm93IG5ldyBFcnJvcigiVGhpcyBlbXNjcmlwdGVuLWdlbmVyYXRlZCBjb2RlIHJlcXVpcmVzIG5vZGUgdjE2LjAuMCAoZGV0ZWN0ZWQgdiIrbm9kZVZlcnNpb24rIikiKX12YXIgZnM9cmVxdWlyZSQkMjt2YXIgbm9kZVBhdGg9cmVxdWlyZSQkMTtzY3JpcHREaXJlY3Rvcnk9X19kaXJuYW1lKyIvIjtyZWFkXz0oZmlsZW5hbWUsYmluYXJ5KT0+e2ZpbGVuYW1lPWlzRmlsZVVSSShmaWxlbmFtZSk/bmV3IFVSTChmaWxlbmFtZSk6bm9kZVBhdGgubm9ybWFsaXplKGZpbGVuYW1lKTtyZXR1cm4gZnMucmVhZEZpbGVTeW5jKGZpbGVuYW1lLGJpbmFyeT91bmRlZmluZWQ6InV0ZjgiKX07cmVhZEJpbmFyeT1maWxlbmFtZT0+e3ZhciByZXQ9cmVhZF8oZmlsZW5hbWUsdHJ1ZSk7aWYoIXJldC5idWZmZXIpe3JldD1uZXcgVWludDhBcnJheShyZXQpO31hc3NlcnQocmV0LmJ1ZmZlcik7cmV0dXJuIHJldH07cmVhZEFzeW5jPShmaWxlbmFtZSxvbmxvYWQsb25lcnJvcixiaW5hcnk9dHJ1ZSk9PntmaWxlbmFtZT1pc0ZpbGVVUkkoZmlsZW5hbWUpP25ldyBVUkwoZmlsZW5hbWUpOm5vZGVQYXRoLm5vcm1hbGl6ZShmaWxlbmFtZSk7ZnMucmVhZEZpbGUoZmlsZW5hbWUsYmluYXJ5P3VuZGVmaW5lZDoidXRmOCIsKGVycixkYXRhKT0+e2lmKGVycilvbmVycm9yKGVycik7ZWxzZSBvbmxvYWQoYmluYXJ5P2RhdGEuYnVmZmVyOmRhdGEpO30pO307aWYoIU1vZHVsZVsidGhpc1Byb2dyYW0iXSYmcHJvY2Vzcy5hcmd2Lmxlbmd0aD4xKXt0aGlzUHJvZ3JhbT1wcm9jZXNzLmFyZ3ZbMV0ucmVwbGFjZSgvXFwvZywiLyIpO31wcm9jZXNzLmFyZ3Yuc2xpY2UoMik7cXVpdF89KHN0YXR1cyx0b1Rocm93KT0+e3Byb2Nlc3MuZXhpdENvZGU9c3RhdHVzO3Rocm93IHRvVGhyb3d9O31lbHNlIGlmKEVOVklST05NRU5UX0lTX1NIRUxMKXtpZih0eXBlb2YgcHJvY2Vzcz09Im9iamVjdCImJnR5cGVvZiBjb21tb25qc1JlcXVpcmU9PT0iZnVuY3Rpb24ifHx0eXBlb2Ygd2luZG93PT0ib2JqZWN0Inx8dHlwZW9mIGltcG9ydFNjcmlwdHM9PSJmdW5jdGlvbiIpdGhyb3cgbmV3IEVycm9yKCJub3QgY29tcGlsZWQgZm9yIHRoaXMgZW52aXJvbm1lbnQgKGRpZCB5b3UgYnVpbGQgdG8gSFRNTCBhbmQgdHJ5IHRvIHJ1biBpdCBub3Qgb24gdGhlIHdlYiwgb3Igc2V0IEVOVklST05NRU5UIHRvIHNvbWV0aGluZyAtIGxpa2Ugbm9kZSAtIGFuZCBydW4gaXQgc29tZXBsYWNlIGVsc2UgLSBsaWtlIG9uIHRoZSB3ZWI/KSIpfWVsc2UgaWYoRU5WSVJPTk1FTlRfSVNfV0VCfHxFTlZJUk9OTUVOVF9JU19XT1JLRVIpe2lmKEVOVklST05NRU5UX0lTX1dPUktFUil7c2NyaXB0RGlyZWN0b3J5PXNlbGYubG9jYXRpb24uaHJlZjt9ZWxzZSBpZih0eXBlb2YgZG9jdW1lbnQhPSJ1bmRlZmluZWQiJiZkb2N1bWVudC5jdXJyZW50U2NyaXB0KXtzY3JpcHREaXJlY3Rvcnk9ZG9jdW1lbnQuY3VycmVudFNjcmlwdC5zcmM7fWlmKF9zY3JpcHROYW1lKXtzY3JpcHREaXJlY3Rvcnk9X3NjcmlwdE5hbWU7fWlmKHNjcmlwdERpcmVjdG9yeS5zdGFydHNXaXRoKCJibG9iOiIpKXtzY3JpcHREaXJlY3Rvcnk9IiI7fWVsc2Uge3NjcmlwdERpcmVjdG9yeT1zY3JpcHREaXJlY3Rvcnkuc3Vic3RyKDAsc2NyaXB0RGlyZWN0b3J5LnJlcGxhY2UoL1s/I10uKi8sIiIpLmxhc3RJbmRleE9mKCIvIikrMSk7fWlmKCEodHlwZW9mIHdpbmRvdz09Im9iamVjdCJ8fHR5cGVvZiBpbXBvcnRTY3JpcHRzPT0iZnVuY3Rpb24iKSl0aHJvdyBuZXcgRXJyb3IoIm5vdCBjb21waWxlZCBmb3IgdGhpcyBlbnZpcm9ubWVudCAoZGlkIHlvdSBidWlsZCB0byBIVE1MIGFuZCB0cnkgdG8gcnVuIGl0IG5vdCBvbiB0aGUgd2ViLCBvciBzZXQgRU5WSVJPTk1FTlQgdG8gc29tZXRoaW5nIC0gbGlrZSBub2RlIC0gYW5kIHJ1biBpdCBzb21lcGxhY2UgZWxzZSAtIGxpa2Ugb24gdGhlIHdlYj8pIik7e3JlYWRfPXVybD0+e3ZhciB4aHI9bmV3IFhNTEh0dHBSZXF1ZXN0O3hoci5vcGVuKCJHRVQiLHVybCxmYWxzZSk7eGhyLnNlbmQobnVsbCk7cmV0dXJuIHhoci5yZXNwb25zZVRleHR9O2lmKEVOVklST05NRU5UX0lTX1dPUktFUil7cmVhZEJpbmFyeT11cmw9Pnt2YXIgeGhyPW5ldyBYTUxIdHRwUmVxdWVzdDt4aHIub3BlbigiR0VUIix1cmwsZmFsc2UpO3hoci5yZXNwb25zZVR5cGU9ImFycmF5YnVmZmVyIjt4aHIuc2VuZChudWxsKTtyZXR1cm4gbmV3IFVpbnQ4QXJyYXkoeGhyLnJlc3BvbnNlKX07fXJlYWRBc3luYz0odXJsLG9ubG9hZCxvbmVycm9yKT0+e3ZhciB4aHI9bmV3IFhNTEh0dHBSZXF1ZXN0O3hoci5vcGVuKCJHRVQiLHVybCx0cnVlKTt4aHIucmVzcG9uc2VUeXBlPSJhcnJheWJ1ZmZlciI7eGhyLm9ubG9hZD0oKT0+e2lmKHhoci5zdGF0dXM9PTIwMHx8eGhyLnN0YXR1cz09MCYmeGhyLnJlc3BvbnNlKXtvbmxvYWQoeGhyLnJlc3BvbnNlKTtyZXR1cm59b25lcnJvcigpO307eGhyLm9uZXJyb3I9b25lcnJvcjt4aHIuc2VuZChudWxsKTt9O319ZWxzZSB7dGhyb3cgbmV3IEVycm9yKCJlbnZpcm9ubWVudCBkZXRlY3Rpb24gZXJyb3IiKX12YXIgb3V0PU1vZHVsZVsicHJpbnQiXXx8Y29uc29sZS5sb2cuYmluZChjb25zb2xlKTt2YXIgZXJyPU1vZHVsZVsicHJpbnRFcnIiXXx8Y29uc29sZS5lcnJvci5iaW5kKGNvbnNvbGUpO09iamVjdC5hc3NpZ24oTW9kdWxlLG1vZHVsZU92ZXJyaWRlcyk7bW9kdWxlT3ZlcnJpZGVzPW51bGw7Y2hlY2tJbmNvbWluZ01vZHVsZUFQSSgpO2lmKE1vZHVsZVsiYXJndW1lbnRzIl0pTW9kdWxlWyJhcmd1bWVudHMiXTtsZWdhY3lNb2R1bGVQcm9wKCJhcmd1bWVudHMiLCJhcmd1bWVudHNfIik7aWYoTW9kdWxlWyJ0aGlzUHJvZ3JhbSJdKXRoaXNQcm9ncmFtPU1vZHVsZVsidGhpc1Byb2dyYW0iXTtsZWdhY3lNb2R1bGVQcm9wKCJ0aGlzUHJvZ3JhbSIsInRoaXNQcm9ncmFtIik7aWYoTW9kdWxlWyJxdWl0Il0pcXVpdF89TW9kdWxlWyJxdWl0Il07bGVnYWN5TW9kdWxlUHJvcCgicXVpdCIsInF1aXRfIik7YXNzZXJ0KHR5cGVvZiBNb2R1bGVbIm1lbW9yeUluaXRpYWxpemVyUHJlZml4VVJMIl09PSJ1bmRlZmluZWQiLCJNb2R1bGUubWVtb3J5SW5pdGlhbGl6ZXJQcmVmaXhVUkwgb3B0aW9uIHdhcyByZW1vdmVkLCB1c2UgTW9kdWxlLmxvY2F0ZUZpbGUgaW5zdGVhZCIpO2Fzc2VydCh0eXBlb2YgTW9kdWxlWyJwdGhyZWFkTWFpblByZWZpeFVSTCJdPT0idW5kZWZpbmVkIiwiTW9kdWxlLnB0aHJlYWRNYWluUHJlZml4VVJMIG9wdGlvbiB3YXMgcmVtb3ZlZCwgdXNlIE1vZHVsZS5sb2NhdGVGaWxlIGluc3RlYWQiKTthc3NlcnQodHlwZW9mIE1vZHVsZVsiY2RJbml0aWFsaXplclByZWZpeFVSTCJdPT0idW5kZWZpbmVkIiwiTW9kdWxlLmNkSW5pdGlhbGl6ZXJQcmVmaXhVUkwgb3B0aW9uIHdhcyByZW1vdmVkLCB1c2UgTW9kdWxlLmxvY2F0ZUZpbGUgaW5zdGVhZCIpO2Fzc2VydCh0eXBlb2YgTW9kdWxlWyJmaWxlUGFja2FnZVByZWZpeFVSTCJdPT0idW5kZWZpbmVkIiwiTW9kdWxlLmZpbGVQYWNrYWdlUHJlZml4VVJMIG9wdGlvbiB3YXMgcmVtb3ZlZCwgdXNlIE1vZHVsZS5sb2NhdGVGaWxlIGluc3RlYWQiKTthc3NlcnQodHlwZW9mIE1vZHVsZVsicmVhZCJdPT0idW5kZWZpbmVkIiwiTW9kdWxlLnJlYWQgb3B0aW9uIHdhcyByZW1vdmVkIChtb2RpZnkgcmVhZF8gaW4gSlMpIik7YXNzZXJ0KHR5cGVvZiBNb2R1bGVbInJlYWRBc3luYyJdPT0idW5kZWZpbmVkIiwiTW9kdWxlLnJlYWRBc3luYyBvcHRpb24gd2FzIHJlbW92ZWQgKG1vZGlmeSByZWFkQXN5bmMgaW4gSlMpIik7YXNzZXJ0KHR5cGVvZiBNb2R1bGVbInJlYWRCaW5hcnkiXT09InVuZGVmaW5lZCIsIk1vZHVsZS5yZWFkQmluYXJ5IG9wdGlvbiB3YXMgcmVtb3ZlZCAobW9kaWZ5IHJlYWRCaW5hcnkgaW4gSlMpIik7YXNzZXJ0KHR5cGVvZiBNb2R1bGVbInNldFdpbmRvd1RpdGxlIl09PSJ1bmRlZmluZWQiLCJNb2R1bGUuc2V0V2luZG93VGl0bGUgb3B0aW9uIHdhcyByZW1vdmVkIChtb2RpZnkgZW1zY3JpcHRlbl9zZXRfd2luZG93X3RpdGxlIGluIEpTKSIpO2Fzc2VydCh0eXBlb2YgTW9kdWxlWyJUT1RBTF9NRU1PUlkiXT09InVuZGVmaW5lZCIsIk1vZHVsZS5UT1RBTF9NRU1PUlkgaGFzIGJlZW4gcmVuYW1lZCBNb2R1bGUuSU5JVElBTF9NRU1PUlkiKTtsZWdhY3lNb2R1bGVQcm9wKCJhc20iLCJ3YXNtRXhwb3J0cyIpO2xlZ2FjeU1vZHVsZVByb3AoInJlYWQiLCJyZWFkXyIpO2xlZ2FjeU1vZHVsZVByb3AoInJlYWRBc3luYyIsInJlYWRBc3luYyIpO2xlZ2FjeU1vZHVsZVByb3AoInJlYWRCaW5hcnkiLCJyZWFkQmluYXJ5Iik7bGVnYWN5TW9kdWxlUHJvcCgic2V0V2luZG93VGl0bGUiLCJzZXRXaW5kb3dUaXRsZSIpO2Fzc2VydCghRU5WSVJPTk1FTlRfSVNfU0hFTEwsInNoZWxsIGVudmlyb25tZW50IGRldGVjdGVkIGJ1dCBub3QgZW5hYmxlZCBhdCBidWlsZCB0aW1lLiAgQWRkIGBzaGVsbGAgdG8gYC1zRU5WSVJPTk1FTlRgIHRvIGVuYWJsZS4iKTt2YXIgd2FzbUJpbmFyeTtpZihNb2R1bGVbIndhc21CaW5hcnkiXSl3YXNtQmluYXJ5PU1vZHVsZVsid2FzbUJpbmFyeSJdO2xlZ2FjeU1vZHVsZVByb3AoIndhc21CaW5hcnkiLCJ3YXNtQmluYXJ5Iik7aWYodHlwZW9mIFdlYkFzc2VtYmx5IT0ib2JqZWN0Iil7ZXJyKCJubyBuYXRpdmUgd2FzbSBzdXBwb3J0IGRldGVjdGVkIik7fWZ1bmN0aW9uIGludEFycmF5RnJvbUJhc2U2NChzKXtpZih0eXBlb2YgRU5WSVJPTk1FTlRfSVNfTk9ERSE9InVuZGVmaW5lZCImJkVOVklST05NRU5UX0lTX05PREUpe3ZhciBidWY9QnVmZmVyLmZyb20ocywiYmFzZTY0Iik7cmV0dXJuIG5ldyBVaW50OEFycmF5KGJ1Zi5idWZmZXIsYnVmLmJ5dGVPZmZzZXQsYnVmLmxlbmd0aCl9dmFyIGRlY29kZWQ9YXRvYihzKTt2YXIgYnl0ZXM9bmV3IFVpbnQ4QXJyYXkoZGVjb2RlZC5sZW5ndGgpO2Zvcih2YXIgaT0wO2k8ZGVjb2RlZC5sZW5ndGg7KytpKXtieXRlc1tpXT1kZWNvZGVkLmNoYXJDb2RlQXQoaSk7fXJldHVybiBieXRlc31mdW5jdGlvbiB0cnlQYXJzZUFzRGF0YVVSSShmaWxlbmFtZSl7aWYoIWlzRGF0YVVSSShmaWxlbmFtZSkpe3JldHVybn1yZXR1cm4gaW50QXJyYXlGcm9tQmFzZTY0KGZpbGVuYW1lLnNsaWNlKGRhdGFVUklQcmVmaXgubGVuZ3RoKSl9dmFyIHdhc21NZW1vcnk7dmFyIEFCT1JUPWZhbHNlO3ZhciBFWElUU1RBVFVTO2Z1bmN0aW9uIGFzc2VydChjb25kaXRpb24sdGV4dCl7aWYoIWNvbmRpdGlvbil7YWJvcnQoIkFzc2VydGlvbiBmYWlsZWQiKyh0ZXh0PyI6ICIrdGV4dDoiIikpO319dmFyIEhFQVA4LEhFQVBVOCxIRUFQMTYsSEVBUFUxNixIRUFQMzIsSEVBUFUzMixIRUFQRjMyLEhFQVBGNjQ7ZnVuY3Rpb24gdXBkYXRlTWVtb3J5Vmlld3MoKXt2YXIgYj13YXNtTWVtb3J5LmJ1ZmZlcjtNb2R1bGVbIkhFQVA4Il09SEVBUDg9bmV3IEludDhBcnJheShiKTtNb2R1bGVbIkhFQVAxNiJdPUhFQVAxNj1uZXcgSW50MTZBcnJheShiKTtNb2R1bGVbIkhFQVBVOCJdPUhFQVBVOD1uZXcgVWludDhBcnJheShiKTtNb2R1bGVbIkhFQVBVMTYiXT1IRUFQVTE2PW5ldyBVaW50MTZBcnJheShiKTtNb2R1bGVbIkhFQVAzMiJdPUhFQVAzMj1uZXcgSW50MzJBcnJheShiKTtNb2R1bGVbIkhFQVBVMzIiXT1IRUFQVTMyPW5ldyBVaW50MzJBcnJheShiKTtNb2R1bGVbIkhFQVBGMzIiXT1IRUFQRjMyPW5ldyBGbG9hdDMyQXJyYXkoYik7TW9kdWxlWyJIRUFQRjY0Il09SEVBUEY2ND1uZXcgRmxvYXQ2NEFycmF5KGIpO31hc3NlcnQoIU1vZHVsZVsiU1RBQ0tfU0laRSJdLCJTVEFDS19TSVpFIGNhbiBubyBsb25nZXIgYmUgc2V0IGF0IHJ1bnRpbWUuICBVc2UgLXNTVEFDS19TSVpFIGF0IGxpbmsgdGltZSIpO2Fzc2VydCh0eXBlb2YgSW50MzJBcnJheSE9InVuZGVmaW5lZCImJnR5cGVvZiBGbG9hdDY0QXJyYXkhPT0idW5kZWZpbmVkIiYmSW50MzJBcnJheS5wcm90b3R5cGUuc3ViYXJyYXkhPXVuZGVmaW5lZCYmSW50MzJBcnJheS5wcm90b3R5cGUuc2V0IT11bmRlZmluZWQsIkpTIGVuZ2luZSBkb2VzIG5vdCBwcm92aWRlIGZ1bGwgdHlwZWQgYXJyYXkgc3VwcG9ydCIpO2Fzc2VydCghTW9kdWxlWyJ3YXNtTWVtb3J5Il0sIlVzZSBvZiBgd2FzbU1lbW9yeWAgZGV0ZWN0ZWQuICBVc2UgLXNJTVBPUlRFRF9NRU1PUlkgdG8gZGVmaW5lIHdhc21NZW1vcnkgZXh0ZXJuYWxseSIpO2Fzc2VydCghTW9kdWxlWyJJTklUSUFMX01FTU9SWSJdLCJEZXRlY3RlZCBydW50aW1lIElOSVRJQUxfTUVNT1JZIHNldHRpbmcuICBVc2UgLXNJTVBPUlRFRF9NRU1PUlkgdG8gZGVmaW5lIHdhc21NZW1vcnkgZHluYW1pY2FsbHkiKTtmdW5jdGlvbiB3cml0ZVN0YWNrQ29va2llKCl7dmFyIG1heD1fZW1zY3JpcHRlbl9zdGFja19nZXRfZW5kKCk7YXNzZXJ0KChtYXgmMyk9PTApO2lmKG1heD09MCl7bWF4Kz00O31IRUFQVTMyW21