UNPKG

ketcher-standalone

Version:
582 lines (512 loc) 9.56 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["CalculateMacromoleculeProperties"] = 13] = "CalculateMacromoleculeProperties"; })(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["CalculateMacromoleculeProperties"] = "calculateMacroProperties"; })(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["AXOLABS"] = "axo-labs"; SupportedFormat["HELM"] = "helm"; SupportedFormat["RDF"] = "rdf"; SupportedFormat["MonomerLibrary"] = "monomer-library"; })(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/IGQgOiB7CgkJCQllbnVtZXJhYmxlOiB0cnVlLAoJCQkJZ2V0OiBmdW5jdGlvbiAoKSB7CgkJCQkJcmV0dXJuIG5ba107CgkJCQl9CgkJCX0pOwoJCX0pOwoJCXJldHVybiBhOwoJfQoKCWZ1bmN0aW9uIGNvbW1vbmpzUmVxdWlyZSAoKSB7CgkJdGhyb3cgbmV3IEVycm9yKCdEeW5hbWljIHJlcXVpcmVzIGFyZSBub3QgY3VycmVudGx5IHN1cHBvcnRlZCBieSBAcm9sbHVwL3BsdWdpbi1jb21tb25qcycpOwoJfQoKCXZhciBfdHlwZW9mXzEgPSBjcmVhdGVDb21tb25qc01vZHVsZShmdW5jdGlvbiAobW9kdWxlKSB7CglmdW5jdGlvbiBfdHlwZW9mKG8pIHsKCSAgIkBiYWJlbC9oZWxwZXJzIC0gdHlwZW9mIjsKCgkgIHJldHVybiBtb2R1bGUuZXhwb3J0cyA9IF90eXBlb2YgPSAiZnVuY3Rpb24iID09IHR5cGVvZiBTeW1ib2wgJiYgInN5bWJvbCIgPT0gdHlwZW9mIFN5bWJvbC5pdGVyYXRvciA/IGZ1bmN0aW9uIChvKSB7CgkgICAgcmV0dXJuIHR5cGVvZiBvOwoJICB9IDogZnVuY3Rpb24gKG8pIHsKCSAgICByZXR1cm4gbyAmJiAiZnVuY3Rpb24iID09IHR5cGVvZiBTeW1ib2wgJiYgby5jb25zdHJ1Y3RvciA9PT0gU3ltYm9sICYmIG8gIT09IFN5bWJvbC5wcm90b3R5cGUgPyAic3ltYm9sIiA6IHR5cGVvZiBvOwoJICB9LCBtb2R1bGUuZXhwb3J0cy5fX2VzTW9kdWxlID0gdHJ1ZSwgbW9kdWxlLmV4cG9ydHNbImRlZmF1bHQiXSA9IG1vZHVsZS5leHBvcnRzLCBfdHlwZW9mKG8pOwoJfQoJbW9kdWxlLmV4cG9ydHMgPSBfdHlwZW9mLCBtb2R1bGUuZXhwb3J0cy5fX2VzTW9kdWxlID0gdHJ1ZSwgbW9kdWxlLmV4cG9ydHNbImRlZmF1bHQiXSA9IG1vZHVsZS5leHBvcnRzOwoJfSk7CgoJdmFyIHRvUHJpbWl0aXZlXzEgPSBjcmVhdGVDb21tb25qc01vZHVsZShmdW5jdGlvbiAobW9kdWxlKSB7Cgl2YXIgX3R5cGVvZiA9IF90eXBlb2ZfMVsiZGVmYXVsdCJdOwoJZnVuY3Rpb24gdG9QcmltaXRpdmUodCwgcikgewoJICBpZiAoIm9iamVjdCIgIT0gX3R5cGVvZih0KSB8fCAhdCkgcmV0dXJuIHQ7CgkgIHZhciBlID0gdFtTeW1ib2wudG9QcmltaXRpdmVdOwoJICBpZiAodm9pZCAwICE9PSBlKSB7CgkgICAgdmFyIGkgPSBlLmNhbGwodCwgciB8fCAiZGVmYXVsdCIpOwoJICAgIGlmICgib2JqZWN0IiAhPSBfdHlwZW9mKGkpKSByZXR1cm4gaTsKCSAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCJAQHRvUHJpbWl0aXZlIG11c3QgcmV0dXJuIGEgcHJpbWl0aXZlIHZhbHVlLiIpOwoJICB9CgkgIHJldHVybiAoInN0cmluZyIgPT09IHIgPyBTdHJpbmcgOiBOdW1iZXIpKHQpOwoJfQoJbW9kdWxlLmV4cG9ydHMgPSB0b1ByaW1pdGl2ZSwgbW9kdWxlLmV4cG9ydHMuX19lc01vZHVsZSA9IHRydWUsIG1vZHVsZS5leHBvcnRzWyJkZWZhdWx0Il0gPSBtb2R1bGUuZXhwb3J0czsKCX0pOwoKCXZhciB0b1Byb3BlcnR5S2V5XzEgPSBjcmVhdGVDb21tb25qc01vZHVsZShmdW5jdGlvbiAobW9kdWxlKSB7Cgl2YXIgX3R5cGVvZiA9IF90eXBlb2ZfMVsiZGVmYXVsdCJdOwoKCWZ1bmN0aW9uIHRvUHJvcGVydHlLZXkodCkgewoJICB2YXIgaSA9IHRvUHJpbWl0aXZlXzEodCwgInN0cmluZyIpOwoJICByZXR1cm4gInN5bWJvbCIgPT0gX3R5cGVvZihpKSA/IGkgOiBpICsgIiI7Cgl9Cgltb2R1bGUuZXhwb3J0cyA9IHRvUHJvcGVydHlLZXksIG1vZHVsZS5leHBvcnRzLl9fZXNNb2R1bGUgPSB0cnVlLCBtb2R1bGUuZXhwb3J0c1siZGVmYXVsdCJdID0gbW9kdWxlLmV4cG9ydHM7Cgl9KTsKCgl2YXIgZGVmaW5lUHJvcGVydHkgPSBjcmVhdGVDb21tb25qc01vZHVsZShmdW5jdGlvbiAobW9kdWxlKSB7CglmdW5jdGlvbiBfZGVmaW5lUHJvcGVydHkoZSwgciwgdCkgewoJICByZXR1cm4gKHIgPSB0b1Byb3BlcnR5S2V5XzEocikpIGluIGUgPyBPYmplY3QuZGVmaW5lUHJvcGVydHkoZSwgciwgewoJICAgIHZhbHVlOiB0LAoJICAgIGVudW1lcmFibGU6ICEwLAoJICAgIGNvbmZpZ3VyYWJsZTogITAsCgkgICAgd3JpdGFibGU6ICEwCgkgIH0pIDogZVtyXSA9IHQsIGU7Cgl9Cgltb2R1bGUuZXhwb3J0cyA9IF9kZWZpbmVQcm9wZXJ0eSwgbW9kdWxlLmV4cG9ydHMuX19lc01vZHVsZSA9IHRydWUsIG1vZHVsZS5leHBvcnRzWyJkZWZhdWx0Il0gPSBtb2R1bGUuZXhwb3J0czsKCX0pOwoKCXZhciBfZGVmaW5lUHJvcGVydHkgPSAvKkBfX1BVUkVfXyovZ2V0RGVmYXVsdEV4cG9ydEZyb21DanMoZGVmaW5lUHJvcGVydHkpOwoKCXZhciBhcnJheVdpdGhIb2xlcyA9IGNyZWF0ZUNvbW1vbmpzTW9kdWxlKGZ1bmN0aW9uIChtb2R1bGUpIHsKCWZ1bmN0aW9uIF9hcnJheVdpdGhIb2xlcyhyKSB7CgkgIGlmIChBcnJheS5pc0FycmF5KHIpKSByZXR1cm4gcjsKCX0KCW1vZHVsZS5leHBvcnRzID0gX2FycmF5V2l0aEhvbGVzLCBtb2R1bGUuZXhwb3J0cy5fX2VzTW9kdWxlID0gdHJ1ZSwgbW9kdWxlLmV4cG9ydHNbImRlZmF1bHQiXSA9IG1vZHVsZS5leHBvcnRzOwoJfSk7CgoJdmFyIGl0ZXJhYmxlVG9BcnJheUxpbWl0ID0gY3JlYXRlQ29tbW9uanNNb2R1bGUoZnVuY3Rpb24gKG1vZHVsZSkgewoJZnVuY3Rpb24gX2l0ZXJhYmxlVG9BcnJheUxpbWl0KHIsIGwpIHsKCSAgdmFyIHQgPSBudWxsID09IHIgPyBudWxsIDogInVuZGVmaW5lZCIgIT0gdHlwZW9mIFN5bWJvbCAmJiByW1N5bWJvbC5pdGVyYXRvcl0gfHwgclsiQEBpdGVyYXRvciJdOwoJICBpZiAobnVsbCAhPSB0KSB7CgkgICAgdmFyIGUsCgkgICAgICBuLAoJICAgICAgaSwKCSAgICAgIHUsCgkgICAgICBhID0gW10sCgkgICAgICBmID0gITAsCgkgICAgICBvID0gITE7CgkgICAgdHJ5IHsKCSAgICAgIGlmIChpID0gKHQgPSB0LmNhbGwocikpLm5leHQsIDAgPT09IGwpIHsKCSAgICAgICAgaWYgKE9iamVjdCh0KSAhPT0gdCkgcmV0dXJuOwoJICAgICAgICBmID0gITE7CgkgICAgICB9IGVsc2UgZm9yICg7ICEoZiA9IChlID0gaS5jYWxsKHQpKS5kb25lKSAmJiAoYS5wdXNoKGUudmFsdWUpLCBhLmxlbmd0aCAhPT0gbCk7IGYgPSAhMCk7CgkgICAgfSBjYXRjaCAocikgewoJICAgICAgbyA9ICEwLCBuID0gcjsKCSAgICB9IGZpbmFsbHkgewoJICAgICAgdHJ5IHsKCSAgICAgICAgaWYgKCFmICYmIG51bGwgIT0gdFsicmV0dXJuIl0gJiYgKHUgPSB0WyJyZXR1cm4iXSgpLCBPYmplY3QodSkgIT09IHUpKSByZXR1cm47CgkgICAgICB9IGZpbmFsbHkgewoJICAgICAgICBpZiAobykgdGhyb3cgbjsKCSAgICAgIH0KCSAgICB9CgkgICAgcmV0dXJuIGE7CgkgIH0KCX0KCW1vZHVsZS5leHBvcnRzID0gX2l0ZXJhYmxlVG9BcnJheUxpbWl0LCBtb2R1bGUuZXhwb3J0cy5fX2VzTW9kdWxlID0gdHJ1ZSwgbW9kdWxlLmV4cG9ydHNbImRlZmF1bHQiXSA9IG1vZHVsZS5leHBvcnRzOwoJfSk7CgoJdmFyIGFycmF5TGlrZVRvQXJyYXkgPSBjcmVhdGVDb21tb25qc01vZHVsZShmdW5jdGlvbiAobW9kdWxlKSB7CglmdW5jdGlvbiBfYXJyYXlMaWtlVG9BcnJheShyLCBhKSB7CgkgIChudWxsID09IGEgfHwgYSA+IHIubGVuZ3RoKSAmJiAoYSA9IHIubGVuZ3RoKTsKCSAgZm9yICh2YXIgZSA9IDAsIG4gPSBBcnJheShhKTsgZSA8IGE7IGUrKykgbltlXSA9IHJbZV07CgkgIHJldHVybiBuOwoJfQoJbW9kdWxlLmV4cG9ydHMgPSBfYXJyYXlMaWtlVG9BcnJheSwgbW9kdWxlLmV4cG9ydHMuX19lc01vZHVsZSA9IHRydWUsIG1vZHVsZS5leHBvcnRzWyJkZWZhdWx0Il0gPSBtb2R1bGUuZXhwb3J0czsKCX0pOwoKCXZhciB1bnN1cHBvcnRlZEl0ZXJhYmxlVG9BcnJheSA9IGNyZWF0ZUNvbW1vbmpzTW9kdWxlKGZ1bmN0aW9uIChtb2R1bGUpIHsKCWZ1bmN0aW9uIF91bnN1cHBvcnRlZEl0ZXJhYmxlVG9BcnJheShyLCBhKSB7CgkgIGlmIChyKSB7CgkgICAgaWYgKCJzdHJpbmciID09IHR5cGVvZiByKSByZXR1cm4gYXJyYXlMaWtlVG9BcnJheShyLCBhKTsKCSAgICB2YXIgdCA9IHt9LnRvU3RyaW5nLmNhbGwocikuc2xpY2UoOCwgLTEpOwoJICAgIHJldHVybiAiT2JqZWN0IiA9PT0gdCAmJiByLmNvbnN0cnVjdG9yICYmICh0ID0gci5jb25zdHJ1Y3Rvci5uYW1lKSwgIk1hcCIgPT09IHQgfHwgIlNldCIgPT09IHQgPyBBcnJheS5mcm9tKHIpIDogIkFyZ3VtZW50cyIgPT09IHQgfHwgL14oPzpVaXxJKW50KD86OHwxNnwzMikoPzpDbGFtcGVkKT9BcnJheSQvLnRlc3QodCkgPyBhcnJheUxpa2VUb0FycmF5KHIsIGEpIDogdm9pZCAwOwoJICB9Cgl9Cgltb2R1bGUuZXhwb3J0cyA9IF91bnN1cHBvcnRlZEl0ZXJhYmxlVG9BcnJheSwgbW9kdWxlLmV4cG9ydHMuX19lc01vZHVsZSA9IHRydWUsIG1vZHVsZS5leHBvcnRzWyJkZWZhdWx0Il0gPSBtb2R1bGUuZXhwb3J0czsKCX0pOwoKCXZhciBub25JdGVyYWJsZVJlc3QgPSBjcmVhdGVDb21tb25qc01vZHVsZShmdW5jdGlvbiAobW9kdWxlKSB7CglmdW5jdGlvbiBfbm9uSXRlcmFibGVSZXN0KCkgewoJICB0aHJvdyBuZXcgVHlwZUVycm9yKCJJbnZhbGlkIGF0dGVtcHQgdG8gZGVzdHJ1Y3R1cmUgbm9uLWl0ZXJhYmxlIGluc3RhbmNlLlxuSW4gb3JkZXIgdG8gYmUgaXRlcmFibGUsIG5vbi1hcnJheSBvYmplY3RzIG11c3QgaGF2ZSBhIFtTeW1ib2wuaXRlcmF0b3JdKCkgbWV0aG9kLiIpOwoJfQoJbW9kdWxlLmV4cG9ydHMgPSBfbm9uSXRlcmFibGVSZXN0LCBtb2R1bGUuZXhwb3J0cy5fX2VzTW9kdWxlID0gdHJ1ZSwgbW9kdWxlLmV4cG9ydHNbImRlZmF1bHQiXSA9IG1vZHVsZS5leHBvcnRzOwoJfSk7CgoJdmFyIHNsaWNlZFRvQXJyYXkgPSBjcmVhdGVDb21tb25qc01vZHVsZShmdW5jdGlvbiAobW9kdWxlKSB7CglmdW5jdGlvbiBfc2xpY2VkVG9BcnJheShyLCBlKSB7CgkgIHJldHVybiBhcnJheVdpdGhIb2xlcyhyKSB8fCBpdGVyYWJsZVRvQXJyYXlMaW1pdChyLCBlKSB8fCB1bnN1cHBvcnRlZEl0ZXJhYmxlVG9BcnJheShyLCBlKSB8fCBub25JdGVyYWJsZVJlc3QoKTsKCX0KCW1vZHVsZS5leHBvcnRzID0gX3NsaWNlZFRvQXJyYXksIG1vZHVsZS5leHBvcnRzLl9fZXNNb2R1bGUgPSB0cnVlLCBtb2R1bGUuZXhwb3J0c1siZGVmYXVsdCJdID0gbW9kdWxlLmV4cG9ydHM7Cgl9KTsKCgl2YXIgX3NsaWNlZFRvQXJyYXkgPSAvKkBfX1BVUkVfXyovZ2V0RGVmYXVsdEV4cG9ydEZyb21DanMoc2xpY2VkVG9BcnJheSk7CgoJdmFyIENvbW1hbmQ7CgkoZnVuY3Rpb24gKENvbW1hbmQpIHsKCSAgQ29tbWFuZFtDb21tYW5kWyJJbmZvIl0gPSAwXSA9ICJJbmZvIjsKCSAgQ29tbWFuZFtDb21tYW5kWyJDb252ZXJ0Il0gPSAxXSA9ICJDb252ZXJ0IjsKCSAgQ29tbWFuZFtDb21tYW5kWyJMYXlvdXQiXSA9IDJdID0gIkxheW91dCI7CgkgIENvbW1hbmRbQ29tbWFuZFsiQ2xlYW4iXSA9IDNdID0gIkNsZWFuIjsKCSAgQ29tbWFuZFtDb21tYW5kWyJBcm9tYXRpemUiXSA9IDRdID0gIkFyb21hdGl6ZSI7CgkgIENvbW1hbmRbQ29tbWFuZFsiRGVhcm9tYXRpemUiXSA9IDVdID0gIkRlYXJvbWF0aXplIjsKCSAgQ29tbWFuZFtDb21tYW5kWyJDYWxjdWxhdGVDaXAiXSA9IDZdID0gIkNhbGN1bGF0ZUNpcCI7CgkgIENvbW1hbmRbQ29tbWFuZFsiQXV0b21hcCJdID0gN10gPSAiQXV0b21hcCI7CgkgIENvbW1hbmRbQ29tbWFuZFsiQ2hlY2siXSA9IDhdID0gIkNoZWNrIjsKCSAgQ29tbWFuZFtDb21tYW5kWyJDYWxjdWxhdGUiXSA9IDldID0gIkNhbGN1bGF0ZSI7CgkgIENvbW1hbmRbQ29tbWFuZFsiR2VuZXJhdGVJbWFnZUFzQmFzZTY0Il0gPSAxMF0gPSAiR2VuZXJhdGVJbWFnZUFzQmFzZTY0IjsKCSAgQ29tbWFuZFtDb21tYW5kWyJHZXRJbkNoSUtleSJdID0gMTFdID0gIkdldEluQ2hJS2V5IjsKCSAgQ29tbWFuZFtDb21tYW5kWyJFeHBsaWNpdEh5ZHJvZ2VucyJdID0gMTJdID0gIkV4cGxpY2l0SHlkcm9nZW5zIjsKCSAgQ29tbWFuZFtDb21tYW5kWyJDYWxjdWxhdGVNYWNyb21vbGVjdWxlUHJvcGVydGllcyJdID0gMTNdID0gIkNhbGN1bGF0ZU1hY3JvbW9sZWN1bGVQcm9wZXJ0aWVzIjsKCX0pKENvbW1hbmQgfHwgKENvbW1hbmQgPSB7fSkpOwoJdmFyIFdvcmtlckV2ZW50OwoJKGZ1bmN0aW9uIChXb3JrZXJFdmVudCkgewoJICBXb3JrZXJFdmVudFsiSW5mbyJdID0gImluZm8iOwoJICBXb3JrZXJFdmVudFsiQ29udmVydCJdID0gImNvbnZlcnQiOwoJICBXb3JrZXJFdmVudFsiTGF5b3V0Il0gPSAibGF5b3V0IjsKCSAgV29ya2VyRXZlbnRbIkNsZWFuIl0gPSAiY2xlYW4iOwoJICBXb3JrZXJFdmVudFsiQXJvbWF0aXplIl0gPSAiYXJvbWF0aXplIjsKCSAgV29ya2VyRXZlbnRbIkRlYXJvbWF0aXplIl0gPSAiZGVhcm9tYXRpemUiOwoJICBXb3JrZXJFdmVudFsiQ2FsY3VsYXRlQ2lwIl0gPSAiY2FsY3VsYXRlQ2lwIjsKCSAgV29ya2VyRXZlbnRbIkF1dG9tYXAiXSA9ICJhdXRvbWFwIjsKCSAgV29ya2VyRXZlbnRbIkNoZWNrIl0gPSAiY2hlY2siOwoJICBXb3JrZXJFdmVudFsiQ2FsY3VsYXRlIl0gPSAiY2FsY3VsYXRlIjsKCSAgV29ya2VyRXZlbnRbIkdlbmVyYXRlSW1hZ2VBc0Jhc2U2NCJdID0gImdlbmVyYXRlSW1hZ2VBc0Jhc2U2NCI7CgkgIFdvcmtlckV2ZW50WyJHZXRJbkNoSUtleSJdID0gImdldEluQ2hJS2V5IjsKCSAgV29ya2VyRXZlbnRbIkV4cGxpY2l0SHlkcm9nZW5zIl0gPSAiY29udmVydF9leHBsaWNpdF9oeWRyb2dlbnMiOwoJICBXb3JrZXJFdmVudFsiQ2FsY3VsYXRlTWFjcm9tb2xlY3VsZVByb3BlcnRpZXMiXSA9ICJjYWxjdWxhdGVNYWNyb1Byb3BlcnRpZXMiOwoJfSkoV29ya2VyRXZlbnQgfHwgKFdvcmtlckV2ZW50ID0ge30pKTsKCXZhciBTdXBwb3J0ZWRGb3JtYXQ7CgkoZnVuY3Rpb24gKFN1cHBvcnRlZEZvcm1hdCkgewoJICBTdXBwb3J0ZWRGb3JtYXRbIlJ4biJdID0gInJ4bmZpbGUiOwoJICBTdXBwb3J0ZWRGb3JtYXRbIk1vbCJdID0gIm1vbGZpbGUiOwoJICBTdXBwb3J0ZWRGb3JtYXRbIlNtaWxlcyJdID0gInNtaWxlcyI7CgkgIFN1cHBvcnRlZEZvcm1hdFsiU21hcnRzIl0gPSAic21hcnRzIjsKCSAgU3VwcG9ydGVkRm9ybWF0WyJDTUwiXSA9ICJjbWwiOwoJICBTdXBwb3J0ZWRGb3JtYXRbIkluQ2hJIl0gPSAiaW5jaGkiOwoJICBTdXBwb3J0ZWRGb3JtYXRbIkluQ2hJQXV4SW5mbyJdID0gImluY2hpLWF1eCI7CgkgIFN1cHBvcnRlZEZvcm1hdFsiSW5DaElLZXkiXSA9ICJpbmNoaS1rZXkiOwoJICBTdXBwb3J0ZWRGb3JtYXRbIktldCJdID0gImtldCI7CgkgIFN1cHBvcnRlZEZvcm1hdFsiQ0RYIl0gPSAiY2R4IjsKCSAgU3VwcG9ydGVkRm9ybWF0WyJDRFhNTCJdID0gImNkeG1sIjsKCSAgU3VwcG9ydGVkRm9ybWF0WyJTREYiXSA9ICJzZGYiOwoJICBTdXBwb3J0ZWRGb3JtYXRbIkZBU1RBIl0gPSAiZmFzdGEiOwoJICBTdXBwb3J0ZWRGb3JtYXRbIlNFUVVFTkNFIl0gPSAic2VxdWVuY2UiOwoJICBTdXBwb3J0ZWRGb3JtYXRbIlNFUVVFTkNFXzNfTEVUVEVSIl0gPSAicGVwdGlkZS1zZXF1ZW5jZS0zLWxldHRlciI7CgkgIFN1cHBvcnRlZEZvcm1hdFsiSURUIl0gPSAiaWR0IjsKCSAgU3VwcG9ydGVkRm9ybWF0WyJBWE9MQUJTIl0gPSAiYXhvLWxhYnMiOwoJICBTdXBwb3J0ZWRGb3JtYXRbIkhFTE0iXSA9ICJoZWxtIjsKCSAgU3VwcG9ydGVkRm9ybWF0WyJSREYiXSA9ICJyZGYiOwoJICBTdXBwb3J0ZWRGb3JtYXRbIk1vbm9tZXJMaWJyYXJ5Il0gPSAibW9ub21lci1saWJyYXJ5IjsKCX0pKFN1cHBvcnRlZEZvcm1hdCB8fCAoU3VwcG9ydGVkRm9ybWF0ID0ge30pKTsKCgl2YXIgZW1wdHkgPSB7fTsKCgl2YXIgZW1wdHkkMSA9IC8qI19fUFVSRV9fKi9PYmplY3QuZnJlZXplKHsKCQlfX3Byb3RvX186IG51bGwsCgkJJ2RlZmF1bHQnOiBlbXB0eQoJfSk7CgoJLy8gQ29weXJpZ2h0IEpveWVudCwgSW5jLiBhbmQgb3RoZXIgTm9kZSBjb250cmlidXRvcnMuCgkvLwoJLy8gUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEKCS8vIGNvcHkgb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUKCS8vICJTb2Z0d2FyZSIpLCB0byBkZWFsIGluIHRoZSBTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcKCS8vIHdpdGhvdXQgbGltaXRhdGlvbiB0aGUgcmlnaHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwKCS8vIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQKCS8vIHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXMgZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZQoJLy8gZm9sbG93aW5nIGNvbmRpdGlvbnM6CgkvLwoJLy8gVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQKCS8vIGluIGFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlIFNvZnR3YXJlLgoJLy8KCS8vIFRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCAiQVMgSVMiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTCgkvLyBPUiBJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GCgkvLyBNRVJDSEFOVEFCSUxJVFksIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOCgkvLyBOTyBFVkVOVCBTSEFMTCBUSEUgQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwKCS8vIERBTUFHRVMgT1IgT1RIRVIgTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUgoJLy8gT1RIRVJXSVNFLCBBUklTSU5HIEZST00sIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRQoJLy8gVVNFIE9SIE9USEVSIERFQUxJTkdTIElOIFRIRSBTT0ZUV0FSRS4KCgkvLyByZXNvbHZlcyAuIGFuZCAuLiBlbGVtZW50cyBpbiBhIHBhdGggYXJyYXkgd2l0aCBkaXJlY3RvcnkgbmFtZXMgdGhlcmUKCS8vIG11c3QgYmUgbm8gc2xhc2hlcywgZW1wdHkgZWxlbWVudHMsIG9yIGRldmljZSBuYW1lcyAoYzpcKSBpbiB0aGUgYXJyYXkKCS8vIChzbyBhbHNvIG5vIGxlYWRpbmcgYW5kIHRyYWlsaW5nIHNsYXNoZXMgLSBpdCBkb2VzIG5vdCBkaXN0aW5ndWlzaAoJLy8gcmVsYXRpdmUgYW5kIGFic29sdXRlIHBhdGhzKQoJZnVuY3Rpb24gbm9ybWFsaXplQXJyYXkocGFydHMsIGFsbG93QWJvdmVSb290KSB7CgkgIC8vIGlmIHRoZSBwYXRoIHRyaWVzIHRvIGdvIGFib3ZlIHRoZSByb290LCBgdXBgIGVuZHMgdXAgPiAwCgkgIHZhciB1cCA9IDA7CgkgIGZvciAodmFyIGkgPSBwYXJ0cy5sZW5ndGggLSAxOyBpID49IDA7IGktLSkgewoJICAgIHZhciBsYXN0ID0gcGFydHNbaV07CgkgICAgaWYgKGxhc3QgPT09ICcuJykgewoJICAgICAgcGFydHMuc3BsaWNlKGksIDEpOwoJICAgIH0gZWxzZSBpZiAobGFzdCA9PT0gJy4uJykgewoJICAgICAgcGFydHMuc3BsaWNlKGksIDEpOwoJICAgICAgdXArKzsKCSAgICB9IGVsc2UgaWYgKHVwKSB7CgkgICAgICBwYXJ0cy5zcGxpY2UoaSwgMSk7CgkgICAgICB1cC0tOwoJICAgIH0KCSAgfQoKCSAgLy8gaWYgdGhlIHBhdGggaXMgYWxsb3dlZCB0byBnbyBhYm92ZSB0aGUgcm9vdCwgcmVzdG9yZSBsZWFkaW5nIC4ucwoJICBpZiAoYWxsb3dBYm92ZVJvb3QpIHsKCSAgICBmb3IgKDsgdXAtLTsgdXApIHsKCSAgICAgIHBhcnRzLnVuc2hpZnQoJy4uJyk7CgkgICAgfQoJICB9CgoJICByZXR1cm4gcGFydHM7Cgl9CgoJLy8gU3BsaXQgYSBmaWxlbmFtZSBpbnRvIFtyb290LCBkaXIsIGJhc2VuYW1lLCBleHRdLCB1bml4IHZlcnNpb24KCS8vICdyb290JyBpcyBqdXN0IGEgc2xhc2gsIG9yIG5vdGhpbmcuCgl2YXIgc3BsaXRQYXRoUmUgPQoJICAgIC9eKFwvP3wpKFtcc1xTXSo/KSgoPzpcLnsxLDJ9fFteXC9dKz98KShcLlteLlwvXSp8KSkoPzpbXC9dKikkLzsKCXZhciBzcGxpdFBhdGggPSBmdW5jdGlvbihmaWxlbmFtZSkgewoJICByZXR1cm4gc3BsaXRQYXRoUmUuZXhlYyhmaWxlbmFtZSkuc2xpY2UoMSk7Cgl9OwoKCS8vIHBhdGgucmVzb2x2ZShbZnJvbSAuLi5dLCB0bykKCS8vIHBvc2l4IHZlcnNpb24KCWZ1bmN0aW9uIHJlc29sdmUoKSB7CgkgIHZhciByZXNvbHZlZFBhdGggPSAnJywKCSAgICAgIHJlc29sdmVkQWJzb2x1dGUgPSBmYWxzZTsKCgkgIGZvciAodmFyIGkgPSBhcmd1bWVudHMubGVuZ3RoIC0gMTsgaSA+PSAtMSAmJiAhcmVzb2x2ZWRBYnNvbHV0ZTsgaS0tKSB7CgkgICAgdmFyIHBhdGggPSAoaSA+PSAwKSA/IGFyZ3VtZW50c1tpXSA6ICcvJzsKCgkgICAgLy8gU2tpcCBlbXB0eSBhbmQgaW52YWxpZCBlbnRyaWVzCgkgICAgaWYgKHR5cGVvZiBwYXRoICE9PSAnc3RyaW5nJykgewoJICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignQXJndW1lbnRzIHRvIHBhdGgucmVzb2x2ZSBtdXN0IGJlIHN0cmluZ3MnKTsKCSAgICB9IGVsc2UgaWYgKCFwYXRoKSB7CgkgICAgICBjb250aW51ZTsKCSAgICB9CgoJICAgIHJlc29sdmVkUGF0aCA9IHBhdGggKyAnLycgKyByZXNvbHZlZFBhdGg7CgkgICAgcmVzb2x2ZWRBYnNvbHV0ZSA9IHBhdGguY2hhckF0KDApID09PSAnLyc7CgkgIH0KCgkgIC8vIEF0IHRoaXMgcG9pbnQgdGhlIHBhdGggc2hvdWxkIGJlIHJlc29sdmVkIHRvIGEgZnVsbCBhYnNvbHV0ZSBwYXRoLCBidXQKCSAgLy8gaGFuZGxlIHJlbGF0aXZlIHBhdGhzIHRvIGJlIHNhZmUgKG1pZ2h0IGhhcHBlbiB3aGVuIHByb2Nlc3MuY3dkKCkgZmFpbHMpCgoJICAvLyBOb3JtYWxpemUgdGhlIHBhdGgKCSAgcmVzb2x2ZWRQYXRoID0gbm9ybWFsaXplQXJyYXkoZmlsdGVyKHJlc29sdmVkUGF0aC5zcGxpdCgnLycpLCBmdW5jdGlvbihwKSB7CgkgICAgcmV0dXJuICEhcDsKCSAgfSksICFyZXNvbHZlZEFic29sdXRlKS5qb2luKCcvJyk7CgoJICByZXR1cm4gKChyZXNvbHZlZEFic29sdXRlID8gJy8nIDogJycpICsgcmVzb2x2ZWRQYXRoKSB8fCAnLic7Cgl9CgkvLyBwYXRoLm5vcm1hbGl6ZShwYXRoKQoJLy8gcG9zaXggdmVyc2lvbgoJZnVuY3Rpb24gbm9ybWFsaXplKHBhdGgpIHsKCSAgdmFyIGlzUGF0aEFic29sdXRlID0gaXNBYnNvbHV0ZShwYXRoKSwKCSAgICAgIHRyYWlsaW5nU2xhc2ggPSBzdWJzdHIocGF0aCwgLTEpID09PSAnLyc7CgoJICAvLyBOb3JtYWxpemUgdGhlIHBhdGgKCSAgcGF0aCA9IG5vcm1hbGl6ZUFycmF5KGZpbHRlcihwYXRoLnNwbGl0KCcvJyksIGZ1bmN0aW9uKHApIHsKCSAgICByZXR1cm4gISFwOwoJICB9KSwgIWlzUGF0aEFic29sdXRlKS5qb2luKCcvJyk7CgoJICBpZiAoIXBhdGggJiYgIWlzUGF0aEFic29sdXRlKSB7CgkgICAgcGF0aCA9ICcuJzsKCSAgfQoJICBpZiAocGF0aCAmJiB0cmFpbGluZ1NsYXNoKSB7CgkgICAgcGF0aCArPSAnLyc7CgkgIH0KCgkgIHJldHVybiAoaXNQYXRoQWJzb2x1dGUgPyAnLycgOiAnJykgKyBwYXRoOwoJfQoJLy8gcG9zaXggdmVyc2lvbgoJZnVuY3Rpb24gaXNBYnNvbHV0ZShwYXRoKSB7CgkgIHJldHVybiBwYXRoLmNoYXJBdCgwKSA9PT0gJy8nOwoJfQoKCS8vIHBvc2l4IHZlcnNpb24KCWZ1bmN0aW9uIGpvaW4oKSB7CgkgIHZhciBwYXRocyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywgMCk7CgkgIHJldHVybiBub3JtYWxpemUoZmlsdGVyKHBhdGhzLCBmdW5jdGlvbihwLCBpbmRleCkgewoJICAgIGlmICh0eXBlb2YgcCAhPT0gJ3N0cmluZycpIHsKCSAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0FyZ3VtZW50cyB0byBwYXRoLmpvaW4gbXVzdCBiZSBzdHJpbmdzJyk7CgkgICAgfQoJICAgIHJldHVybiBwOwoJICB9KS5qb2luKCcvJykpOwoJfQoKCgkvLyBwYXRoLnJlbGF0aXZlKGZyb20sIHRvKQoJLy8gcG9zaXggdmVyc2lvbgoJZnVuY3Rpb24gcmVsYXRpdmUoZnJvbSwgdG8pIHsKCSAgZnJvbSA9IHJlc29sdmUoZnJvbSkuc3Vic3RyKDEpOwoJICB0byA9IHJlc29sdmUodG8pLnN1YnN0cigxKTsKCgkgIGZ1bmN0aW9uIHRyaW0oYXJyKSB7CgkgICAgdmFyIHN0YXJ0ID0gMDsKCSAgICBmb3IgKDsgc3RhcnQgPCBhcnIubGVuZ3RoOyBzdGFydCsrKSB7CgkgICAgICBpZiAoYXJyW3N0YXJ0XSAhPT0gJycpIGJyZWFrOwoJICAgIH0KCgkgICAgdmFyIGVuZCA9IGFyci5sZW5ndGggLSAxOwoJICAgIGZvciAoOyBlbmQgPj0gMDsgZW5kLS0pIHsKCSAgICAgIGlmIChhcnJbZW5kXSAhPT0gJycpIGJyZWFrOwoJICAgIH0KCgkgICAgaWYgKHN0YXJ0ID4gZW5kKSByZXR1cm4gW107CgkgICAgcmV0dXJuIGFyci5zbGljZShzdGFydCwgZW5kIC0gc3RhcnQgKyAxKTsKCSAgfQoKCSAgdmFyIGZyb21QYXJ0cyA9IHRyaW0oZnJvbS5zcGxpdCgnLycpKTsKCSAgdmFyIHRvUGFydHMgPSB0cmltKHRvLnNwbGl0KCcvJykpOwoKCSAgdmFyIGxlbmd0aCA9IE1hdGgubWluKGZyb21QYXJ0cy5sZW5ndGgsIHRvUGFydHMubGVuZ3RoKTsKCSAgdmFyIHNhbWVQYXJ0c0xlbmd0aCA9IGxlbmd0aDsKCSAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkrKykgewoJICAgIGlmIChmcm9tUGFydHNbaV0gIT09IHRvUGFydHNbaV0pIHsKCSAgICAgIHNhbWVQYXJ0c0xlbmd0aCA9IGk7CgkgICAgICBicmVhazsKCSAgICB9CgkgIH0KCgkgIHZhciBvdXRwdXRQYXJ0cyA9IFtdOwoJICBmb3IgKHZhciBpID0gc2FtZVBhcnRzTGVuZ3RoOyBpIDwgZnJvbVBhcnRzLmxlbmd0aDsgaSsrKSB7CgkgICAgb3V0cHV0UGFydHMucHVzaCgnLi4nKTsKCSAgfQoKCSAgb3V0cHV0UGFydHMgPSBvdXRwdXRQYXJ0cy5jb25jYXQodG9QYXJ0cy5zbGljZShzYW1lUGFydHNMZW5ndGgpKTsKCgkgIHJldHVybiBvdXRwdXRQYXJ0cy5qb2luKCcvJyk7Cgl9CgoJdmFyIHNlcCA9ICcvJzsKCXZhciBkZWxpbWl0ZXIgPSAnOic7CgoJZnVuY3Rpb24gZGlybmFtZShwYXRoKSB7CgkgIHZhciByZXN1bHQgPSBzcGxpdFBhdGgocGF0aCksCgkgICAgICByb290ID0gcmVzdWx0WzBdLAoJICAgICAgZGlyID0gcmVzdWx0WzFdOwoKCSAgaWYgKCFyb290ICYmICFkaXIpIHsKCSAgICAvLyBObyBkaXJuYW1lIHdoYXRzb2V2ZXIKCSAgICByZXR1cm4gJy4nOwoJICB9CgoJICBpZiAoZGlyKSB7CgkgICAgLy8gSXQgaGFzIGEgZGlybmFtZSwgc3RyaXAgdHJhaWxpbmcgc2xhc2gKCSAgICBkaXIgPSBkaXIuc3Vic3RyKDAsIGRpci5sZW5ndGggLSAxKTsKCSAgfQoKCSAgcmV0dXJuIHJvb3QgKyBkaXI7Cgl9CgoJZnVuY3Rpb24gYmFzZW5hbWUocGF0aCwgZXh0KSB7CgkgIHZhciBmID0gc3BsaXRQYXRoKHBhdGgpWzJdOwoJICAvLyBUT0RPOiBtYWtlIHRoaXMgY29tcGFyaXNvbiBjYXNlLWluc2Vuc2l0aXZlIG9uIHdpbmRvd3M/CgkgIGlmIChleHQgJiYgZi5zdWJzdHIoLTEgKiBleHQubGVuZ3RoKSA9PT0gZXh0KSB7CgkgICAgZiA9IGYuc3Vic3RyKDAsIGYubGVuZ3RoIC0gZXh0Lmxlbmd0aCk7CgkgIH0KCSAgcmV0dXJuIGY7Cgl9CgoKCWZ1bmN0aW9uIGV4dG5hbWUocGF0aCkgewoJICByZXR1cm4gc3BsaXRQYXRoKHBhdGgpWzNdOwoJfQoJdmFyIHBhdGggPSB7CgkgIGV4dG5hbWU6IGV4dG5hbWUsCgkgIGJhc2VuYW1lOiBiYXNlbmFtZSwKCSAgZGlybmFtZTogZGlybmFtZSwKCSAgc2VwOiBzZXAsCgkgIGRlbGltaXRlcjogZGVsaW1pdGVyLAoJICByZWxhdGl2ZTogcmVsYXRpdmUsCgkgIGpvaW46IGpvaW4sCgkgIGlzQWJzb2x1dGU6IGlzQWJzb2x1dGUsCgkgIG5vcm1hbGl6ZTogbm9ybWFsaXplLAoJICByZXNvbHZlOiByZXNvbHZlCgl9OwoJZnVuY3Rpb24gZmlsdGVyICh4cywgZikgewoJICAgIGlmICh4cy5maWx0ZXIpIHJldHVybiB4cy5maWx0ZXIoZik7CgkgICAgdmFyIHJlcyA9IFtdOwoJICAgIGZvciAodmFyIGkgPSAwOyBpIDwgeHMubGVuZ3RoOyBpKyspIHsKCSAgICAgICAgaWYgKGYoeHNbaV0sIGksIHhzKSkgcmVzLnB1c2goeHNbaV0pOwoJICAgIH0KCSAgICByZXR1cm4gcmVzOwoJfQoKCS8vIFN0cmluZy5wcm90b3R5cGUuc3Vic3RyIC0gbmVnYXRpdmUgaW5kZXggZG9uJ3Qgd29yayBpbiBJRTgKCXZhciBzdWJzdHIgPSAnYWInLnN1YnN0cigtMSkgPT09ICdiJyA/CgkgICAgZnVuY3Rpb24gKHN0ciwgc3RhcnQsIGxlbikgeyByZXR1cm4gc3RyLnN1YnN0cihzdGFydCwgbGVuKSB9IDoKCSAgICBmdW5jdGlvbiAoc3RyLCBzdGFydCwgbGVuKSB7CgkgICAgICAgIGlmIChzdGFydCA8IDApIHN0YXJ0ID0gc3RyLmxlbmd0aCArIHN0YXJ0OwoJICAgICAgICByZXR1cm4gc3RyLnN1YnN0cihzdGFydCwgbGVuKTsKCSAgICB9Cgk7CgoJdmFyIHBhdGgkMSA9IC8qI19fUFVSRV9fKi9PYmplY3QuZnJlZXplKHsKCQlfX3Byb3RvX186IG51bGwsCgkJcmVzb2x2ZTogcmVzb2x2ZSwKCQlub3JtYWxpemU6IG5vcm1hbGl6ZSwKCQlpc0Fic29sdXRlOiBpc0Fic29sdXRlLAoJCWpvaW46IGpvaW4sCgkJcmVsYXRpdmU6IHJlbGF0aXZlLAoJCXNlcDogc2VwLAoJCWRlbGltaXRlcjogZGVsaW1pdGVyLAoJCWRpcm5hbWU6IGRpcm5hbWUsCgkJYmFzZW5hbWU6IGJhc2VuYW1lLAoJCWV4dG5hbWU6IGV4dG5hbWUsCgkJJ2RlZmF1bHQnOiBwYXRoCgl9KTsKCgl2YXIgcmVxdWlyZSQkMiA9IC8qQF9fUFVSRV9fKi9nZXRBdWdtZW50ZWROYW1lc3BhY2UoZW1wdHkkMSk7CgoJdmFyIHJlcXVpcmUkJDEgPSAvKkBfX1BVUkVfXyovZ2V0QXVnbWVudGVkTmFtZXNwYWNlKHBhdGgkMSk7CgoJdmFyIGluZGlnb0tldGNoZXJOb3JlbmRlciA9IGNyZWF0ZUNvbW1vbmpzTW9kdWxlKGZ1bmN0aW9uIChtb2R1bGUsIGV4cG9ydHMpIHsKCXZhciBNb2R1bGUgPSAoKCkgPT4gewoJICB2YXIgX3NjcmlwdE5hbWUgPSB0eXBlb2YgZG9jdW1lbnQgIT0gJ3VuZGVmaW5lZCcgPyBkb2N1bWVudC5jdXJyZW50U2NyaXB0Py5zcmMgOiB1bmRlZmluZWQ7CgkgIGlmICh0eXBlb2YgX19maWxlbmFtZSAhPSAndW5kZWZpbmVkJykgX3NjcmlwdE5hbWUgfHw9IF9fZmlsZW5hbWU7CgkgIHJldHVybiAoCglmdW5jdGlvbihtb2R1bGVBcmcgPSB7fSkgewoJICB2YXIgbW9kdWxlUnRuOwoKCXZhciBNb2R1bGU9T2JqZWN0LmFzc2lnbih7fSxtb2R1bGVBcmcpO3ZhciByZWFkeVByb21pc2VSZXNvbHZlLHJlYWR5UHJvbWlzZVJlamVjdDt2YXIgcmVhZHlQcm9taXNlPW5ldyBQcm9taXNlKChyZXNvbHZlLHJlamVjdCk9PntyZWFkeVByb21pc2VSZXNvbHZlPXJlc29sdmU7cmVhZHlQcm9taXNlUmVqZWN0PXJlamVjdDt9KTtbImdldEV4Y2VwdGlvbk1lc3NhZ2UiLCJpbmNyZW1lbnRFeGNlcHRpb25SZWZjb3VudCIsImRlY3JlbWVudEV4Y2VwdGlvblJlZmNvdW50IiwiX21lbW9yeSIsIl9fX2luZGlyZWN0X2Z1bmN0aW9uX3RhYmxlIiwiX2pzVGhyb3ciLCJfcHJpbnRfanNuIiwib25SdW50aW1lSW5pdGlhbGl6ZWQiXS5mb3JFYWNoKHByb3A9PntpZighT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihyZWFkeVByb21pc2UscHJvcCkpe09iamVjdC5kZWZpbmVQcm9wZXJ0eShyZWFkeVByb21pc2UscHJvcCx7Z2V0OigpPT5hYm9ydCgiWW91IGFyZSBnZXR0aW5nICIrcHJvcCsiIG9uIHRoZSBQcm9taXNlIG9iamVjdCwgaW5zdGVhZCBvZiB0aGUgaW5zdGFuY2UuIFVzZSAudGhlbigpIHRvIGdldCBjYWxsZWQgYmFjayB3aXRoIHRoZSBpbnN0YW5jZSwgc2VlIHRoZSBNT0RVTEFSSVpFIGRvY3MgaW4gc3JjL3NldHRpbmdzLmpzIiksc2V0OigpPT5hYm9ydCgiWW91IGFyZSBzZXR0aW5nICIrcHJvcCsiIG9uIHRoZSBQcm9taXNlIG9iamVjdCwgaW5zdGVhZCBvZiB0aGUgaW5zdGFuY2UuIFVzZSAudGhlbigpIHRvIGdldCBjYWxsZWQgYmFjayB3aXRoIHRoZSBpbnN0YW5jZSwgc2VlIHRoZSBNT0RVTEFSSVpFIGRvY3MgaW4gc3JjL3NldHRpbmdzLmpzIil9KTt9fSk7dmFyIEVOVklST05NRU5UX0lTX1dFQj10eXBlb2Ygd2luZG93PT0ib2JqZWN0Ijt2YXIgRU5WSVJPTk1FTlRfSVNfV09SS0VSPXR5cGVvZiBpbXBvcnRTY3JpcHRzPT0iZnVuY3Rpb24iO3ZhciBFTlZJUk9OTUVOVF9JU19OT0RFPXR5cGVvZiBwcm9jZXNzPT0ib2JqZWN0IiYmdHlwZW9mIHByb2Nlc3MudmVyc2lvbnM9PSJvYmplY3QiJiZ0eXBlb2YgcHJvY2Vzcy52ZXJzaW9ucy5ub2RlPT0ic3RyaW5nIjt2YXIgRU5WSVJPTk1FTlRfSVNfU0hFTEw9IUVOVklST05NRU5UX0lTX1dFQiYmIUVOVklST05NRU5UX0lTX05PREUmJiFFTlZJUk9OTUVOVF9JU19XT1JLRVI7aWYoTW9kdWxlWyJFTlZJUk9OTUVOVCJdKXt0aHJvdyBuZXcgRXJyb3IoIk1vZHVsZS5FTlZJUk9OTUVOVCBoYXMgYmVlbiBkZXByZWNhdGVkLiBUbyBmb3JjZSB0aGUgZW52aXJvbm1lbnQsIHVzZSB0aGUgRU5WSVJPTk1FTlQgY29tcGlsZS10aW1lIG9wdGlvbiAoZm9yIGV4YW1wbGUsIC1zRU5WSVJPTk1FTlQ9d2ViIG9yIC1zRU5WSVJPTk1FTlQ9bm9kZSkiKX12YXIgbW9kdWxlT3ZlcnJpZGVzPU9iamVjdC5hc3NpZ24oe30sTW9kdWxlKTt2YXIgdGhpc1Byb2dyYW09Ii4vdGhpcy5wcm9ncmFtIjt2YXIgc2NyaXB0RGlyZWN0b3J5PSIiO3ZhciByZWFkXyxyZWFkQXN5bmMscmVhZEJpbmFyeTtpZihFTlZJUk9OTUVOVF9JU19OT0RFKXtpZih0eXBlb2YgcHJvY2Vzcz09InVuZGVmaW5lZCJ8fCFwcm9jZXNzLnJlbGVhc2V8fHByb2Nlc3MucmVsZWFzZS5uYW1lIT09Im5vZGUiKXRocm93IG5ldyBFcnJvcigibm90IGNvbXBpbGVkIGZvciB0aGlzIGVudmlyb25tZW50IChkaWQgeW91IGJ1aWxkIHRvIEhUTUwgYW5kIHRyeSB0byBydW4gaXQgbm90IG9uIHRoZSB3ZWIsIG9yIHNldCBFTlZJUk9OTUVOVCB0byBzb21ldGhpbmcgLSBsaWtlIG5vZGUgLSBhbmQgcnVuIGl0IHNvbWVwbGFjZSBlbHNlIC0gbGlrZSBvbiB0aGUgd2ViPykiKTt2YXIgbm9kZVZlcnNpb249cHJvY2Vzcy52ZXJzaW9ucy5ub2RlO3ZhciBudW1lcmljVmVyc2lvbj1ub2RlVmVyc2lvbi5zcGxpdCgiLiIpLnNsaWNlKDAsMyk7bnVtZXJpY1ZlcnNpb249bnVtZXJpY1ZlcnNpb25bMF0qMWU0K251bWVyaWNWZXJzaW9uWzFdKjEwMCtudW1lcmljVmVyc2lvblsyXS5zcGxpdCgiLSIpWzBdKjE7aWYobnVtZXJpY1ZlcnNpb248MTZlNCl7dGhyb3cgbmV3IEVycm9yKCJUaGlzIGVtc2NyaXB0ZW4tZ2VuZXJhdGVkIGNvZGUgcmVxdWlyZXMgbm9kZSB2MTYuMC4wIChkZXRlY3RlZCB2Iitub2RlVmVyc2lvbisiKSIpfXZhciBmcz1yZXF1aXJlJCQyO3ZhciBub2RlUGF0aD1yZXF1aXJlJCQxO3NjcmlwdERpcmVjdG9yeT1fX2Rpcm5hbWUrIi8iO3JlYWRfPShmaWxlbmFtZSxiaW5hcnkpPT57ZmlsZW5hbWU9aXNGaWxlVVJJKGZpbGVuYW1lKT9uZXcgVVJMKGZpbGVuYW1lKTpub2RlUGF0aC5ub3JtYWxpemUoZmlsZW5hbWUpO3JldHVybiBmcy5yZWFkRmlsZVN5bmMoZmlsZW5hbWUsYmluYXJ5P3VuZGVmaW5lZDoidXRmOCIpfTtyZWFkQmluYXJ5PWZpbGVuYW1lPT57dmFyIHJldD1yZWFkXyhmaWxlbmFtZSx0cnVlKTtpZighcmV0LmJ1ZmZlcil7cmV0PW5ldyBVaW50OEFycmF5KHJldCk7fWFzc2VydChyZXQuYnVmZmVyKTtyZXR1cm4gcmV0fTtyZWFkQXN5bmM9KGZpbGVuYW1lLG9ubG9hZCxvbmVycm9yLGJpbmFyeT10cnVlKT0+e2ZpbGVuYW1lPWlzRmlsZVVSSShmaWxlbmFtZSk/bmV3IFVSTChmaWxlbmFtZSk6bm9kZVBhdGgubm9ybWFsaXplKGZpbGVuYW1lKTtmcy5yZWFkRmlsZShmaWxlbmFtZSxiaW5hcnk/dW5kZWZpbmVkOiJ1dGY4IiwoZXJyLGRhdGEpPT57aWYoZXJyKW9uZXJyb3IoZXJyKTtlbHNlIG9ubG9hZChiaW5hcnk/ZGF0YS5idWZmZXI6ZGF0YSk7fSk7fTtpZighTW9kdWxlWyJ0aGlzUHJvZ3JhbSJdJiZwcm9jZXNzLmFyZ3YubGVuZ3RoPjEpe3RoaXNQcm9ncmFtPXByb2Nlc3MuYXJndlsxXS5yZXBsYWNlKC9cXC9nLCIvIik7fXByb2Nlc3MuYXJndi5zbGljZSgyKTt9ZWxzZSBpZihFTlZJUk9OTUVOVF9JU19TSEVMTCl7aWYodHlwZW9mIHByb2Nlc3M9PSJvYmplY3QiJiZ0eXBlb2YgY29tbW9uanNSZXF1aXJlPT09ImZ1bmN0aW9uInx8dHlwZW9mIHdpbmRvdz09Im9iamVjdCJ8fHR5cGVvZiBpbXBvcnRTY3JpcHRzPT0iZnVuY3Rpb24iKXRocm93IG5ldyBFcnJvcigibm90IGNvbXBpbGVkIGZvciB0aGlzIGVudmlyb25tZW50IChkaWQgeW91IGJ1aWxkIHRvIEhUTUwgYW5kIHRyeSB0byBydW4gaXQgbm90IG9uIHRoZSB3ZWIsIG9yIHNldCBFTlZJUk9OTUVOVCB0byBzb21ldGhpbmcgLSBsaWtlIG5vZGUgLSBhbmQgcnVuIGl0IHNvbWVwbGFjZSBlbHNlIC0gbGlrZSBvbiB0aGUgd2ViPykiKX1lbHNlIGlmKEVOVklST05NRU5UX0lTX1dFQnx8RU5WSVJPTk1FTlRfSVNfV09SS0VSKXtpZihFTlZJUk9OTUVOVF9JU19XT1JLRVIpe3NjcmlwdERpcmVjdG9yeT1zZWxmLmxvY2F0aW9uLmhyZWY7fWVsc2UgaWYodHlwZW9mIGRvY3VtZW50IT0idW5kZWZpbmVkIiYmZG9jdW1lbnQuY3VycmVudFNjcmlwdCl7c2NyaXB0RGlyZWN0b3J5PWRvY3VtZW50LmN1cnJlbnRTY3JpcHQuc3JjO31pZihfc2NyaXB0TmFtZSl7c2NyaXB0RGlyZWN0b3J5PV9zY3JpcHROYW1lO31pZihzY3JpcHREaXJlY3Rvcnkuc3RhcnRzV2l0aCgiYmxvYjoiKSl7c2NyaXB0RGlyZWN0b3J5PSIiO31lbHNlIHtzY3JpcHREaXJlY3Rvcnk9c2NyaXB0RGlyZWN0b3J5LnN1YnN0cigwLHNjcmlwdERpcmVjdG9yeS5yZXBsYWNlKC9bPyNdLiovLCIiKS5sYXN0SW5kZXhPZigiLyIpKzEpO31pZighKHR5cGVvZiB3aW5kb3c9PSJvYmplY3QifHx0eXBlb2YgaW1wb3J0U2NyaXB0cz09ImZ1bmN0aW9uIikpdGhyb3cgbmV3IEVycm9yKCJub3QgY29tcGlsZWQgZm9yIHRoaXMgZW52aXJvbm1lbnQgKGRpZCB5b3UgYnVpbGQgdG8gSFRNTCBhbmQgdHJ5IHRvIHJ1biBpdCBub3Qgb24gdGhlIHdlYiwgb3Igc2V0IEVOVklST05NRU5UIHRvIHNvbWV0aGluZyAtIGxpa2Ugbm9kZSAtIGFuZCBydW4gaXQgc29tZXBsYWNlIGVsc2UgLSBsaWtlIG9uIHRoZSB3ZWI/KSIpO3tyZWFkXz11cmw9Pnt2YXIgeGhyPW5ldyBYTUxIdHRwUmVxdWVzdDt4aHIub3BlbigiR0VUIix1cmwsZmFsc2UpO3hoci5zZW5kKG51bGwpO3JldHVybiB4aHIucmVzcG9uc2VUZXh0fTtpZihFTlZJUk9OTUVOVF9JU19XT1JLRVIpe3JlYWRCaW5hcnk9dXJsPT57dmFyIHhocj1uZXcgWE1MSHR0cFJlcXVlc3Q7eGhyLm9wZW4oIkdFVCIsdXJsLGZhbHNlKTt4aHIucmVzcG9uc2VUeXBlPSJhcnJheWJ1ZmZlciI7eGhyLnNlbmQobnVsbCk7cmV0dXJuIG5ldyBVaW50OEFycmF5KHhoci5yZXNwb25zZSl9O31yZWFkQXN5bmM9KHVybCxvbmxvYWQsb25lcnJvcik9Pnt2YXIgeGhyPW5ldyBYTUxIdHRwUmVxdWVzdDt4aHIub3BlbigiR0VUIix1cmwsdHJ1ZSk7eGhyLnJlc3BvbnNlVHlwZT0iYXJyYXlidWZmZXIiO3hoci5vbmxvYWQ9KCk9PntpZih4aHIuc3RhdHVzPT0yMDB8fHhoci5zdGF0dXM9PTAmJnhoci5yZXNwb25zZSl7b25sb2FkKHhoci5yZXNwb25zZSk7cmV0dXJufW9uZXJyb3IoKTt9O3hoci5vbmVycm9yPW9uZXJyb3I7eGhyLnNlbmQobnVsbCk7fTt9fWVsc2Uge3Rocm93IG5ldyBFcnJvcigiZW52aXJvbm1lbnQgZGV0ZWN0aW9uIGVycm9yIil9dmFyIG91dD1Nb2R1bGVbInByaW50Il18fGNvbnNvbGUubG9nLmJpbmQoY29uc29sZSk7dmFyIGVycj1Nb2R1bGVbInByaW50RXJyIl18fGNvbnNvbGUuZXJyb3IuYmluZChjb25zb2xlKTtPYmplY3QuYXNzaWduKE1vZHVsZSxtb2R1bGVPdmVycmlkZXMpO21vZHVsZU92ZXJyaWRlcz1udWxsO2NoZWNrSW5jb21pbmdNb2R1bGVBUEkoKTtpZihNb2R1bGVbImFyZ3VtZW50cyJdKU1vZHVsZVsiYXJndW1lbnRzIl07bGVnYWN5TW9kdWxlUHJvcCgiYXJndW1lbnRzIiwiYXJndW1lbnRzXyIpO2lmKE1vZHVsZVsidGhpc1Byb2dyYW0iXSl0aGlzUHJvZ3JhbT1Nb2R1bGVbInRoaXNQcm9ncmFtIl07bGVnYWN5TW9kdWxlUHJvcCgidGhpc1Byb2dyYW0iLCJ0aGlzUHJvZ3JhbSIpO2lmKE1vZHVsZVsicXVpdCJdKU1vZHVsZVsicXVpdCJdO2xlZ2FjeU1vZHVsZVByb3AoInF1aXQiLCJxdWl0XyIpO2Fzc2VydCh0eXBlb2YgTW9kdWxlWyJtZW1vcnlJbml0aWFsaXplclByZWZpeFVSTCJdPT0idW5kZWZpbmVkIiwiTW9kdWxlLm1lbW9yeUluaXRpYWxpemVyUHJlZml4VVJMIG9wdGlvbiB3YXMgcmVtb3ZlZCwgdXNlIE1vZHVsZS5sb2NhdGVGaWxlIGluc3RlYWQiKTthc3NlcnQodHlwZW9mIE1vZHVsZVsicHRocmVhZE1haW5QcmVmaXhVUkwiXT09InVuZGVmaW5lZCIsIk1vZHVsZS5wdGhyZWFkTWFpblByZWZpeFVSTCBvcHRpb24gd2FzIHJlbW92ZWQsIHVzZSBNb2R1bGUubG9jYXRlRmlsZSBpbnN0ZWFkIik7YXNzZXJ0KHR5cGVvZiBNb2R1bGVbImNkSW5pdGlhbGl6ZXJQcmVmaXhVUkwiXT09InVuZGVmaW5lZCIsIk1vZHVsZS5jZEluaXRpYWxpemVyUHJlZml4VVJMIG9wdGlvbiB3YXMgcmVtb3ZlZCwgdXNlIE1vZHVsZS5sb2NhdGVGaWxlIGluc3RlYWQiKTthc3NlcnQodHlwZW9mIE1vZHVsZVsiZmlsZVBhY2thZ2VQcmVmaXhVUkwiXT09InVuZGVmaW5lZCIsIk1vZHVsZS5maWxlUGFja2FnZVByZWZpeFVSTCBvcHRpb24gd2FzIHJlbW92ZWQsIHVzZSBNb2R1bGUubG9jYXRlRmlsZSBpbnN0ZWFkIik7YXNzZXJ0KHR5cGVvZiBNb2R1bGVbInJlYWQiXT09InVuZGVmaW5lZCIsIk1vZHVsZS5yZWFkIG9wdGlvbiB3YXMgcmVtb3ZlZCAobW9kaWZ5IHJlYWRfIGluIEpTKSIpO2Fzc2VydCh0eXBlb2YgTW9kdWxlWyJyZWFkQXN5bmMiXT09InVuZGVmaW5lZCIsIk1vZHVsZS5yZWFkQXN5bmMgb3B0aW9uIHdhcyByZW1vdmVkIChtb2RpZnkgcmVhZEFzeW5jIGluIEpTKSIpO2Fzc2VydCh0eXBlb2YgTW9kdWxlWyJyZWFkQmluYXJ5Il09PSJ1bmRlZmluZWQiLCJNb2R1bGUucmVhZEJpbmFyeSBvcHRpb24gd2FzIHJlbW92ZWQgKG1vZGlmeSByZWFkQmluYXJ5IGluIEpTKSIpO2Fzc2VydCh0eXBlb2YgTW9kdWxlWyJzZXRXaW5kb3dUaXRsZSJdPT0idW5kZWZpbmVkIiwiTW9kdWxlLnNldFdpbmRvd1RpdGxlIG9wdGlvbiB3YXMgcmVtb3ZlZCAobW9kaWZ5IGVtc2NyaXB0ZW5fc2V0X3dpbmRvd190aXRsZSBpbiBKUykiKTthc3NlcnQodHlwZW9mIE1vZHVsZVsiVE9UQUxfTUVNT1JZIl09PSJ1bmRlZmluZWQiLCJNb2R1bGUuVE9UQUxfTUVNT1JZIGhhcyBiZWVuIHJlbmFtZWQgTW9kdWxlLklOSVRJQUxfTUVNT1JZIik7bGVnYWN5TW9kdWxlUHJvcCgiYXNtIiwid2FzbUV4cG9ydHMiKTtsZWdhY3lNb2R1bGVQcm9wKCJyZWFkIiwicmVhZF8iKTtsZWdhY3lNb2R1bGVQcm9wKCJyZWFkQXN5bmMiLCJyZWFkQXN5bmMiKTtsZWdhY3lNb2R1bGVQcm9wKCJyZWFkQmluYXJ5IiwicmVhZEJpbmFyeSIpO2xlZ2FjeU1vZHVsZVByb3AoInNldFdpbmRvd1RpdGxlIiwic2V0V2luZG93VGl0bGUiKTthc3NlcnQoIUVOVklST05NRU5UX0lTX1NIRUxMLCJzaGVsbCBlbnZpcm9ubWVudCBkZXRlY3RlZCBidXQgbm90IGVuYWJsZWQgYXQgYnVpbGQgdGltZS4gIEFkZCBgc2hlbGxgIHRvIGAtc0VOVklST05NRU5UYCB0byBlbmFibGUuIik7dmFyIHdhc21CaW5hcnk7aWYoTW9kdWxlWyJ3YXNtQmluYXJ5Il0pd2FzbUJpbmFyeT1Nb2R1bGVbIndhc21CaW5hcnkiXTtsZWdhY3lNb2R1bGVQcm9wKCJ3YXNtQmluYXJ5Iiwid2FzbUJpbmFyeSIpO2lmKHR5cGVvZiBXZWJBc3NlbWJseSE9Im9iamVjdCIpe2Vycigibm8gbmF0aXZlIHdhc20gc3VwcG9ydCBkZXRlY3RlZCIpO31mdW5jdGlvbiBpbnRBcnJheUZyb21CYXNlNjQocyl7aWYodHlwZW9mIEVOVklST05NRU5UX0lTX05PREUhPSJ1bmRlZmluZWQiJiZFTlZJUk9OTUVOVF9JU19OT0RFKXt2YXIgYnVmPUJ1ZmZlci5mcm9tKHMsImJhc2U2NCIpO3JldHVybiBuZXcgVWludDhBcnJheShidWYuYnVmZmVyLGJ1Zi5ieXRlT2Zmc2V0LGJ1Zi5sZW5ndGgpfXZhciBkZWNvZGVkPWF0b2Iocyk7dmFyIGJ5dGVzPW5ldyBVaW50OEFycmF5KGRlY29kZWQubGVuZ3RoKTtmb3IodmFyIGk9MDtpPGRlY29kZWQubGVuZ3RoOysraSl7Ynl0ZXNbaV09ZGVjb2RlZC5jaGFyQ29kZUF0KGkpO31yZXR1cm4gYnl0ZXN9ZnVuY3Rpb24gdHJ5UGFyc2VBc0RhdGFVUkkoZmlsZW5hbWUpe2lmKCFpc0RhdGFVUkkoZmlsZW5hbWUpKXtyZXR1cm59cmV0dXJuIGludEFycmF5RnJvbUJhc2U2NChmaWxlbmFtZS5zbGljZShkYXRhVVJJUHJlZml4Lmxlbmd0aCkpfXZhciB3YXNtTWVtb3J5O3ZhciBBQk9SVD1mYWxzZTtmdW5jdGlvbiBhc3NlcnQoY29uZGl0aW9uLHRleHQpe2lmKCFjb25kaXRpb24pe2Fib3J0KCJBc3NlcnRpb24gZmFpbGVkIisodGV4dD8iOiAiK3RleHQ6IiIpKTt9fXZhciBIRUFQOCxIRUFQVTgsSEVBUDE2LEhFQVBVMTYsSEVBUDMyLEhFQVBVMzIsSEVBUEYzMixIRUFQRjY0O2Z1bmN0aW9uIHVwZGF0ZU1lbW9yeVZpZXdzKCl7dmFyIGI9d2FzbU1lbW9yeS5idWZmZXI7TW9kdWxlWyJIRUFQOCJdPUhFQVA4PW5ldyBJbnQ4QXJyYXkoYik7TW9kdWxlWyJIRUFQMTYiXT1IRUFQMTY9bmV3IEludDE2QXJyYXkoYik7TW9kdWxlWyJIRUFQVTgiXT1IRUFQVTg9bmV3IFVpbnQ4QXJyYXkoYik7TW9kdWxlWyJIRUFQVTE2Il09SEVBUFUxNj1uZXcgVWludDE2QXJyYXkoYik7TW9kdWxlWyJIRUFQMzIiXT1IRUFQMzI9bmV3IEludDMyQXJyYXkoYik7TW9kdWxlWyJIRUFQVTMyIl09SEVBUFUzMj1uZXcgVWludDMyQXJyYXkoYik7TW9kdWxlWyJIRUFQRjMyIl09SEVBUEYzMj1uZXcgRmxvYXQzMkFycmF5KGIpO01vZHVsZVsiSEVBUEY2NCJdPUhFQVBGNjQ9bmV3IEZsb2F0NjRBcnJheShiKTt9YXNzZXJ0KCFNb2R1bGVbIlNUQUNLX1NJWkUiXSwiU1RBQ0tfU0laRSBjYW4gbm8gbG9uZ2VyIGJlIHNldCBhdCBydW50aW1lLiAgVXNlIC1zU1RBQ0tfU0laRSBhdCBsaW5rIHRpbWUiKTthc3NlcnQodHlwZW9mIEludDMyQXJyYXkhPSJ1bmRlZmluZWQiJiZ0eXBlb2YgRmxvYXQ2NEFycmF5IT09InVuZGVmaW5lZCImJkludDMyQXJyYXkucHJvdG90eXBlLnN1YmFycmF5IT11bmRlZmluZWQmJkludDMyQXJyYXkucHJvdG90eXBlLnNldCE9dW5kZWZpbmVkLCJKUyBlbmdpbmUgZG9lcyBub3QgcHJvdmlkZSBmdWxsIHR5cGVkIGFycmF5IHN1cHBvcnQiKTthc3NlcnQoIU1vZHVsZVsid2FzbU1lbW9yeSJdLCJVc2Ugb2YgYHdhc21NZW1vcnlgIGRldGVjdGVkLiAgVXNlIC1zSU1QT1JURURfTUVNT1JZIHRvIGRlZmluZSB3YXNtTWVtb3J5IGV4dGVybmFsbHkiKTthc3NlcnQoIU1vZHVsZVsiSU5JVElBTF9NRU1PUlkiXSwiRGV0ZWN0ZWQgcnVudGltZSBJTklUS